You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

288 lines
8.2 KiB
PHP

<?php
/**
* The conflicting plugin watcher.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Security;
use RankMath\Helpers\Param;
use RankMath\Helper as GlobalHelper;
defined( 'ABSPATH' ) || exit;
/**
* Watcher class.
*/
class Watcher implements Runner {
use Hooker;
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'init', 'maybe_deactivate_plugins' );
$this->action( 'activated_plugin', 'check_activated_plugin' );
$this->action( 'deactivated_plugin', 'check_deactivated_plugin' );
$this->filter( 'wp_helpers_notifications_render', 'deactivate_plugins_link', 10, 3 );
$this->action( 'update_option_blog_public', 'check_search_engine_visibility' );
}
/**
* Set/Deactivate conflicting SEO or Sitemap plugins.
*/
public function maybe_deactivate_plugins() {
if ( ! Param::get( 'rank_math_deactivate_plugins' ) ) {
return;
}
if ( ! current_user_can( 'deactivate_plugins' ) ) {
wp_die( esc_html__( 'Sorry, you are not allowed to deactivate plugins for this site.', 'rank-math' ) );
}
check_admin_referer( 'rank_math_deactivate_plugins' );
$type = Param::get( 'plugin_type', 'seo', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
$allowed = [ 'seo', 'sitemap' ];
if ( ! in_array( $type, $allowed, true ) ) {
return;
}
$this->deactivate_conflicting_plugins( $type );
}
/**
* Function to run when new plugin is activated.
*/
public static function check_activated_plugin() {
$set = [];
$plugins = get_option( 'active_plugins', [] );
foreach ( self::get_conflicting_plugins() as $plugin => $type ) {
if ( ! isset( $set[ $type ] ) && in_array( $plugin, $plugins, true ) ) {
$set[ $type ] = true;
self::set_notification( $type );
}
}
if ( in_array( 'wpml-string-translation/plugin.php', $plugins, true ) ) {
GlobalHelper::remove_notification( 'convert_wpml_settings' );
}
}
/**
* Function to run when plugin is deactivated.
*
* @param string $plugin Deactivated plugin path.
*/
public function check_deactivated_plugin( $plugin ) {
$plugins = self::get_conflicting_plugins();
if ( ! isset( $plugins[ $plugin ] ) ) {
return;
}
$this->remove_notification( $plugins[ $plugin ], $plugin );
}
/**
* Function to run when Module is enabled/disabled.
*
* @param string $module Module.
* @param string $state Module state.
*/
public static function module_changed( $module, $state ) {
if ( ! in_array( $module, [ 'sitemap', 'redirections', 'rich-snippet' ], true ) ) {
return;
}
if ( 'off' === $state ) {
$type = 'sitemap' === $module ? 'sitemap' : 'seo';
GlobalHelper::remove_notification( "conflicting_{$type}_plugins" );
}
self::check_activated_plugin();
}
/**
* Deactivate conflicting plugins.
*
* @param string $type Plugin type.
*/
private function deactivate_conflicting_plugins( $type ) {
foreach ( self::get_conflicting_plugins() as $plugin => $plugin_type ) {
if ( $type === $plugin_type && is_plugin_active( $plugin ) ) {
if ( ! current_user_can( 'deactivate_plugin', $plugin ) ) {
$message = sprintf(
/* translators: plugin name */
esc_html__( 'You are not allowed to deactivate this plugin: %s.', 'rank-math' ),
esc_html( $plugin )
);
GlobalHelper::add_notification(
$message,
[
'type' => 'error',
'classes' => 'is-dismissible',
]
);
continue;
}
deactivate_plugins( $plugin );
}
}
GlobalHelper::redirect( Security::remove_query_arg_raw( [ 'rank_math_deactivate_plugins', 'plugin_type', '_wpnonce' ] ) );
}
/**
* Function to set conflict plugin notification.
*
* @param string $type Plugin type.
*/
private static function set_notification( $type ) {
$message = sprintf(
/* translators: deactivation link */
esc_html__( 'Please keep only one SEO plugin active, otherwise, you might lose your rankings and traffic. %s.', 'rank-math' ),
'<a href="###DEACTIVATE_SEO_PLUGINS###">' . __( 'Click here to Deactivate', 'rank-math' ) . '</a>'
);
if ( 'sitemap' === $type ) {
$message = sprintf(
/* translators: deactivation link */
esc_html__( 'Please keep only one Sitemap plugin active, otherwise, you might lose your rankings and traffic. %s.', 'rank-math' ),
'<a href="###DEACTIVATE_SITEMAP_PLUGINS###">' . __( 'Click here to Deactivate', 'rank-math' ) . '</a>'
);
}
GlobalHelper::add_notification(
$message,
[
'id' => "conflicting_{$type}_plugins",
'type' => 'error',
'classes' => 'is-dismissible',
]
);
}
/**
* Function to remove conflict plugin notification.
*
* @param string $type Plugin type.
* @param string $plugin Plugin name.
*/
private function remove_notification( $type, $plugin ) {
foreach ( self::get_conflicting_plugins() as $file => $plugin_type ) {
if ( $plugin !== $file && $type === $plugin_type && is_plugin_active( $file ) ) {
return;
}
}
GlobalHelper::remove_notification( "conflicting_{$type}_plugins" );
}
/**
* Function to get all conflicting plugins.
*
* @return array
*/
private static function get_conflicting_plugins() {
$plugins = [
'wordpress-seo/wp-seo.php' => 'seo',
'wordpress-seo-premium/wp-seo-premium.php' => 'seo',
'wpseo-local/local-seo.php' => 'seo',
'wpseo-news/wpseo-news.php' => 'seo',
'wpseo-video/video-seo.php' => 'seo',
'all-in-one-seo-pack/all_in_one_seo_pack.php' => 'seo',
'all-in-one-seo-pack-pro/all_in_one_seo_pack.php' => 'seo',
'wp-seopress/seopress.php' => 'seo',
'wp-seopress-pro/seopress-pro.php' => 'seo',
];
if ( GlobalHelper::is_module_active( 'redirections' ) ) {
$plugins['redirection/redirection.php'] = 'seo';
}
if ( GlobalHelper::is_module_active( 'sitemap' ) ) {
$plugins['google-sitemap-generator/sitemap.php'] = 'sitemap';
$plugins['xml-sitemap-feed/xml-sitemap.php'] = 'sitemap';
}
if ( GlobalHelper::is_module_active( 'rich-snippet' ) ) {
$plugins['wp-schema-pro/wp-schema-pro.php'] = 'seo';
$plugins['all-in-one-schemaorg-rich-snippets/index.php'] = 'seo';
}
return $plugins;
}
/**
* Replace link inside notice dynamically to avoid issues with the nonce.
*
* @param string $output Notice output.
* @param string $message Notice message.
* @param array $options Notice options.
*
* @return string
*/
public function deactivate_plugins_link( $output, $message, $options ) {
if ( ! isset( $options['id'] ) || ! preg_match( '/conflicting_.*_plugins/', $options['id'] ) ) {
return $output;
}
$deactivate_url = Security::add_query_arg(
[
'rank_math_deactivate_plugins' => '1',
'plugin_type' => 'seo',
'_wpnonce' => wp_create_nonce( 'rank_math_deactivate_plugins' ),
],
admin_url( 'plugins.php' )
);
$output = str_replace( '###DEACTIVATE_SEO_PLUGINS###', $deactivate_url, $output );
$deactivate_sitemap_plugins_url = Security::add_query_arg(
[
'rank_math_deactivate_plugins' => '1',
'plugin_type' => 'sitemap',
'_wpnonce' => wp_create_nonce( 'rank_math_deactivate_plugins' ),
],
admin_url( 'plugins.php' )
);
$output = str_replace( '###DEACTIVATE_SITEMAP_PLUGINS###', $deactivate_sitemap_plugins_url, $output );
return $output;
}
/**
* Check search visibility
*
* @param integer $value Setting value.
*/
public function check_search_engine_visibility( $value ) {
if ( ! $value ) {
GlobalHelper::remove_notification( 'search_engine_visibility' );
return;
}
GlobalHelper::add_notification(
sprintf(
// translators: %1$s: general reading settings URL.
__( '<strong>SEO Notice</strong>: Your site is set to No Index and will not appear in search engines. You can change the Search engine visibility <a href="%1$s">from here</a>.', 'rank-math' ),
admin_url( 'options-reading.php' )
),
[
'type' => 'warning',
'id' => 'search_engine_visibility',
'classes' => 'is-dismissible',
]
);
}
}