class-admin-init.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO\Admin
  6. */
  7. /**
  8. * Performs the load on admin side.
  9. */
  10. class WPSEO_Admin_Init {
  11. /**
  12. * Holds the global `$pagenow` variable's value.
  13. *
  14. * @var string
  15. */
  16. private $pagenow;
  17. /**
  18. * Holds the asset manager.
  19. *
  20. * @var WPSEO_Admin_Asset_Manager
  21. */
  22. private $asset_manager;
  23. /**
  24. * Class constructor.
  25. */
  26. public function __construct() {
  27. $GLOBALS['wpseo_admin'] = new WPSEO_Admin();
  28. $this->pagenow = $GLOBALS['pagenow'];
  29. $this->asset_manager = new WPSEO_Admin_Asset_Manager();
  30. add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_dismissible' ] );
  31. add_action( 'admin_init', [ $this, 'tagline_notice' ], 15 );
  32. add_action( 'admin_init', [ $this, 'blog_public_notice' ], 15 );
  33. add_action( 'admin_init', [ $this, 'permalink_notice' ], 15 );
  34. add_action( 'admin_init', [ $this, 'page_comments_notice' ], 15 );
  35. add_action( 'admin_init', [ $this, 'yoast_plugin_suggestions_notification' ], 15 );
  36. add_action( 'admin_init', [ $this, 'recalculate_notice' ], 15 );
  37. add_action( 'admin_init', [ $this, 'unsupported_php_notice' ], 15 );
  38. add_action( 'admin_init', [ $this->asset_manager, 'register_assets' ] );
  39. add_action( 'admin_init', [ $this, 'show_hook_deprecation_warnings' ] );
  40. add_action( 'admin_init', [ 'WPSEO_Plugin_Conflict', 'hook_check_for_plugin_conflicts' ] );
  41. add_action( 'admin_init', [ $this, 'handle_notifications' ], 15 );
  42. add_action( 'admin_notices', [ $this, 'permalink_settings_notice' ] );
  43. add_action( 'admin_enqueue_scripts', [ $this->asset_manager, 'register_wp_assets' ], PHP_INT_MAX );
  44. $listeners = [];
  45. $listeners[] = new WPSEO_Post_Type_Archive_Notification_Handler();
  46. /**
  47. * Listener interface classes.
  48. *
  49. * @var WPSEO_Listener $listener
  50. */
  51. foreach ( $listeners as $listener ) {
  52. $listener->listen();
  53. }
  54. $this->load_meta_boxes();
  55. $this->load_taxonomy_class();
  56. $this->load_admin_page_class();
  57. $this->load_admin_user_class();
  58. $this->load_xml_sitemaps_admin();
  59. $this->load_plugin_suggestions();
  60. }
  61. /**
  62. * Handles the notifiers for the dashboard page.
  63. *
  64. * @return void
  65. */
  66. public function handle_notifications() {
  67. /**
  68. * Notification handlers.
  69. *
  70. * @var WPSEO_Notification_Handler[] $handlers
  71. */
  72. $handlers = [];
  73. $handlers[] = new WPSEO_Post_Type_Archive_Notification_Handler();
  74. $notification_center = Yoast_Notification_Center::get();
  75. foreach ( $handlers as $handler ) {
  76. $handler->handle( $notification_center );
  77. }
  78. }
  79. /**
  80. * Enqueue our styling for dismissible yoast notifications.
  81. */
  82. public function enqueue_dismissible() {
  83. $this->asset_manager->enqueue_style( 'dismissible' );
  84. }
  85. /**
  86. * Notify about the default tagline if the user hasn't changed it.
  87. */
  88. public function tagline_notice() {
  89. $query_args = [
  90. 'autofocus[control]' => 'blogdescription',
  91. ];
  92. $customize_url = add_query_arg( $query_args, wp_customize_url() );
  93. $info_message = sprintf(
  94. /* translators: 1: link open tag; 2: link close tag. */
  95. __( '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' ),
  96. '<a href="' . esc_attr( $customize_url ) . '">',
  97. '</a>'
  98. );
  99. $notification_options = [
  100. 'type' => Yoast_Notification::ERROR,
  101. 'id' => 'wpseo-dismiss-tagline-notice',
  102. 'capabilities' => 'wpseo_manage_options',
  103. ];
  104. $tagline_notification = new Yoast_Notification( $info_message, $notification_options );
  105. $notification_center = Yoast_Notification_Center::get();
  106. $notification_center->remove_notification( $tagline_notification );
  107. }
  108. /**
  109. * Add an alert if the blog is not publicly visible.
  110. */
  111. public function blog_public_notice() {
  112. $info_message = '<strong>' . __( 'Huge SEO Issue: You\'re blocking access to robots.', 'wordpress-seo' ) . '</strong> ';
  113. $info_message .= sprintf(
  114. /* 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 */
  115. __( 'You must %1$sgo to your Reading Settings%2$s and uncheck the box for Search Engine Visibility.', 'wordpress-seo' ),
  116. '<a href="' . esc_url( admin_url( 'options-reading.php' ) ) . '">',
  117. '</a>'
  118. );
  119. $notification_options = [
  120. 'type' => Yoast_Notification::ERROR,
  121. 'id' => 'wpseo-dismiss-blog-public-notice',
  122. 'priority' => 1.0,
  123. 'capabilities' => 'wpseo_manage_options',
  124. ];
  125. $notification = new Yoast_Notification( $info_message, $notification_options );
  126. $notification_center = Yoast_Notification_Center::get();
  127. if ( ! $this->is_blog_public() ) {
  128. $notification_center->add_notification( $notification );
  129. }
  130. else {
  131. $notification_center->remove_notification( $notification );
  132. }
  133. }
  134. /**
  135. * Display notice to disable comment pagination.
  136. */
  137. public function page_comments_notice() {
  138. $info_message = __( 'Paging comments is enabled, this is not needed in 999 out of 1000 cases, we recommend to disable it.', 'wordpress-seo' );
  139. $info_message .= '<br/>';
  140. $info_message .= sprintf(
  141. /* 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 */
  142. __( 'To fix this uncheck the box in front of the "Break comments into pages..." on the %1$sComment settings page%2$s.', 'wordpress-seo' ),
  143. '<a href="' . esc_url( admin_url( 'options-discussion.php' ) ) . '">',
  144. '</a>'
  145. );
  146. $notification_options = [
  147. 'type' => Yoast_Notification::WARNING,
  148. 'id' => 'wpseo-dismiss-page_comments-notice',
  149. 'capabilities' => 'wpseo_manage_options',
  150. ];
  151. $tagline_notification = new Yoast_Notification( $info_message, $notification_options );
  152. $notification_center = Yoast_Notification_Center::get();
  153. if ( $this->has_page_comments() ) {
  154. $notification_center->add_notification( $tagline_notification );
  155. }
  156. else {
  157. $notification_center->remove_notification( $tagline_notification );
  158. }
  159. }
  160. /**
  161. * Returns whether or not the site has the default tagline.
  162. *
  163. * @return bool
  164. */
  165. public function has_default_tagline() {
  166. $blog_description = get_bloginfo( 'description' );
  167. $default_blog_description = 'Just another WordPress site';
  168. // We are checking against the WordPress internal translation.
  169. // @codingStandardsIgnoreLine
  170. $translated_blog_description = __( 'Just another WordPress site', 'default' );
  171. return $translated_blog_description === $blog_description || $default_blog_description === $blog_description;
  172. }
  173. /**
  174. * Show alert when the permalink doesn't contain %postname%.
  175. */
  176. public function permalink_notice() {
  177. $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' );
  178. $info_message .= '<br/>';
  179. $info_message .= sprintf(
  180. /* 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 */
  181. __( 'You can fix this on the %1$sPermalink settings page%2$s.', 'wordpress-seo' ),
  182. '<a href="' . admin_url( 'options-permalink.php' ) . '">',
  183. '</a>'
  184. );
  185. $notification_options = [
  186. 'type' => Yoast_Notification::WARNING,
  187. 'id' => 'wpseo-dismiss-permalink-notice',
  188. 'capabilities' => 'wpseo_manage_options',
  189. 'priority' => 0.8,
  190. ];
  191. $notification = new Yoast_Notification( $info_message, $notification_options );
  192. $notification_center = Yoast_Notification_Center::get();
  193. if ( ! $this->has_postname_in_permalink() ) {
  194. $notification_center->add_notification( $notification );
  195. }
  196. else {
  197. $notification_center->remove_notification( $notification );
  198. }
  199. }
  200. /**
  201. * Are page comments enabled.
  202. *
  203. * @return bool
  204. */
  205. public function has_page_comments() {
  206. return '1' === get_option( 'page_comments' );
  207. }
  208. /**
  209. * Shows a notice to the user if they have Google Analytics for WordPress 5.4.3 installed because it causes an error
  210. * on the google search console page.
  211. *
  212. * @deprecated 12.5
  213. *
  214. * @codeCoverageIgnore
  215. */
  216. public function ga_compatibility_notice() {
  217. _deprecated_function( __METHOD__, 'WPSEO 12.5' );
  218. }
  219. /**
  220. * Determines whether a suggested plugins notification needs to be displayed.
  221. *
  222. * @return void
  223. */
  224. public function yoast_plugin_suggestions_notification() {
  225. $checker = new WPSEO_Plugin_Availability();
  226. $notification_center = Yoast_Notification_Center::get();
  227. // Get all Yoast plugins that have dependencies.
  228. $plugins = $checker->get_plugins_with_dependencies();
  229. foreach ( $plugins as $plugin_name => $plugin ) {
  230. $dependency_names = $checker->get_dependency_names( $plugin );
  231. $notification = $this->get_yoast_seo_suggested_plugins_notification( $plugin_name, $plugin, $dependency_names[0] );
  232. if ( $checker->dependencies_are_satisfied( $plugin ) && ! $checker->is_installed( $plugin ) ) {
  233. $notification_center->add_notification( $notification );
  234. continue;
  235. }
  236. $notification_center->remove_notification( $notification );
  237. }
  238. }
  239. /**
  240. * Build Yoast SEO suggested plugins notification.
  241. *
  242. * @param string $name The plugin name to use for the unique ID.
  243. * @param array $plugin The plugin to retrieve the data from.
  244. * @param string $dependency_name The name of the dependency.
  245. *
  246. * @return Yoast_Notification The notification containing the suggested plugin.
  247. */
  248. private function get_yoast_seo_suggested_plugins_notification( $name, $plugin, $dependency_name ) {
  249. $info_message = sprintf(
  250. /* translators: %1$s expands to Yoast SEO, %2$s expands to the plugin version, %3$s expands to the plugin name */
  251. __( '%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' ),
  252. 'Yoast SEO',
  253. $dependency_name,
  254. sprintf( '<a href="%s">%s</a>', $plugin['url'], $plugin['title'] )
  255. );
  256. return new Yoast_Notification(
  257. $info_message,
  258. [
  259. 'id' => 'wpseo-suggested-plugin-' . $name,
  260. 'type' => Yoast_Notification::WARNING,
  261. ]
  262. );
  263. }
  264. /**
  265. * Shows the notice for recalculating the post. the Notice will only be shown if the user hasn't dismissed it before.
  266. */
  267. public function recalculate_notice() {
  268. // Just a return, because we want to temporary disable this notice (#3998 and #4532).
  269. return;
  270. if ( filter_input( INPUT_GET, 'recalculate' ) === '1' ) {
  271. update_option( 'wpseo_dismiss_recalculate', '1' );
  272. return;
  273. }
  274. if ( ! WPSEO_Capability_Utils::current_user_can( 'wpseo_manage_options' ) ) {
  275. return;
  276. }
  277. if ( $this->is_site_notice_dismissed( 'wpseo_dismiss_recalculate' ) ) {
  278. return;
  279. }
  280. Yoast_Notification_Center::get()->add_notification(
  281. new Yoast_Notification(
  282. sprintf(
  283. /* translators: 1: is a link to 'admin_url / admin.php?page=wpseo_tools&recalculate=1' 2: closing link tag */
  284. __( 'We\'ve updated our SEO score algorithm. %1$sRecalculate the SEO scores%2$s for all posts and pages.', 'wordpress-seo' ),
  285. '<a href="' . admin_url( 'admin.php?page=wpseo_tools&recalculate=1' ) . '">',
  286. '</a>'
  287. ),
  288. [
  289. 'type' => 'updated yoast-dismissible',
  290. 'id' => 'wpseo-dismiss-recalculate',
  291. 'nonce' => wp_create_nonce( 'wpseo-dismiss-recalculate' ),
  292. ]
  293. )
  294. );
  295. }
  296. /**
  297. * Creates an unsupported PHP version notification in the notification center.
  298. *
  299. * @return void
  300. */
  301. public function unsupported_php_notice() {
  302. $notification_center = Yoast_Notification_Center::get();
  303. $notification_center->remove_notification_by_id( 'wpseo-dismiss-unsupported-php' );
  304. }
  305. /**
  306. * Gets the latest released major WordPress version from the WordPress stable-check api.
  307. *
  308. * @return float The latest released major WordPress version. 0 The stable-check api doesn't respond.
  309. */
  310. private function get_latest_major_wordpress_version() {
  311. $core_updates = get_core_updates( [ 'dismissed' => true ] );
  312. if ( $core_updates === false ) {
  313. return 0;
  314. }
  315. $wp_version_latest = get_bloginfo( 'version' );
  316. foreach ( $core_updates as $update ) {
  317. if ( $update->response === 'upgrade' && version_compare( $update->version, $wp_version_latest, '>' ) ) {
  318. $wp_version_latest = $update->version;
  319. }
  320. }
  321. // Strip the patch version and convert to a float.
  322. return (float) $wp_version_latest;
  323. }
  324. /**
  325. * Check if the user has dismissed the given notice (by $notice_name).
  326. *
  327. * @param string $notice_name The name of the notice that might be dismissed.
  328. *
  329. * @return bool
  330. */
  331. private function is_site_notice_dismissed( $notice_name ) {
  332. return '1' === get_option( $notice_name, true );
  333. }
  334. /**
  335. * Helper to verify if the user is currently visiting one of our admin pages.
  336. *
  337. * @return bool
  338. */
  339. private function on_wpseo_admin_page() {
  340. return 'admin.php' === $this->pagenow && strpos( filter_input( INPUT_GET, 'page' ), 'wpseo' ) === 0;
  341. }
  342. /**
  343. * Determine whether we should load the meta box class and if so, load it.
  344. */
  345. private function load_meta_boxes() {
  346. $is_editor = WPSEO_Metabox::is_post_overview( $this->pagenow ) || WPSEO_Metabox::is_post_edit( $this->pagenow );
  347. $is_inline_save = filter_input( INPUT_POST, 'action' ) === 'inline-save';
  348. /**
  349. * Filter: 'wpseo_always_register_metaboxes_on_admin' - Allow developers to change whether
  350. * the WPSEO metaboxes are only registered on the typical pages (lean loading) or always
  351. * registered when in admin.
  352. *
  353. * @api bool Whether to always register the metaboxes or not. Defaults to false.
  354. */
  355. if ( $is_editor || $is_inline_save || apply_filters( 'wpseo_always_register_metaboxes_on_admin', false )
  356. ) {
  357. $GLOBALS['wpseo_metabox'] = new WPSEO_Metabox();
  358. $GLOBALS['wpseo_meta_columns'] = new WPSEO_Meta_Columns();
  359. }
  360. }
  361. /**
  362. * Determine if we should load our taxonomy edit class and if so, load it.
  363. */
  364. private function load_taxonomy_class() {
  365. if (
  366. WPSEO_Taxonomy::is_term_edit( $this->pagenow )
  367. || WPSEO_Taxonomy::is_term_overview( $this->pagenow )
  368. ) {
  369. new WPSEO_Taxonomy();
  370. }
  371. }
  372. /**
  373. * Determine if we should load our admin pages class and if so, load it.
  374. *
  375. * Loads admin page class for all admin pages starting with `wpseo_`.
  376. */
  377. private function load_admin_user_class() {
  378. if ( in_array( $this->pagenow, [ 'user-edit.php', 'profile.php' ], true )
  379. && current_user_can( 'edit_users' )
  380. ) {
  381. new WPSEO_Admin_User_Profile();
  382. }
  383. }
  384. /**
  385. * Determine if we should load our admin pages class and if so, load it.
  386. *
  387. * Loads admin page class for all admin pages starting with `wpseo_`.
  388. */
  389. private function load_admin_page_class() {
  390. if ( $this->on_wpseo_admin_page() ) {
  391. // For backwards compatabilty, this still needs a global, for now...
  392. $GLOBALS['wpseo_admin_pages'] = new WPSEO_Admin_Pages();
  393. // Only register the yoast i18n when the page is a Yoast SEO page.
  394. if ( WPSEO_Utils::is_yoast_seo_free_page( filter_input( INPUT_GET, 'page' ) ) ) {
  395. $this->register_i18n_promo_class();
  396. $this->register_premium_upsell_admin_block();
  397. }
  398. }
  399. }
  400. /**
  401. * Loads the plugin suggestions.
  402. */
  403. private function load_plugin_suggestions() {
  404. $suggestions = new WPSEO_Suggested_Plugins( new WPSEO_Plugin_Availability(), Yoast_Notification_Center::get() );
  405. $suggestions->register_hooks();
  406. }
  407. /**
  408. * Registers the Premium Upsell Admin Block.
  409. *
  410. * @return void
  411. */
  412. private function register_premium_upsell_admin_block() {
  413. if ( ! WPSEO_Utils::is_yoast_seo_premium() ) {
  414. $upsell_block = new WPSEO_Premium_Upsell_Admin_Block( 'wpseo_admin_promo_footer' );
  415. $upsell_block->register_hooks();
  416. }
  417. }
  418. /**
  419. * Registers the promotion class for our GlotPress instance, then creates a notification with the i18n promo.
  420. *
  421. * @link https://github.com/Yoast/i18n-module
  422. */
  423. private function register_i18n_promo_class() {
  424. // BC, because an older version of the i18n-module didn't have this class.
  425. $i18n_module = new Yoast_I18n_WordPressOrg_v3(
  426. [
  427. 'textdomain' => 'wordpress-seo',
  428. 'plugin_name' => 'Yoast SEO',
  429. 'hook' => 'wpseo_admin_promo_footer',
  430. ],
  431. false
  432. );
  433. $message = $i18n_module->get_promo_message();
  434. if ( $message !== '' ) {
  435. $message .= $i18n_module->get_dismiss_i18n_message_button();
  436. }
  437. $notification_center = Yoast_Notification_Center::get();
  438. $notification = new Yoast_Notification(
  439. $message,
  440. [
  441. 'type' => Yoast_Notification::WARNING,
  442. 'id' => 'i18nModuleTranslationAssistance',
  443. ]
  444. );
  445. if ( $message ) {
  446. $notification_center->add_notification( $notification );
  447. return;
  448. }
  449. $notification_center->remove_notification( $notification );
  450. }
  451. /**
  452. * See if we should start our XML Sitemaps Admin class.
  453. */
  454. private function load_xml_sitemaps_admin() {
  455. if ( WPSEO_Options::get( 'enable_xml_sitemap', false ) ) {
  456. new WPSEO_Sitemaps_Admin();
  457. }
  458. }
  459. /**
  460. * Check if the site is set to be publicly visible.
  461. *
  462. * @return bool
  463. */
  464. private function is_blog_public() {
  465. return '1' === (string) get_option( 'blog_public' );
  466. }
  467. /**
  468. * Shows deprecation warnings to the user if a plugin has registered a filter we have deprecated.
  469. */
  470. public function show_hook_deprecation_warnings() {
  471. global $wp_filter;
  472. if ( wp_doing_ajax() ) {
  473. return;
  474. }
  475. // WordPress hooks that have been deprecated since a Yoast SEO version.
  476. $deprecated_filters = [
  477. 'wpseo_genesis_force_adjacent_rel_home' => [
  478. 'version' => '9.4',
  479. 'alternative' => null,
  480. ],
  481. ];
  482. // Determine which filters have been registered.
  483. $deprecated_notices = array_intersect(
  484. array_keys( $deprecated_filters ),
  485. array_keys( $wp_filter )
  486. );
  487. // Show notice for each deprecated filter or action that has been registered.
  488. foreach ( $deprecated_notices as $deprecated_filter ) {
  489. $deprecation_info = $deprecated_filters[ $deprecated_filter ];
  490. // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped -- only uses the hardcoded values from above.
  491. _deprecated_hook(
  492. $deprecated_filter,
  493. 'WPSEO ' . $deprecation_info['version'],
  494. $deprecation_info['alternative']
  495. );
  496. // phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped.
  497. }
  498. }
  499. /**
  500. * Check if the permalink uses %postname%.
  501. *
  502. * @return bool
  503. */
  504. private function has_postname_in_permalink() {
  505. return ( false !== strpos( get_option( 'permalink_structure' ), '%postname%' ) );
  506. }
  507. /**
  508. * Shows a notice on the permalink settings page.
  509. */
  510. public function permalink_settings_notice() {
  511. global $pagenow;
  512. if ( $pagenow === 'options-permalink.php' ) {
  513. printf(
  514. '<div class="notice notice-warning"><p><strong>%1$s</strong><br>%2$s<br><a href="%3$s" target="_blank">%4$s</a></p></div>',
  515. esc_html__( 'WARNING:', 'wordpress-seo' ),
  516. sprintf(
  517. /* translators: %1$s and %2$s expand to <em> items to emphasize the word in the middle. */
  518. esc_html__( 'Changing your permalinks settings can seriously impact your search engine visibility. It should almost %1$s never %2$s be done on a live website.', 'wordpress-seo' ),
  519. '<em>',
  520. '</em>'
  521. ),
  522. esc_url( WPSEO_Shortlinker::get( 'https://yoa.st/why-permalinks/' ) ),
  523. // The link's content.
  524. esc_html__( 'Learn about why permalinks are important for SEO.', 'wordpress-seo' )
  525. );
  526. }
  527. }
  528. /* ********************* DEPRECATED METHODS ********************* */
  529. /**
  530. * Add an alert if outdated versions of Yoast SEO plugins are running.
  531. *
  532. * @deprecated 12.3
  533. * @codeCoverageIgnore
  534. */
  535. public function yoast_plugin_compatibility_notification() {
  536. _deprecated_function( __METHOD__, 'WPSEO 12.3' );
  537. }
  538. /**
  539. * Creates a WordPress upgrade notification in the notification center.
  540. *
  541. * @deprecated 12.5
  542. * @codeCoverageIgnore
  543. *
  544. * @return void
  545. */
  546. public function wordpress_upgrade_notice() {
  547. _deprecated_function( __METHOD__, 'WPSEO 12.5' );
  548. }
  549. }