Initial commit: Atomaste website

This commit is contained in:
2025-12-10 12:17:30 -05:00
commit 0b9e5d1605
19260 changed files with 5206382 additions and 0 deletions

View File

@@ -0,0 +1,151 @@
<?php
namespace AIOSEO\Plugin\Common\Main;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Abstract class that Pro and Lite both extend.
*
* @since 4.0.0
*/
class Activate {
/**
* Construct method.
*
* @since 4.0.0
*/
public function __construct() {
register_activation_hook( AIOSEO_FILE, [ $this, 'activate' ] );
register_deactivation_hook( AIOSEO_FILE, [ $this, 'deactivate' ] );
// The following only needs to happen when in the admin.
if ( ! is_admin() ) {
return;
}
// This needs to run on at least 1000 because we load the roles in the Access class on 999.
add_action( 'init', [ $this, 'init' ], 1000 );
}
/**
* Initialize activation.
*
* @since 4.1.5
*
* @return void
*/
public function init() {
// If Pro just deactivated the lite version, we need to manually run the activation hook, because it doesn't run here.
$proDeactivatedLite = (bool) aioseo()->core->cache->get( 'pro_just_deactivated_lite' );
if ( ! $proDeactivatedLite ) {
// Also check for the old transient in the options table (because a user might switch from an older Lite version that lacks the Cache class).
$proDeactivatedLite = (bool) get_option( '_aioseo_cache_pro_just_deactivated_lite' );
}
if ( $proDeactivatedLite ) {
aioseo()->core->cache->delete( 'pro_just_deactivated_lite' );
$this->activate( false );
}
}
/**
* Runs on activation.
*
* @since 4.0.17
*
* @param bool $networkWide Whether or not this is a network wide activation.
* @return void
*/
public function activate( $networkWide ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
aioseo()->access->addCapabilities();
// Make sure our tables exist.
aioseo()->updates->addInitialCustomTablesForV4();
// Set the activation timestamps.
$time = time();
aioseo()->internalOptions->internal->activated = $time;
if ( ! aioseo()->internalOptions->internal->firstActivated ) {
aioseo()->internalOptions->internal->firstActivated = $time;
}
aioseo()->core->cache->clear();
$this->maybeRunSetupWizard();
}
/**
* Runs on deactivation.
*
* @since 4.0.0
*
* @return void
*/
public function deactivate() {
aioseo()->access->removeCapabilities();
}
/**
* Check if we should redirect on activation.
*
* @since 4.1.2
*
* @return void
*/
private function maybeRunSetupWizard() {
if ( '0.0' !== aioseo()->internalOptions->internal->lastActiveVersion ) {
return;
}
$oldOptions = get_option( 'aioseop_options' );
if ( ! empty( $oldOptions ) ) {
return;
}
if ( is_network_admin() ) {
return;
}
if ( isset( $_GET['activate-multi'] ) ) { // phpcs:ignore HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
return;
}
// Sets 30 second transient for welcome screen redirect on activation.
aioseo()->core->cache->update( 'activation_redirect', true, 30 );
}
/**
* Adds our capabilities to all roles on the next request and the installing user on the current request after upgrading to Pro.
*
* @link https://github.com/awesomemotive/aioseo/issues/2267
* @link https://github.com/awesomemotive/aioseo/issues/2288
*
* @since 4.1.4.4
*
* @return void
*/
public function addCapabilitiesOnUpgrade() {
// In case the user is switching to Pro via the AIOSEO Connect feature,
// we need to set this transient here as the regular activation hooks won't run and Pro otherwise won't clear the cache and add the required capabilities.
aioseo()->core->cache->update( 'pro_just_deactivated_lite', true );
// Doing the above isn't sufficient because the current user will be lacking the capabilities on the first request. Therefore, we add them manually just for him.
$userId = function_exists( 'get_current_user_id' ) && get_current_user_id()
? get_current_user_id() // If there is a logged in user, the user is switching from Lite to Pro via the Plugins menu.
: aioseo()->core->cache->get( 'connect_active_user' ); // If there is no logged in user, we're upgrading via AIOSEO Connect.
$user = get_userdata( $userId );
if ( is_object( $user ) ) {
$capabilities = aioseo()->access->getCapabilityList();
foreach ( $capabilities as $capability ) {
$user->add_cap( $capability );
}
}
aioseo()->core->cache->delete( 'connect_active_user' );
}
}

View File

@@ -0,0 +1,263 @@
<?php
namespace AIOSEO\Plugin\Common\Main;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Main class with methods that are called.
*
* @since 4.2.0
* @version 4.7.1 Moved from Pro to Common.
*/
class CategoryBase {
/**
* Class constructor.
*
* @since 4.2.0
*/
public function __construct() {
if ( ! aioseo()->options->searchAppearance->advanced->removeCategoryBase ) {
return;
}
add_filter( 'query_vars', [ $this, 'queryVars' ] );
add_filter( 'request', [ $this, 'maybeRedirectCategoryUrl' ] );
add_filter( 'category_rewrite_rules', [ $this, 'categoryRewriteRules' ] );
add_filter( 'term_link', [ $this, 'modifyTermLink' ], 10, 3 );
// Flush rewrite rules on any of the following actions.
add_action( 'created_category', [ $this, 'scheduleFlushRewrite' ] );
add_action( 'delete_category', [ $this, 'scheduleFlushRewrite' ] );
add_action( 'edited_category', [ $this, 'scheduleFlushRewrite' ] );
}
/**
* Add the redirect var to the query vars if the "strip category bases" option is enabled.
*
* @since 4.2.0
*
* @param array $queryVars Query vars to filter.
* @return array The filtered query vars.
*/
public function queryVars( $queryVars ) {
$queryVars[] = 'aioseo_category_redirect';
return $queryVars;
}
/**
* Redirect the category URL to the new one.
*
* @param array $queryVars Query vars to check for redirect var.
* @return array The original query vars.
*/
public function maybeRedirectCategoryUrl( $queryVars ) {
if ( isset( $queryVars['aioseo_category_redirect'] ) ) {
$categoryUrl = trailingslashit( get_option( 'home' ) ) . user_trailingslashit( $queryVars['aioseo_category_redirect'], 'category' );
wp_redirect( $categoryUrl, 301, 'AIOSEO' );
die;
}
return $queryVars;
}
/**
* Rewrite the category base.
*
* @since 4.2.0
*
* @return array The rewritten rules.
*/
public function categoryRewriteRules() {
global $wp_rewrite; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
$categoryRewrite = $this->getCategoryRewriteRules();
// Redirect from the old base.
$categoryStructure = $wp_rewrite->get_category_permastruct(); // phpcs:ignore Squiz.NamingConventions.ValidVariableName
$categoryBase = trim( str_replace( '%category%', '(.+)', $categoryStructure ), '/' ) . '$';
// Add the rewrite rules.
$categoryRewrite[ $categoryBase ] = 'index.php?aioseo_category_redirect=$matches[1]';
return $categoryRewrite;
}
/**
* Get the rewrite rules for the category.
*
* @since 4.2.0
*
* @return array An array of category rewrite rules.
*/
private function getCategoryRewriteRules() {
global $wp_rewrite; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
$categoryRewrite = [];
$categories = get_categories( [ 'hide_empty' => false ] );
if ( empty( $categories ) ) {
return $categoryRewrite;
}
$blogPrefix = $this->getBlogPrefix();
$paginationBase = $wp_rewrite->pagination_base; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
foreach ( $categories as $category ) {
$nicename = $this->getCategoryParents( $category ) . $category->slug;
$categoryRewrite = $this->addCategoryRewrites( $categoryRewrite, $nicename, $blogPrefix, $paginationBase );
// Also add the rules for uppercase.
$filteredNicename = $this->convertEncodedToUppercase( $nicename );
if ( $nicename !== $filteredNicename ) {
$categoryRewrite = $this->addCategoryRewrites( $categoryRewrite, $filteredNicename, $blogPrefix, $paginationBase );
}
}
return $categoryRewrite;
}
/**
* Get the blog prefix.
*
* @since 4.2.0
*
* @return string The prefix for the blog.
*/
private function getBlogPrefix() {
$permalinkStructure = get_option( 'permalink_structure' );
if (
is_multisite() &&
! is_subdomain_install() &&
is_main_site() &&
0 === strpos( $permalinkStructure, '/blog/' )
) {
return 'blog/';
}
return '';
}
/**
* Retrieve category parents with separator.
*
* @since 4.2.0
*
* @param \WP_Term $category the category instance.
* @return string A list of category parents.
*/
private function getCategoryParents( $category ) {
if (
$category->parent === $category->term_id ||
absint( $category->parent ) < 1
) {
return '';
}
$parents = get_category_parents( $category->parent, false, '/', true );
return is_wp_error( $parents ) ? '' : $parents;
}
/**
* Walks through category nicename and convert encoded parts
* into uppercase using $this->encode_to_upper().
*
* @since 4.2.0
*
* @param string $nicename The encoded category string.
* @return string The converted category string.
*/
private function convertEncodedToUppercase( $nicename ) {
// Checks if name has any encoding in it.
if ( false === strpos( $nicename, '%' ) ) {
return $nicename;
}
$nicenames = explode( '/', $nicename );
$nicenames = array_map( [ $this, 'convertToUppercase' ], $nicenames );
return implode( '/', $nicenames );
}
/**
* Converts the encoded URI string to uppercase.
*
* @since 4.2.0
*
* @param string $encoded The encoded category string.
* @return string The converted category string.
*/
private function convertToUppercase( $encoded ) {
if ( false === strpos( $encoded, '%' ) ) {
return $encoded;
}
return strtoupper( $encoded );
}
/**
* Adds the required category rewrites rules.
*
* @since 4.2.0
*
* @param array $categoryRewrite The current set of rules.
* @param string $categoryNicename The category nicename.
* @param string $blogPrefix Multisite blog prefix.
* @param string $paginationBase WP_Query pagination base.
* @return array The added set of rules.
*/
private function addCategoryRewrites( $categoryRewrite, $categoryNicename, $blogPrefix, $paginationBase ) {
$categoryRewrite[ $blogPrefix . '(' . $categoryNicename . ')/(?:feed/)?(feed|rdf|rss|rss2|atom)/?$' ] = 'index.php?category_name=$matches[1]&feed=$matches[2]';
$categoryRewrite[ $blogPrefix . '(' . $categoryNicename . ')/' . $paginationBase . '/?([0-9]{1,})/?$' ] = 'index.php?category_name=$matches[1]&paged=$matches[2]';
$categoryRewrite[ $blogPrefix . '(' . $categoryNicename . ')/?$' ] = 'index.php?category_name=$matches[1]';
return $categoryRewrite;
}
/**
* Remove the category base from the category link.
*
* @since 4.2.0
*
* @param string $link Term link.
* @param object $term The current Term Object.
* @param string $taxonomy The current Taxonomy.
* @return string The modified term link.
*/
public function modifyTermLink( $link, $term = null, $taxonomy = '' ) {
if ( 'category' !== $taxonomy ) {
return $link;
}
$categoryBase = get_option( 'category_base' );
if ( empty( $categoryBase ) ) {
global $wp_rewrite; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
$categoryStructure = $wp_rewrite->get_category_permastruct(); // phpcs:ignore Squiz.NamingConventions.ValidVariableName
$categoryBase = trim( str_replace( '%category%', '', $categoryStructure ), '/' );
}
// Remove initial slash, if there is one (we remove the trailing slash in the regex replacement and don't want to end up short a slash).
if ( '/' === substr( $categoryBase, 0, 1 ) ) {
$categoryBase = substr( $categoryBase, 1 );
}
$categoryBase .= '/';
return preg_replace( '`' . preg_quote( (string) $categoryBase, '`' ) . '`u', '', (string) $link, 1 );
}
/**
* Flush the rewrite rules.
*
* @since 4.2.0
*
* @return void
*/
public function scheduleFlushRewrite() {
aioseo()->options->flushRewriteRules();
}
}

View File

@@ -0,0 +1,605 @@
<?php
namespace AIOSEO\Plugin\Common\Main;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
use AIOSEO\Plugin\Common\Integrations\BuddyPress as BuddyPressIntegration;
/**
* Abstract class that Pro and Lite both extend.
*
* @since 4.0.0
*/
abstract class Filters {
/**
* The plugin we are checking.
*
* @since 4.0.0
*
* @var string
*/
private $plugin;
/**
* ID of the WooCommerce product that is being duplicated.
*
* @since 4.1.4
*
* @var integer
*/
private static $originalProductId;
/**
* Construct method.
*
* @since 4.0.0
*/
public function __construct() {
add_filter( 'wp_optimize_get_tables', [ $this, 'wpOptimizeAioseoTables' ] );
// This action needs to run on AJAX/cron for scheduled rewritten posts in Yoast Duplicate Post.
add_action( 'duplicate_post_after_rewriting', [ $this, 'updateRescheduledPostMeta' ], 10, 2 );
if ( wp_doing_ajax() || wp_doing_cron() ) {
return;
}
add_filter( 'plugin_row_meta', [ $this, 'pluginRowMeta' ], 10, 2 );
add_filter( 'plugin_action_links_' . AIOSEO_PLUGIN_BASENAME, [ $this, 'pluginActionLinks' ], 10, 2 );
// Genesis theme compatibility.
add_filter( 'genesis_detect_seo_plugins', [ $this, 'genesisTheme' ] );
// WeGlot compatibility.
if ( isset( $_SERVER['REQUEST_URI'] ) && preg_match( '#(/default-sitemap\.xsl)$#i', (string) sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) ) {
add_filter( 'weglot_active_translation_before_treat_page', '__return_false' );
}
if ( isset( $_SERVER['REQUEST_URI'] ) && preg_match( '#(\.xml)$#i', (string) sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) ) {
add_filter( 'jetpack_boost_should_defer_js', '__return_false' );
}
// GoDaddy CDN compatibility.
add_filter( 'wpaas_cdn_file_ext', [ $this, 'goDaddySitemapXml' ] );
// Duplicate Post integration.
add_action( 'dp_duplicate_post', [ $this, 'duplicatePost' ], 10, 2 );
add_action( 'dp_duplicate_page', [ $this, 'duplicatePost' ], 10, 2 );
add_action( 'woocommerce_product_duplicate_before_save', [ $this, 'scheduleDuplicateProduct' ], 10, 2 );
add_action( 'add_post_meta', [ $this, 'rewriteAndRepublish' ], 10, 3 );
// BBpress compatibility.
add_action( 'init', [ $this, 'resetUserBBPress' ], -1 );
add_filter( 'the_title', [ $this, 'maybeRemoveBBPressReplyFilter' ], 0, 2 );
// Bypass the JWT Auth plugin's unnecessary restrictions. https://wordpress.org/plugins/jwt-auth/
add_filter( 'jwt_auth_default_whitelist', [ $this, 'allowRestRoutes' ] );
// Clear the site authors cache.
add_action( 'profile_update', [ $this, 'clearAuthorsCache' ] );
add_action( 'user_register', [ $this, 'clearAuthorsCache' ] );
add_filter( 'aioseo_public_post_types', [ $this, 'removeInvalidPublicPostTypes' ] );
add_filter( 'aioseo_public_taxonomies', [ $this, 'removeInvalidPublicTaxonomies' ] );
add_action( 'admin_print_scripts', [ $this, 'removeEmojiDetectionScripts' ], 0 );
// Disable Jetpack sitemaps module.
if ( aioseo()->options->sitemap->general->enable ) {
add_filter( 'jetpack_get_available_modules', [ $this, 'disableJetpackSitemaps' ] );
}
add_action( 'after_setup_theme', [ $this, 'removeHelloElementorDescriptionTag' ] );
add_action( 'wp', [ $this, 'removeAvadaOgTags' ] );
add_action( 'init', [ $this, 'declareAioseoFollowingConsentApi' ] );
}
/**
* Declares AIOSEO and its addons as following the Consent API.
*
* @since 4.6.5
*
* @return void
*/
public function declareAioseoFollowingConsentApi() {
add_filter( 'wp_consent_api_registered_all-in-one-seo-pack/all_in_one_seo_pack.php', '__return_true' );
add_filter( 'wp_consent_api_registered_all-in-one-seo-pack-pro/all_in_one_seo_pack.php', '__return_true' );
foreach ( aioseo()->addons->getAddons() as $addon ) {
if ( empty( $addon->installed ) || empty( $addon->basename ) ) {
continue;
}
if ( isset( $addon->basename ) ) {
add_filter( 'wp_consent_api_registered_' . $addon->basename, '__return_true' );
}
}
}
/**
* Removes emoji detection scripts on WP 6.2 which broke our Emojis.
*
* @since 4.3.4.1
*
* @return void
*/
public function removeEmojiDetectionScripts() {
global $wp_version; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
if ( version_compare( $wp_version, '6.2', '>=' ) ) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
}
}
/**
* Resets the current user if bbPress is active.
* We have to do this because our calls to wp_get_current_user() set the current user early and this breaks core functionality in bbPress.
*
* @link https://github.com/awesomemotive/aioseo/issues/22300
*
* @since 4.1.5
*
* @return void
*/
public function resetUserBBPress() {
if ( function_exists( 'bbpress' ) ) {
global $current_user; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
$current_user = null; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
}
}
/**
* Removes the bbPress title filter when adding a new reply with empty title to avoid fatal error.
*
* @link https://github.com/awesomemotive/aioseo/issues/4183
*
* @since 4.3.1
*
* @param string $title The post title.
* @param int $id The post ID (optional - in order to fix an issue where other plugins/themes don't pass in the second arg).
* @return string The post title.
*/
public function maybeRemoveBBPressReplyFilter( $title, $id = 0 ) {
if (
function_exists( 'bbp_get_reply_post_type' ) &&
get_post_type( $id ) === bbp_get_reply_post_type() &&
aioseo()->helpers->isScreenBase( 'post' )
) {
remove_filter( 'the_title', 'bbp_get_reply_title_fallback', 2 );
}
return $title;
}
/**
* Duplicates the model when duplicate post is triggered.
*
* @since 4.1.1
*
* @param integer $targetPostId The target post ID.
* @param \WP_Post $sourcePost The source post object.
* @return void
*/
public function duplicatePost( $targetPostId, $sourcePost = null ) {
$sourcePostId = ! empty( $sourcePost->ID ) ? $sourcePost->ID : $sourcePost;
$sourceAioseoPost = Models\Post::getPost( $sourcePostId );
$targetPost = Models\Post::getPost( $targetPostId );
$columns = $sourceAioseoPost->getColumns();
foreach ( $columns as $column => $value ) {
// Skip the ID column.
if ( 'id' === $column ) {
continue;
}
if ( 'post_id' === $column ) {
$targetPost->$column = $targetPostId;
continue;
}
$targetPost->$column = $sourceAioseoPost->$column;
}
$targetPost->save();
}
/**
* Duplicates the model when rewrite and republish is triggered.
*
* @since 4.3.4
*
* @param integer $postId The post ID.
* @param string $metaKey The meta key.
* @param mixed $metaValue The meta value.
* @return void
*/
public function rewriteAndRepublish( $postId, $metaKey = '', $metaValue = '' ) {
if ( '_dp_has_rewrite_republish_copy' !== $metaKey ) {
return;
}
$originalPost = aioseo()->helpers->getPost( $postId );
if ( ! is_object( $originalPost ) ) {
return;
}
$this->duplicatePost( (int) $metaValue, $originalPost );
}
/**
* Updates the model when a post is republished.
* Yoast Duplicate Post doesn't do this since we store our data in a custom table.
*
* @since 4.6.7
*
* @param int $scheduledPostId The ID of the scheduled post.
* @param int $originalPostId The ID of the original post.
* @return void
*/
public function updateRescheduledPostMeta( $scheduledPostId, $originalPostId ) {
$this->duplicatePost( $originalPostId, $scheduledPostId );
// Delete the AIOSEO post record for the scheduled post.
$scheduledAioseoPost = Models\Post::getPost( $scheduledPostId );
$scheduledAioseoPost->delete();
}
/**
* Schedules an action to duplicate our meta after the duplicated WooCommerce product has been saved.
*
* @since 4.1.4
*
* @param \WC_Product $newProduct The new, duplicated product.
* @param \WC_Product $originalProduct The original product.
* @return void
*/
public function scheduleDuplicateProduct( $newProduct, $originalProduct = null ) {
self::$originalProductId = $originalProduct->get_id();
add_action( 'wp_insert_post', [ $this, 'duplicateProduct' ], 10, 2 );
}
/**
* Duplicates our meta for the new WooCommerce product.
*
* @since 4.1.4
*
* @param integer $postId The new post ID.
* @param \WP_Post $post The new post object.
* @return void
*/
public function duplicateProduct( $postId, $post = null ) {
if ( ! self::$originalProductId || 'product' !== $post->post_type ) {
return;
}
$this->duplicatePost( $postId, self::$originalProductId );
}
/**
* Disable SEO inside the Genesis theme if it's running.
*
* @since 4.0.3
*
* @param array $array An array of checks.
* @return array An array with our function added.
*/
public function genesisTheme( $array ) {
if ( empty( $array ) || ! isset( $array['functions'] ) ) {
return $array;
}
$array['functions'][] = 'aioseo';
return $array;
}
/**
* Remove XML from the GoDaddy CDN so our urls remain intact.
*
* @since 4.0.5
*
* @param array $extensions The original extensions list.
* @return array The extensions list without xml.
*/
public function goDaddySitemapXml( $extensions ) {
$key = array_search( 'xml', $extensions, true );
unset( $extensions[ $key ] );
return $extensions;
}
/**
* Registers our row meta for the plugins page.
*
* @since 4.0.0
*
* @param array $actions List of existing actions.
* @param string $pluginFile The plugin file.
* @return array List of action links.
*/
abstract public function pluginRowMeta( $actions, $pluginFile = '' );
/**
* Registers our action links for the plugins page.
*
* @since 4.0.0
*
* @param array $actions List of existing actions.
* @param string $pluginFile The plugin file.
* @return array List of action links.
*/
abstract public function pluginActionLinks( $actions, $pluginFile = '' );
/**
* Parses the action links.
*
* @since 4.0.0
*
* @param array $actions The actions.
* @param string $pluginFile The plugin file.
* @param array $actionLinks The action links.
* @param string $position The position.
* @return array The parsed actions.
*/
protected function parseActionLinks( $actions, $pluginFile, $actionLinks = [], $position = 'after' ) {
if ( empty( $this->plugin ) ) {
$this->plugin = AIOSEO_PLUGIN_BASENAME;
}
if ( $this->plugin === $pluginFile && ! empty( $actionLinks ) ) {
foreach ( $actionLinks as $key => $value ) {
$link = [
$key => sprintf(
'<a href="%1$s" %2$s target="_blank">%3$s</a>',
esc_url( $value['url'] ),
isset( $value['title'] ) ? 'title="' . esc_attr( $value['title'] ) . '"' : '',
$value['label']
)
];
$actions = 'after' === $position ? array_merge( $actions, $link ) : array_merge( $link, $actions );
}
}
return $actions;
}
/**
* Add our routes to this plugins allow list.
*
* @since 4.1.4
*
* @param array $allowList The original list.
* @return array The modified list.
*/
public function allowRestRoutes( $allowList ) {
return array_merge( $allowList, [
'/aioseo/'
] );
}
/**
* Clear the site authors cache when user is updated or registered.
*
* @since 4.1.8
*
* @return void
*/
public function clearAuthorsCache() {
aioseo()->core->cache->delete( 'site_authors' );
}
/**
* Filters out post types that aren't really public when getPublicPostTypes() is called.
*
* @since 4.1.9
*
* @param array[object]|array[string] $postTypes The post types.
* @return array[object]|array[string] The filtered post types.
*/
public function removeInvalidPublicPostTypes( $postTypes ) {
$postTypesToRemove = [
'fusion_element', // Avada
'elementor_library',
'redirect_rule', // Safe Redirect Manager
'seedprod',
'tcb_lightbox',
// Thrive Themes internal post types.
'tva_module',
'tvo_display',
'tvo_capture',
'tva_module',
'tve_lead_1c_signup',
'tve_form_type',
'tvd_login_edit',
'tve_global_cond_set',
'tve_cond_display',
'tve_lead_2s_lightbox',
'tcb_symbol',
'td_nm_notification',
'tvd_content_set',
'tve_saved_lp',
'tve_notifications',
'tve_user_template',
'tve_video_data',
'tva_course_type',
'tva-acc-restriction',
'tva_course_overview',
'tve_ult_schedule',
'tqb_optin',
'tqb_splash',
'tva_certificate',
'tva_course_overview',
// BuddyPress post types.
BuddyPressIntegration::getEmailCptSlug()
];
foreach ( $postTypes as $index => $postType ) {
if ( is_string( $postType ) && in_array( $postType, $postTypesToRemove, true ) ) {
unset( $postTypes[ $index ] );
continue;
}
if ( is_array( $postType ) && in_array( $postType['name'], $postTypesToRemove, true ) ) {
unset( $postTypes[ $index ] );
}
}
return array_values( $postTypes );
}
/**
* Filters out taxonomies that aren't really public when getPublicTaxonomies() is called.
*
* @since 4.2.4
*
* @param array[object]|array[string] $taxonomies The taxonomies.
* @return array[object]|array[string] The filtered taxonomies.
*/
public function removeInvalidPublicTaxonomies( $taxonomies ) {
$taxonomiesToRemove = [
'fusion_tb_category',
'element_category',
'template_category',
// Thrive Themes internal taxonomies.
'tcb_symbols_tax'
];
foreach ( $taxonomies as $index => $taxonomy ) {
if ( is_string( $taxonomy ) && in_array( $taxonomy, $taxonomiesToRemove, true ) ) {
unset( $taxonomies[ $index ] );
continue;
}
if ( is_array( $taxonomy ) && in_array( $taxonomy['name'], $taxonomiesToRemove, true ) ) {
unset( $taxonomies[ $index ] );
}
}
return array_values( $taxonomies );
}
/**
* Disable Jetpack sitemaps module.
*
* @since 4.2.2
*/
public function disableJetpackSitemaps( $active ) {
unset( $active['sitemaps'] );
return $active;
}
/**
* Dequeues third-party scripts from the other plugins or themes that crashes our menu pages.
*
* @since 4.1.9
* @version 4.3.1
*
* @return void
*/
public function dequeueThirdPartyAssets() {
// TagDiv Opt-in Builder plugin.
wp_dequeue_script( 'tds_js_vue_files_last' );
// MyListing theme.
if ( function_exists( 'mylisting' ) ) {
wp_dequeue_script( 'vuejs' );
wp_dequeue_script( 'theme-script-vendor' );
wp_dequeue_script( 'theme-script-main' );
}
// Voxel theme.
if ( class_exists( '\Voxel\Controllers\Assets_Controller' ) ) {
wp_dequeue_script( 'vue' );
wp_dequeue_script( 'vx:backend.js' );
}
// Meta tags for seo plugin.
if ( class_exists( '\Pagup\MetaTags\Settings' ) ) {
wp_dequeue_script( 'pmt__vuejs' );
wp_dequeue_script( 'pmt__script' );
}
// Plugin: Wpbingo Core (By TungHV).
if ( strpos( wp_styles()->query( 'bwp-lookbook-css' )->src ?? '', 'wpbingo' ) !== false ) {
wp_dequeue_style( 'bwp-lookbook-css' );
}
}
/**
* Dequeues third-party scripts from the other plugins or themes that crashes our menu pages.
*
* @version 4.3.2
*
* @return void
*/
public function dequeueThirdPartyAssetsEarly() {
// Disables scripts for plugins StmMotorsExtends and StmPostType.
if ( class_exists( 'STM_Metaboxes' ) ) {
remove_action( 'admin_enqueue_scripts', [ 'STM_Metaboxes', 'wpcfto_scripts' ] );
}
// Disables scripts for LearnPress plugin.
if ( function_exists( 'learn_press_admin_assets' ) ) {
remove_action( 'admin_enqueue_scripts', [ learn_press_admin_assets(), 'load_scripts' ] );
}
}
/**
* Removes the duplicate meta description tag from the Hello Elementor theme.
*
* @since 4.4.3
*
* @link https://developers.elementor.com/docs/hello-elementor-theme/hello_elementor_add_description_meta_tag/
*
* @return void
*/
public function removeHelloElementorDescriptionTag() {
remove_action( 'wp_head', 'hello_elementor_add_description_meta_tag' );
}
/**
* Removes the Avada OG tags.
*
* @since 4.6.5
*
* @return void
*/
public function removeAvadaOgTags() {
if ( function_exists( 'Avada' ) ) {
$avada = Avada();
if ( is_object( $avada->head ?? null ) ) {
remove_action( 'wp_head', [ $avada->head, 'insert_og_meta' ], 5 );
}
}
}
/**
* Prevent WP-Optimize from deleting our tables.
*
* @since 4.4.5
*
* @param array $tables List of tables.
* @return array Filtered tables.
*/
public function wpOptimizeAioseoTables( $tables ) {
foreach ( $tables as &$table ) {
if (
is_object( $table ) &&
property_exists( $table, 'Name' ) &&
false !== stripos( $table->Name, 'aioseo_' )
) {
$table->is_using = true;
$table->can_be_removed = false;
}
}
return $tables;
}
}

View File

@@ -0,0 +1,173 @@
<?php
namespace AIOSEO\Plugin\Common\Main;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Meta;
/**
* Outputs anything we need to the head of the site.
*
* @since 4.0.0
*/
class Head {
/**
* The page title.
*
* @since 4.0.5
*
* @var string
*/
private static $pageTitle = null;
/**
* Title class instance.
*
* @since 4.3.9
*
* @var Title
*/
private $title;
/**
* Links class instance.
*
* @since 4.2.7
*
* @var Meta\Links
*/
protected $links = null;
/**
* Keywords class instance.
*
* @since 4.2.7
*
* @var Meta\Keywords
*/
protected $keywords = null;
/**
* Verification class instance.
*
* @since 4.2.7
*
* @var Meta\SiteVerification
*/
protected $verification = null;
/**
* The views to output.
*
* @since 4.2.7
*
* @var array
*/
protected $views = [];
/**
* Class constructor.
*
* @since 4.0.0
*/
public function __construct() {
add_action( 'wp', [ $this, 'registerTitleHooks' ], 1000 );
add_action( 'wp_head', [ $this, 'wpHead' ], 1 );
$this->title = new Title();
$this->links = new Meta\Links();
$this->keywords = new Meta\Keywords();
$this->verification = new Meta\SiteVerification();
$this->views = [
'meta' => AIOSEO_DIR . '/app/Common/Views/main/meta.php',
'social' => AIOSEO_DIR . '/app/Common/Views/main/social.php',
'schema' => AIOSEO_DIR . '/app/Common/Views/main/schema.php',
'clarity' => AIOSEO_DIR . '/app/Common/Views/main/clarity.php'
];
}
/**
* Registers our title hooks.
*
* @since 4.0.5
*
* @return void
*/
public function registerTitleHooks() {
if ( apply_filters( 'aioseo_disable', false ) || apply_filters( 'aioseo_disable_title_rewrites', false ) ) {
return;
}
add_filter( 'pre_get_document_title', [ $this, 'getTitle' ], 99999 );
add_filter( 'wp_title', [ $this, 'getTitle' ], 99999 );
if ( ! current_theme_supports( 'title-tag' ) ) {
add_action( 'template_redirect', [ $this->title, 'startOutputBuffering' ], 99999 );
add_action( 'wp_head', [ $this->title, 'endOutputBuffering' ], 99999 );
}
}
/**
* Outputs the head.
*
* @since 4.0.5
* @version 4.6.1
*
* @return void
*/
public function wpHead() {
$included = new Meta\Included();
if ( is_admin() || wp_doing_ajax() || wp_doing_cron() || ! $included->isIncluded() ) {
return;
}
$this->output();
}
/**
* Returns the page title.
*
* @since 4.0.5
*
* @param string $wpTitle The original page title from WordPress.
* @return string $pageTitle The page title.
*/
public function getTitle( $wpTitle = '' ) {
if ( null !== self::$pageTitle ) {
return self::$pageTitle;
}
self::$pageTitle = aioseo()->meta->title->filterPageTitle( $wpTitle );
return self::$pageTitle;
}
/**
* The output function itself.
*
* @since 4.0.0
*
* @return void
*/
public function output() {
remove_action( 'wp_head', 'rel_canonical' );
$views = apply_filters( 'aioseo_meta_views', $this->views );
if ( empty( $views ) ) {
return;
}
echo "\n\t\t<!-- " . sprintf(
'%1$s %2$s',
esc_html( AIOSEO_PLUGIN_NAME ),
aioseo()->helpers->getAioseoVersion() // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
) . " - aioseo.com -->\n";
foreach ( $views as $view ) {
require $view;
}
echo "\t\t<!-- " . esc_html( AIOSEO_PLUGIN_NAME ) . " -->\n\n";
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace AIOSEO\Plugin\Common\Main;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
/**
* Abstract class that Pro and Lite both extend.
*
* @since 4.0.0
*/
class Main {
/**
* Construct method.
*
* @since 4.0.0
*/
public function __construct() {
new Media();
new QueryArgs();
add_action( 'admin_enqueue_scripts', [ $this, 'enqueueTranslations' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'enqueueFrontEndAssets' ] );
add_action( 'admin_footer', [ $this, 'adminFooter' ] );
}
/**
* Enqueues the translations seperately so it can be called from anywhere.
*
* @since 4.1.9
*
* @return void
*/
public function enqueueTranslations() {
aioseo()->core->assets->load( 'src/vue/standalone/app/main.js', [], [
'translations' => aioseo()->helpers->getJedLocaleData( 'all-in-one-seo-pack' )
], 'aioseoTranslations' );
}
/**
* Enqueue styles on the front-end.
*
* @since 4.0.0
*
* @return void
*/
public function enqueueFrontEndAssets() {
$canManageSeo = apply_filters( 'aioseo_manage_seo', 'aioseo_manage_seo' );
if (
! aioseo()->helpers->isAdminBarEnabled() ||
! ( current_user_can( $canManageSeo ) || aioseo()->access->canManage() )
) {
return;
}
aioseo()->core->assets->enqueueCss( 'src/vue/assets/scss/app/admin-bar.scss' );
}
/**
* Enqueue the footer file to let vue attach.
*
* @since 4.0.0
*
* @return void
*/
public function adminFooter() {
echo '<div id="aioseo-admin"></div>';
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace AIOSEO\Plugin\Common\Main;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Media class.
*
* @since 4.0.0
*/
class Media {
/**
* Construct method.
*
* @since 4.0.0
*/
public function __construct() {
add_action( 'template_redirect', [ $this, 'attachmentRedirect' ], 1 );
}
/**
* If the user wants to redirect attachment pages, this is where we do it.
*
* @since 4.0.0
*
* @return void
*/
public function attachmentRedirect() {
if ( ! is_attachment() ) {
return;
}
if (
! aioseo()->dynamicOptions->searchAppearance->postTypes->has( 'attachment' )
) {
return;
}
$redirect = aioseo()->dynamicOptions->searchAppearance->postTypes->attachment->redirectAttachmentUrls;
if ( 'disabled' === $redirect ) {
return;
}
if ( 'attachment' === $redirect ) {
$url = wp_get_attachment_url( get_queried_object_id() );
if ( empty( $url ) ) {
return;
}
return wp_safe_redirect( $url, 301, AIOSEO_PLUGIN_SHORT_NAME );
}
global $post;
if ( ! empty( $post->post_parent ) ) {
wp_safe_redirect( urldecode( get_permalink( $post->post_parent ) ), 301 );
}
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace AIOSEO\Plugin\Common\Main;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* This class contains pre-updates necessary for the next updates class to run.
*
* @since 4.1.5
*/
class PreUpdates {
/**
* Class constructor.
*
* @since 4.1.5
*/
public function __construct() {
// We don't want an AJAX request check here since the plugin might be installed/activated for the first time via AJAX (e.g. EDD/BLC).
// If that's the case, the cache table needs to be created before the activation hook runs.
if ( wp_doing_cron() ) {
return;
}
$lastActiveVersion = aioseo()->internalOptions->internal->lastActiveVersion;
if ( aioseo()->version !== $lastActiveVersion ) {
// Bust the table/columns cache so that we can start the update migrations with a fresh slate.
aioseo()->internalOptions->database->installedTables = '';
}
if ( version_compare( $lastActiveVersion, '4.1.5', '<' ) ) {
$this->createCacheTable();
}
if ( version_compare( $lastActiveVersion, AIOSEO_VERSION, '<' ) ) {
aioseo()->core->cache->clear();
}
}
/**
* Creates a new aioseo_cache table.
*
* @since 4.1.5
*
* @return void
*/
public function createCacheTable() {
$db = aioseo()->core->db->db;
$charsetCollate = '';
if ( ! empty( $db->charset ) ) {
$charsetCollate .= "DEFAULT CHARACTER SET {$db->charset}";
}
if ( ! empty( $db->collate ) ) {
$charsetCollate .= " COLLATE {$db->collate}";
}
$tableName = aioseo()->core->cache->getTableName();
if ( ! aioseo()->core->db->tableExists( $tableName ) ) {
$tableName = $db->prefix . $tableName;
aioseo()->core->db->execute(
"CREATE TABLE {$tableName} (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`key` varchar(80) NOT NULL,
`value` longtext NOT NULL,
`expiration` datetime NULL,
`created` datetime NOT NULL,
`updated` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY ndx_aioseo_cache_key (`key`),
KEY ndx_aioseo_cache_expiration (`expiration`)
) {$charsetCollate};"
);
}
}
}

View File

@@ -0,0 +1,218 @@
<?php
namespace AIOSEO\Plugin\Common\Main;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models\CrawlCleanupLog;
use AIOSEO\Plugin\Common\Models\CrawlCleanupBlockedArg;
/**
* Query arguments class.
*
* @since 4.2.1
* @version 4.5.8
*/
class QueryArgs {
/**
* Construct method.
*
* @since 4.2.1
*/
public function __construct() {
if (
is_admin() ||
aioseo()->helpers->isWpLoginPage() ||
aioseo()->helpers->isAjaxCronRestRequest() ||
aioseo()->helpers->isDoingWpCli()
) {
return;
}
add_action( 'template_redirect', [ $this, 'maybeRemoveQueryArgs' ], 1 );
$this->removeReplyToCom();
}
/**
* Check if we can remove query args.
*
* @since 4.5.8
*
* @return boolean True if the query args can be removed.
*/
private function canRemoveQueryArgs() {
if (
! aioseo()->options->searchAppearance->advanced->blockArgs->enable ||
is_user_logged_in() ||
is_admin() ||
is_robots() ||
get_query_var( 'aiosp_sitemap_path' ) ||
empty( $_GET ) // phpcs:ignore HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
) {
return false;
}
if ( is_singular() ) {
global $post;
$thePost = aioseo()->helpers->getPost( $post->ID );
// Leave the preview query arguments intact.
if (
// phpcs:disable phpcs:ignore HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
isset( $_GET['preview'] ) &&
isset( $_GET['preview_nonce'] ) &&
// phpcs:enable
wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['preview_nonce'] ) ), 'post_preview_' . $thePost->ID ) &&
current_user_can( 'edit_post', $thePost->ID )
) {
return false;
}
}
return true;
}
/**
* Maybe remove query args.
*
* @since 4.5.8
*
* @return void
*/
public function maybeRemoveQueryArgs() {
if ( ! $this->canRemoveQueryArgs() ) {
return;
}
$currentRequest = aioseo()->helpers->getRequestUrl();
// Remove the home path from the url for subfolder installs.
$currentRequest = aioseo()->helpers->excludeHomePath( $currentRequest );
$currentRequestParsed = wp_parse_url( $currentRequest );
// No query args? Never mind!
if ( empty( $currentRequestParsed['query'] ) ) {
return;
}
parse_str( $currentRequestParsed['query'], $currentRequestQueryArgs );
$notAllowed = [];
$recognizedQueryLogs = [];
foreach ( $currentRequestQueryArgs as $key => $value ) {
if ( ! is_string( $value ) ) {
continue;
}
$this->addQueryLog( $currentRequestParsed['path'], $key, $value );
$blocked = CrawlCleanupBlockedArg::getByKeyValue( $key, null );
if ( ! $blocked->exists() ) {
$blocked = CrawlCleanupBlockedArg::getByKeyValue( $key, $value );
}
if ( ! $blocked->exists() ) {
$blocked = CrawlCleanupBlockedArg::matchRegex( $key, $value );
}
if ( $blocked->exists() ) {
$queryArg = $key . ( $value ? '=' . $value : null );
$notAllowed[] = $queryArg;
$blocked->addHit();
continue;
}
$recognizedQueryLogs[ $key ] = empty( $value ) ? true : $value;
}
if ( ! empty( $notAllowed ) ) {
$newUrl = home_url( $currentRequestParsed['path'] );
header( 'Content-Type: redirect', true );
header_remove( 'Content-Type' );
header_remove( 'Last-Modified' );
header_remove( 'X-Pingback' );
wp_safe_redirect( add_query_arg( $recognizedQueryLogs, $newUrl ), 301, AIOSEO_PLUGIN_SHORT_NAME . ' Crawl Cleanup' );
exit;
}
}
/**
* Remove ?replytocom.
*
* @since 4.5.8
*
* @return void
*/
private function removeReplyToCom() {
if ( ! apply_filters( 'aioseo_remove_reply_to_com', true ) ) {
return;
}
add_filter( 'comment_reply_link', [ $this, 'removeReplyToComLink' ] );
add_action( 'template_redirect', [ $this, 'replyToComRedirect' ], 1 );
}
/**
* Remove ?replytocom.
*
* @since 4.7.3
*
* @param string $link The comment link as a string.
* @return string The modified link.
*/
public function removeReplyToComLink( $link ) {
return preg_replace( '`href=(["\'])(?:.*(?:\?|&|&#038;)replytocom=(\d+)#respond)`', 'href=$1#comment-$2', (string) $link );
}
/**
* Redirects out the ?replytocom variables.
*
* @since 4.7.3
*
* @return void
*/
public function replyToComRedirect() {
$replyToCom = absint( wp_unslash( $_GET['replytocom'] ?? null ) ); // phpcs:ignore HM.Security.NonceVerification.Recommended
if ( ! empty( $replyToCom ) && is_singular() ) {
$url = get_permalink( $GLOBALS['post']->ID );
if ( isset( $_SERVER['QUERY_STRING'] ) ) {
$queryString = remove_query_arg( 'replytocom', sanitize_text_field( wp_unslash( $_SERVER['QUERY_STRING'] ) ) );
if ( ! empty( $queryString ) ) {
$url = add_query_arg( [], $url ) . '?' . $queryString;
}
}
$url = add_query_arg( [], $url ) . '#comment-' . $replyToCom;
wp_safe_redirect( $url, 301, AIOSEO_PLUGIN_SHORT_NAME );
exit;
}
}
/**
* Add query args log.
*
* @since 4.5.8
*
* @param string $path A String of the path to create a slug.
* @param string $key A String of key from query arg.
* @param string $value A String of value from query arg.
* @return void
*/
private function addQueryLog( $path, $key, $value = null ) {
$slug = $path . '?' . $key . ( 0 < strlen( $value ) ? '=' . $value : '' );
$log = CrawlCleanupLog::getBySlug( $slug );
$data = [
'slug' => $slug,
'key' => $key,
'value' => $value
];
$log->set( $data );
$log->create();
}
}

View File

@@ -0,0 +1,88 @@
<?php
namespace AIOSEO\Plugin\Common\Main;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Document Title class.
*
* @since 4.3.9
*/
class Title {
/**
* Keeps the buffer level.
*
* @since 4.3.9
*
* @var int
*/
private $bufferLevel = 0;
/**
* Starts the output buffering.
*
* @since 4.3.2
* @version 4.3.9
*
* @return void
*/
public function startOutputBuffering() {
ob_start();
$this->bufferLevel = ob_get_level();
}
/**
* Ends the output buffering.
*
* @since 4.3.2
* @version 4.3.9
*
* @return void
*/
public function endOutputBuffering() {
// Bail if our code didn't start the output buffering at all.
if ( 0 === $this->bufferLevel ) {
return;
}
/**
* In case the current buffer level is different from the one we kept earlier, then: either a plugin started a new buffer or ended our buffer earlier.
* If that's the case, we can't properly rewrite the document title anymore since we don't know what buffer content we'd parse below.
* In order to avoid conflicts/errors (blank/broken pages), we just bail.
* If we bail, the page won't have the title set by AIOSEO, but this can be fixed if the active theme starts supporting the "title-tag" feature {@link https://codex.wordpress.org/Title_Tag}.
*/
if ( ob_get_level() !== $this->bufferLevel ) {
return;
}
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $this->rewriteTitle( (string) ob_get_clean() );
}
/**
* Replace the page document title.
*
* @since 4.0.5
* @version 4.3.2
* @version 4.3.9
*
* @param string $content The buffer content.
* @return string The rewritten title.
*/
private function rewriteTitle( $content ) {
if ( strpos( $content, '<!-- All in One SEO' ) === false ) {
return $content;
}
// Remove all existing title tags.
$content = preg_replace( '#<title.*?/title>#s', '', (string) $content );
$pageTitle = aioseo()->helpers->escapeRegexReplacement( aioseo()->head->getTitle() );
// Return new output with our new title tag included in our own comment block.
return preg_replace( '/(<!--\sAll\sin\sOne\sSEO[a-z0-9\s.]+\s-\saioseo\.com\s-->)/i', "$1\r\n\t\t<title>$pageTitle</title>", (string) $content, 1 );
}
}

View File

@@ -0,0 +1,108 @@
<?php
namespace AIOSEO\Plugin\Common\Main;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Utils;
/**
* Handles plugin deinstallation.
*
* @since 4.8.1
*/
class Uninstall {
/**
* Removes all data.
*
* @since 4.8.1
*
* @param bool $force Whether we should ignore the uninstall option or not. We ignore it when we reset all data via the Debug Panel.
* @return void
*/
public function dropData( $force = false ) {
// Don't call `aioseo()->options` as it's not loaded during uninstall.
$aioseoOptions = get_option( 'aioseo_options', '' );
$aioseoOptions = json_decode( $aioseoOptions, true );
// Confirm that user has decided to remove all data, otherwise stop.
if (
! $force &&
empty( $aioseoOptions['advanced']['uninstall'] )
) {
return;
}
// Drop our custom tables.
$this->uninstallDb();
// Delete all our custom capabilities.
$this->uninstallCapabilities();
}
/**
* Removes all our tables and options.
*
* @since 4.2.3
* @version 4.8.1 Moved from Core to Uninstall.
*
* @return void
*/
private function uninstallDb() {
// Delete all our custom tables.
global $wpdb;
// phpcs:disable WordPress.DB.DirectDatabaseQuery
foreach ( aioseo()->core->getDbTables() as $tableName ) {
$wpdb->query( $wpdb->prepare( 'DROP TABLE IF EXISTS %i', $tableName ) );
}
// Delete all AIOSEO Locations and Location Categories.
$wpdb->delete( $wpdb->posts, [ 'post_type' => 'aioseo-location' ], [ '%s' ] );
$wpdb->delete( $wpdb->term_taxonomy, [ 'taxonomy' => 'aioseo-location-category' ], [ '%s' ] );
// Delete all the plugin settings.
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", 'aioseo\_%' ) );
// Remove any transients we've left behind.
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", '\_aioseo\_%' ) );
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", 'aioseo\_%' ) );
// Delete all entries from the action scheduler table.
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}actionscheduler_actions WHERE hook LIKE %s", 'aioseo\_%' ) );
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}actionscheduler_groups WHERE slug = %s", 'aioseo' ) );
// phpcs:enable
}
/**
* Removes all our custom capabilities.
*
* @since 4.8.1
*
* @return void
*/
private function uninstallCapabilities() {
$access = new Utils\Access();
$customCapabilities = $access->getCapabilityList() ?? [];
$roles = aioseo()->helpers->getUserRoles();
// Loop through roles and remove custom capabilities.
foreach ( $roles as $roleName => $roleInfo ) {
$role = get_role( $roleName );
if ( $role ) {
$role->remove_cap( 'aioseo_admin' );
$role->remove_cap( 'aioseo_manage_seo' );
foreach ( $customCapabilities as $capability ) {
$role->remove_cap( $capability );
}
}
}
remove_role( 'aioseo_manager' );
remove_role( 'aioseo_editor' );
}
}