| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706 |
- <?php
- /**
- * WPSEO plugin file.
- *
- * @package WPSEO\Admin
- */
- /**
- * Performs the load on admin side.
- */
- class WPSEO_Admin_Init {
- /**
- * Holds the global `$pagenow` variable's value.
- *
- * @var string
- */
- private $pagenow;
- /**
- * Holds the asset manager.
- *
- * @var WPSEO_Admin_Asset_Manager
- */
- private $asset_manager;
- /**
- * Class constructor
- */
- public function __construct() {
- $GLOBALS['wpseo_admin'] = new WPSEO_Admin();
- $this->pagenow = $GLOBALS['pagenow'];
- $this->asset_manager = new WPSEO_Admin_Asset_Manager();
- add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_dismissible' ) );
- add_action( 'admin_init', array( $this, 'tagline_notice' ), 15 );
- add_action( 'admin_init', array( $this, 'blog_public_notice' ), 15 );
- add_action( 'admin_init', array( $this, 'permalink_notice' ), 15 );
- add_action( 'admin_init', array( $this, 'page_comments_notice' ), 15 );
- add_action( 'admin_init', array( $this, 'ga_compatibility_notice' ), 15 );
- add_action( 'admin_init', array( $this, 'yoast_plugin_compatibility_notification' ), 15 );
- add_action( 'admin_init', array( $this, 'yoast_plugin_suggestions_notification' ), 15 );
- add_action( 'admin_init', array( $this, 'recalculate_notice' ), 15 );
- add_action( 'admin_init', array( $this, 'unsupported_php_notice' ), 15 );
- add_action( 'admin_init', array( $this->asset_manager, 'register_assets' ) );
- add_action( 'admin_init', array( $this, 'show_hook_deprecation_warnings' ) );
- add_action( 'admin_init', array( 'WPSEO_Plugin_Conflict', 'hook_check_for_plugin_conflicts' ) );
- add_action( 'admin_init', array( $this, 'handle_notifications' ), 15 );
- $listeners = array();
- $listeners[] = new WPSEO_Post_Type_Archive_Notification_Handler();
- /** @var WPSEO_Listener $listener */
- foreach ( $listeners as $listener ) {
- $listener->listen();
- }
- $this->load_meta_boxes();
- $this->load_taxonomy_class();
- $this->load_admin_page_class();
- $this->load_admin_user_class();
- $this->load_xml_sitemaps_admin();
- $this->load_plugin_suggestions();
- }
- /**
- * Handles the notifiers for the dashboard page.
- *
- * @return void
- */
- public function handle_notifications() {
- /**
- * @var WPSEO_Notification_Handler[] $handlers
- */
- $handlers = array();
- $handlers[] = new WPSEO_Post_Type_Archive_Notification_Handler();
- $notification_center = Yoast_Notification_Center::get();
- foreach ( $handlers as $handler ) {
- $handler->handle( $notification_center );
- }
- }
- /**
- * Enqueue our styling for dismissible yoast notifications.
- */
- public function enqueue_dismissible() {
- $this->asset_manager->enqueue_style( 'dismissible' );
- }
- /**
- * Helper to verify if the current user has already seen the about page for the current version
- *
- * @return bool
- */
- private function seen_about() {
- $seen_about_version = substr( get_user_meta( get_current_user_id(), 'wpseo_seen_about_version', true ), 0, 3 );
- $last_minor_version = substr( WPSEO_VERSION, 0, 3 );
- return version_compare( $seen_about_version, $last_minor_version, '>=' );
- }
- /**
- * Notify about the default tagline if the user hasn't changed it
- */
- public function tagline_notice() {
- $current_url = ( is_ssl() ? 'https://' : 'http://' );
- $current_url .= sanitize_text_field( $_SERVER['SERVER_NAME'] ) . sanitize_text_field( $_SERVER['REQUEST_URI'] );
- $customize_url = add_query_arg( array(
- 'autofocus[control]' => 'blogdescription',
- 'url' => urlencode( $current_url ),
- ), wp_customize_url() );
- $info_message = sprintf(
- /* translators: 1: link open tag; 2: link close tag. */
- __( 'You still have the default WordPress tagline, even an empty one is probably better. %1$sYou can fix this in the customizer%2$s.', 'wordpress-seo' ),
- '<a href="' . esc_attr( $customize_url ) . '">',
- '</a>'
- );
- $notification_options = array(
- 'type' => Yoast_Notification::ERROR,
- 'id' => 'wpseo-dismiss-tagline-notice',
- 'capabilities' => 'wpseo_manage_options',
- );
- $tagline_notification = new Yoast_Notification( $info_message, $notification_options );
- $notification_center = Yoast_Notification_Center::get();
- if ( $this->has_default_tagline() ) {
- $notification_center->add_notification( $tagline_notification );
- }
- else {
- $notification_center->remove_notification( $tagline_notification );
- }
- }
- /**
- * Add an alert if the blog is not publicly visible
- */
- public function blog_public_notice() {
- $info_message = '<strong>' . __( 'Huge SEO Issue: You\'re blocking access to robots.', 'wordpress-seo' ) . '</strong> ';
- $info_message .= sprintf(
- /* translators: %1$s resolves to the opening tag of the link to the reading settings, %1$s resolves to the closing tag for the link */
- __( 'You must %1$sgo to your Reading Settings%2$s and uncheck the box for Search Engine Visibility.', 'wordpress-seo' ),
- '<a href="' . esc_url( admin_url( 'options-reading.php' ) ) . '">',
- '</a>'
- );
- $notification_options = array(
- 'type' => Yoast_Notification::ERROR,
- 'id' => 'wpseo-dismiss-blog-public-notice',
- 'priority' => 1.0,
- 'capabilities' => 'wpseo_manage_options',
- );
- $notification = new Yoast_Notification( $info_message, $notification_options );
- $notification_center = Yoast_Notification_Center::get();
- if ( ! $this->is_blog_public() ) {
- $notification_center->add_notification( $notification );
- }
- else {
- $notification_center->remove_notification( $notification );
- }
- }
- /**
- * Display notice to disable comment pagination
- */
- public function page_comments_notice() {
- $info_message = __( 'Paging comments is enabled, this is not needed in 999 out of 1000 cases, we recommend to disable it.', 'wordpress-seo' );
- $info_message .= '<br/>';
- $info_message .= sprintf(
- /* translators: %1$s resolves to the opening tag of the link to the comment setting page, %2$s resolves to the closing tag of the link */
- __( 'To fix this uncheck the box in front of the "Break comments into pages..." on the %1$sComment settings page%2$s.', 'wordpress-seo' ),
- '<a href="' . esc_url( admin_url( 'options-discussion.php' ) ) . '">',
- '</a>'
- );
- $notification_options = array(
- 'type' => Yoast_Notification::WARNING,
- 'id' => 'wpseo-dismiss-page_comments-notice',
- 'capabilities' => 'wpseo_manage_options',
- );
- $tagline_notification = new Yoast_Notification( $info_message, $notification_options );
- $notification_center = Yoast_Notification_Center::get();
- if ( $this->has_page_comments() ) {
- $notification_center->add_notification( $tagline_notification );
- }
- else {
- $notification_center->remove_notification( $tagline_notification );
- }
- }
- /**
- * Returns whether or not the site has the default tagline
- *
- * @return bool
- */
- public function has_default_tagline() {
- $blog_description = get_bloginfo( 'description' );
- $default_blog_description = 'Just another WordPress site';
- // We are checking against the WordPress internal translation.
- // @codingStandardsIgnoreLine
- $translated_blog_description = __( 'Just another WordPress site' );
- return $translated_blog_description === $blog_description || $default_blog_description === $blog_description;
- }
- /**
- * Show alert when the permalink doesn't contain %postname%
- */
- public function permalink_notice() {
- $info_message = __( 'You do not have your postname in the URL of your posts and pages, it is highly recommended that you do. Consider setting your permalink structure to <strong>/%postname%/</strong>.', 'wordpress-seo' );
- $info_message .= '<br/>';
- $info_message .= sprintf(
- /* translators: %1$s resolves to the starting tag of the link to the permalink settings page, %2$s resolves to the closing tag of the link */
- __( 'You can fix this on the %1$sPermalink settings page%2$s.', 'wordpress-seo' ),
- '<a href="' . admin_url( 'options-permalink.php' ) . '">',
- '</a>'
- );
- $notification_options = array(
- 'type' => Yoast_Notification::WARNING,
- 'id' => 'wpseo-dismiss-permalink-notice',
- 'capabilities' => 'wpseo_manage_options',
- 'priority' => 0.8,
- );
- $notification = new Yoast_Notification( $info_message, $notification_options );
- $notification_center = Yoast_Notification_Center::get();
- if ( ! $this->has_postname_in_permalink() ) {
- $notification_center->add_notification( $notification );
- }
- else {
- $notification_center->remove_notification( $notification );
- }
- }
- /**
- * Are page comments enabled
- *
- * @return bool
- */
- public function has_page_comments() {
- return '1' === get_option( 'page_comments' );
- }
- /**
- * Shows a notice to the user if they have Google Analytics for WordPress 5.4.3 installed because it causes an error
- * on the google search console page.
- */
- public function ga_compatibility_notice() {
- $notification = $this->get_compatibility_notification();
- $notification_center = Yoast_Notification_Center::get();
- if ( defined( 'GAWP_VERSION' ) && '5.4.3' === GAWP_VERSION ) {
- $notification_center->add_notification( $notification );
- }
- else {
- $notification_center->remove_notification( $notification );
- }
- }
- /**
- * Build compatibility problem notification
- *
- * @return Yoast_Notification
- */
- private function get_compatibility_notification() {
- $info_message = sprintf(
- /* translators: %1$s expands to Yoast SEO, %2$s expands to 5.4.3, %3$s expands to Google Analytics by Yoast */
- __( '%1$s detected you are using version %2$s of %3$s, please update to the latest version to prevent compatibility issues.', 'wordpress-seo' ),
- 'Yoast SEO',
- '5.4.3',
- 'Google Analytics by Yoast'
- );
- return new Yoast_Notification(
- $info_message,
- array(
- 'id' => 'gawp-compatibility-notice',
- 'type' => Yoast_Notification::ERROR,
- )
- );
- }
- /**
- * Determines whether a suggested plugins notification needs to be displayed.
- *
- * @return void
- */
- public function yoast_plugin_suggestions_notification() {
- $checker = new WPSEO_Plugin_Availability();
- $notification_center = Yoast_Notification_Center::get();
- // Get all Yoast plugins that have dependencies.
- $plugins = $checker->get_plugins_with_dependencies();
- foreach ( $plugins as $plugin_name => $plugin ) {
- $dependency_names = $checker->get_dependency_names( $plugin );
- $notification = $this->get_yoast_seo_suggested_plugins_notification( $plugin_name, $plugin, $dependency_names[0] );
- if ( $checker->dependencies_are_satisfied( $plugin ) && ! $checker->is_installed( $plugin ) ) {
- $notification_center->add_notification( $notification );
- continue;
- }
- $notification_center->remove_notification( $notification );
- }
- }
- /**
- * Build Yoast SEO suggested plugins notification.
- *
- * @param string $name The plugin name to use for the unique ID.
- * @param array $plugin The plugin to retrieve the data from.
- * @param string $dependency_name The name of the dependency.
- *
- * @return Yoast_Notification The notification containing the suggested plugin.
- */
- private function get_yoast_seo_suggested_plugins_notification( $name, $plugin, $dependency_name ) {
- $info_message = sprintf(
- /* translators: %1$s expands to Yoast SEO, %2$s expands to the plugin version, %3$s expands to the plugin name */
- __( '%1$s and %2$s can work together a lot better by adding a helper plugin. Please install %3$s to make your life better.', 'wordpress-seo' ),
- 'Yoast SEO',
- $dependency_name,
- sprintf( '<a href="%s">%s</a>', $plugin['url'], $plugin['title'] )
- );
- return new Yoast_Notification(
- $info_message,
- array(
- 'id' => 'wpseo-suggested-plugin-' . $name,
- 'type' => Yoast_Notification::WARNING,
- )
- );
- }
- /**
- * Add an alert if outdated versions of Yoast SEO plugins are running.
- */
- public function yoast_plugin_compatibility_notification() {
- $compatibility_checker = new WPSEO_Plugin_Compatibility( WPSEO_VERSION );
- $plugins = $compatibility_checker->get_installed_plugins_compatibility();
- $notification_center = Yoast_Notification_Center::get();
- foreach ( $plugins as $name => $plugin ) {
- $type = ( $plugin['active'] ) ? Yoast_Notification::ERROR : Yoast_Notification::WARNING;
- $notification = $this->get_yoast_seo_compatibility_notification( $name, $plugin, $type );
- if ( $plugin['compatible'] === false ) {
- $notification_center->add_notification( $notification );
- continue;
- }
- $notification_center->remove_notification( $notification );
- }
- }
- /**
- * Build Yoast SEO compatibility problem notification
- *
- * @param string $name The plugin name to use for the unique ID.
- * @param array $plugin The plugin to retrieve the data from.
- * @param string $level The severity level to use for the notification.
- *
- * @return Yoast_Notification
- */
- private function get_yoast_seo_compatibility_notification( $name, $plugin, $level = Yoast_Notification::WARNING ) {
- $info_message = sprintf(
- /* translators: %1$s expands to Yoast SEO, %2$s expands to the plugin version, %3$s expands to the plugin name */
- __( '%1$s detected you are using version %2$s of %3$s, please update to the latest version to prevent compatibility issues.', 'wordpress-seo' ),
- 'Yoast SEO',
- $plugin['version'],
- $plugin['title']
- );
- return new Yoast_Notification(
- $info_message,
- array(
- 'id' => 'wpseo-outdated-yoast-seo-plugin-' . $name,
- 'type' => $level,
- )
- );
- }
- /**
- * Shows the notice for recalculating the post. the Notice will only be shown if the user hasn't dismissed it before.
- */
- public function recalculate_notice() {
- // Just a return, because we want to temporary disable this notice (#3998 and #4532).
- return;
- if ( filter_input( INPUT_GET, 'recalculate' ) === '1' ) {
- update_option( 'wpseo_dismiss_recalculate', '1' );
- return;
- }
- if ( ! WPSEO_Capability_Utils::current_user_can( 'wpseo_manage_options' ) ) {
- return;
- }
- if ( $this->is_site_notice_dismissed( 'wpseo_dismiss_recalculate' ) ) {
- return;
- }
- Yoast_Notification_Center::get()->add_notification(
- new Yoast_Notification(
- sprintf(
- /* translators: 1: is a link to 'admin_url / admin.php?page=wpseo_tools&recalculate=1' 2: closing link tag */
- __( 'We\'ve updated our SEO score algorithm. %1$sRecalculate the SEO scores%2$s for all posts and pages.', 'wordpress-seo' ),
- '<a href="' . admin_url( 'admin.php?page=wpseo_tools&recalculate=1' ) . '">',
- '</a>'
- ),
- array(
- 'type' => 'updated yoast-dismissible',
- 'id' => 'wpseo-dismiss-recalculate',
- 'nonce' => wp_create_nonce( 'wpseo-dismiss-recalculate' ),
- )
- )
- );
- }
- /**
- * Creates an unsupported PHP version notification in the notification center.
- *
- * @return void
- */
- public function unsupported_php_notice() {
- $notification_center = Yoast_Notification_Center::get();
- $notification_center->remove_notification_by_id( 'wpseo-dismiss-unsupported-php' );
- }
- /**
- * Check if the user has dismissed the given notice (by $notice_name)
- *
- * @param string $notice_name The name of the notice that might be dismissed.
- *
- * @return bool
- */
- private function is_site_notice_dismissed( $notice_name ) {
- return '1' === get_option( $notice_name, true );
- }
- /**
- * Helper to verify if the user is currently visiting one of our admin pages.
- *
- * @return bool
- */
- private function on_wpseo_admin_page() {
- return 'admin.php' === $this->pagenow && strpos( filter_input( INPUT_GET, 'page' ), 'wpseo' ) === 0;
- }
- /**
- * Determine whether we should load the meta box class and if so, load it.
- */
- private function load_meta_boxes() {
- $is_editor = WPSEO_Metabox::is_post_overview( $this->pagenow ) || WPSEO_Metabox::is_post_edit( $this->pagenow );
- $is_inline_save = filter_input( INPUT_POST, 'action' ) === 'inline-save';
- /**
- * Filter: 'wpseo_always_register_metaboxes_on_admin' - Allow developers to change whether
- * the WPSEO metaboxes are only registered on the typical pages (lean loading) or always
- * registered when in admin.
- *
- * @api bool Whether to always register the metaboxes or not. Defaults to false.
- */
- if ( $is_editor || $is_inline_save || apply_filters( 'wpseo_always_register_metaboxes_on_admin', false )
- ) {
- $GLOBALS['wpseo_metabox'] = new WPSEO_Metabox();
- $GLOBALS['wpseo_meta_columns'] = new WPSEO_Meta_Columns();
- }
- }
- /**
- * Determine if we should load our taxonomy edit class and if so, load it.
- */
- private function load_taxonomy_class() {
- if (
- WPSEO_Taxonomy::is_term_edit( $this->pagenow )
- || WPSEO_Taxonomy::is_term_overview( $this->pagenow )
- ) {
- new WPSEO_Taxonomy();
- }
- }
- /**
- * Determine if we should load our admin pages class and if so, load it.
- *
- * Loads admin page class for all admin pages starting with `wpseo_`.
- */
- private function load_admin_user_class() {
- if ( in_array( $this->pagenow, array( 'user-edit.php', 'profile.php' ), true )
- && current_user_can( 'edit_users' )
- ) {
- new WPSEO_Admin_User_Profile();
- }
- }
- /**
- * Determine if we should load our admin pages class and if so, load it.
- *
- * Loads admin page class for all admin pages starting with `wpseo_`.
- */
- private function load_admin_page_class() {
- if ( $this->on_wpseo_admin_page() ) {
- // For backwards compatabilty, this still needs a global, for now...
- $GLOBALS['wpseo_admin_pages'] = new WPSEO_Admin_Pages();
- // Only register the yoast i18n when the page is a Yoast SEO page.
- if ( WPSEO_Utils::is_yoast_seo_free_page( filter_input( INPUT_GET, 'page' ) ) ) {
- $this->register_i18n_promo_class();
- $this->register_premium_upsell_admin_block();
- }
- }
- }
- /**
- * Loads the plugin suggestions.
- */
- private function load_plugin_suggestions() {
- $suggestions = new WPSEO_Suggested_Plugins( new WPSEO_Plugin_Availability(), Yoast_Notification_Center::get() );
- $suggestions->register_hooks();
- }
- /**
- * Registers the Premium Upsell Admin Block.
- *
- * @return void
- */
- private function register_premium_upsell_admin_block() {
- if ( ! WPSEO_Utils::is_yoast_seo_premium() ) {
- $upsell_block = new WPSEO_Premium_Upsell_Admin_Block( 'wpseo_admin_promo_footer' );
- $upsell_block->register_hooks();
- }
- }
- /**
- * Registers the promotion class for our GlotPress instance, then creates a notification with the i18n promo.
- *
- * @link https://github.com/Yoast/i18n-module
- */
- private function register_i18n_promo_class() {
- // BC, because an older version of the i18n-module didn't have this class.
- $i18n_module = new Yoast_I18n_WordPressOrg_v3(
- array(
- 'textdomain' => 'wordpress-seo',
- 'plugin_name' => 'Yoast SEO',
- 'hook' => 'wpseo_admin_promo_footer',
- ), false
- );
- $message = $i18n_module->get_promo_message();
- if ( $message !== '' ) {
- $message .= $i18n_module->get_dismiss_i18n_message_button();
- }
- $notification_center = Yoast_Notification_Center::get();
- $notification = new Yoast_Notification(
- $message,
- array(
- 'type' => Yoast_Notification::WARNING,
- 'id' => 'i18nModuleTranslationAssistance',
- )
- );
- if ( $message ) {
- $notification_center->add_notification( $notification );
- return;
- }
- $notification_center->remove_notification( $notification );
- }
- /**
- * See if we should start our XML Sitemaps Admin class
- */
- private function load_xml_sitemaps_admin() {
- if ( WPSEO_Options::get( 'enable_xml_sitemap', false ) ) {
- new WPSEO_Sitemaps_Admin();
- }
- }
- /**
- * Check if the site is set to be publicly visible
- *
- * @return bool
- */
- private function is_blog_public() {
- return '1' === (string) get_option( 'blog_public' );
- }
- /**
- * Shows deprecation warnings to the user if a plugin has registered a filter we have deprecated.
- */
- public function show_hook_deprecation_warnings() {
- global $wp_filter;
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
- return false;
- }
- // WordPress hooks that have been deprecated since a Yoast SEO version.
- $deprecated_filters = array(
- 'wpseo_metadesc_length' => array(
- 'version' => '3.0',
- 'alternative' => 'javascript',
- ),
- 'wpseo_metadesc_length_reason' => array(
- 'version' => '3.0',
- 'alternative' => 'javascript',
- ),
- 'wpseo_body_length_score' => array(
- 'version' => '3.0',
- 'alternative' => 'javascript',
- ),
- 'wpseo_linkdex_results' => array(
- 'version' => '3.0',
- 'alternative' => 'javascript',
- ),
- 'wpseo_snippet' => array(
- 'version' => '3.0',
- 'alternative' => 'javascript',
- ),
- 'wp_seo_get_bc_title' => array(
- 'version' => '5.8',
- 'alternative' => 'wpseo_breadcrumb_single_link_info',
- ),
- 'wpseo_metakey' => array(
- 'version' => '6.3',
- 'alternative' => null,
- ),
- 'wpseo_metakeywords' => array(
- 'version' => '6.3',
- 'alternative' => null,
- ),
- 'wpseo_stopwords' => array(
- 'version' => '7.0',
- 'alternative' => null,
- ),
- 'wpseo_redirect_orphan_attachment' => array(
- 'version' => '7.0',
- 'alternative' => null,
- ),
- );
- // Determine which filters have been registered.
- $deprecated_notices = array_intersect(
- array_keys( $deprecated_filters ),
- array_keys( $wp_filter )
- );
- // Show notice for each deprecated filter or action that has been registered.
- foreach ( $deprecated_notices as $deprecated_filter ) {
- $deprecation_info = $deprecated_filters[ $deprecated_filter ];
- _deprecated_hook(
- $deprecated_filter,
- 'WPSEO ' . $deprecation_info['version'],
- $deprecation_info['alternative']
- );
- }
- }
- /**
- * Check if there is a dismiss notice action.
- *
- * @param string $notice_name The name of the notice to dismiss.
- *
- * @return bool
- */
- private function dismiss_notice( $notice_name ) {
- return filter_input( INPUT_GET, $notice_name ) === '1' && wp_verify_nonce( filter_input( INPUT_GET, 'nonce' ), $notice_name );
- }
- /**
- * Check if the permalink uses %postname%
- *
- * @return bool
- */
- private function has_postname_in_permalink() {
- return ( false !== strpos( get_option( 'permalink_structure' ), '%postname%' ) );
- }
- }
|