Yoast SEO - Version 14.9

Version Description

Release Date: September 1st, 2020

Yoast SEO 14.9 comes with a new round of improvements, plus a new language-based enhancement: improved keyphrase recognition for Hebrew. Read more about those changes in our release post!

Bugfixes:

  • Fixes a bug where a JavaScript console warning was thrown on category edit pages.
  • Fixes a bug where the page number was not shown in the breadcrumb for paginated series.
  • Fixes a bug where the robots.txt and .htaccess file editor would not work due to get_home_path() not being a writable path. Props to druesome.
  • Fixes a bug where port numbers in the indexable permalinks were missing (when applicable).
  • Fixes a bug where the indexables table would contain incorrect permalinks for posts if the term slug had been changed and the post permalink contains the term slug.
  • Fixes a bug where the indexables table would contain incorrect permalinks for pages if the slug of the parent page had been changed.
  • Fixes a bug where a warning would occur when a query was unsuccessful while indexing post type archives. Props to Sekiphp.
  • Fixes a bug where closing parentheses would always be regarded as sentence endings in RTL languages.
  • Fixes a bug where closing parentheses would always be regarded as sentence endings when followed by an upper-case letter.

Enhancements:

  • Adds an update notification for major and minor releases.
  • Improves the SQL performance by not performing unnecessary update queries when updating a posts public status.
  • Optimizes performance by preventing regular database queries.
  • Improves keyphrase recognition in Polish by filtering more function words.
  • Improves the feedback string in the Keyphrase in Subheadings assessment by making it more explicit.
  • Improves all keyphrase-based assessments for Hebrew by filtering function words and allowing keyphrases to be recognized in the text when preceded by a prefix (e.g., or ).
  • We already had a filter available to change the default Schema Article type (wpseo_schema_article_post_types), but it wasn't called anywhere. Now it is.

Other:

  • Adds the weekly cron schedule to the cron_schedules filter to prevent overwriting the one WordPress adds. Props to peter-webbird.
  • Merges the googlebot and bingbot meta tag values into the robots meta tag value and deprecates the Googlebot_Presenter and Bingbot_Presenter.
Download this release

Release Info

Developer Yoast
Plugin Icon 128x128 Yoast SEO
Version 14.9
Comparing to
See all releases

Code changes from version 14.8.1 to 14.9

Files changed (116) hide show
  1. admin/admin-settings-changed-listener.php +1 -1
  2. admin/ajax.php +0 -6
  3. admin/ajax/class-recalculate-scores-ajax.php +0 -123
  4. admin/class-admin-asset-manager.php +30 -24
  5. admin/class-admin-init.php +99 -0
  6. admin/class-admin-media-purge-notification.php +1 -1
  7. admin/class-admin.php +1 -42
  8. admin/class-license-page-manager.php +4 -13
  9. admin/class-meta-columns.php +25 -31
  10. admin/class-meta-storage.php +0 -126
  11. admin/class-meta-table-accessible.php +0 -103
  12. admin/class-recalculate-scores.php +0 -54
  13. admin/class-yoast-notification-center.php +10 -2
  14. admin/links/class-link-cleanup-transient.php +0 -35
  15. admin/links/class-link-column-count.php +0 -93
  16. admin/links/class-link-content-processor.php +0 -143
  17. admin/links/class-link-extractor.php +0 -52
  18. admin/links/class-link-factory.php +0 -94
  19. admin/links/class-link-filter.php +0 -61
  20. admin/links/class-link-installer.php +0 -56
  21. admin/links/class-link-internal-lookup.php +0 -25
  22. admin/links/class-link-notifier.php +0 -125
  23. admin/links/class-link-query.php +0 -160
  24. admin/links/class-link-reindex-dashboard.php +0 -207
  25. admin/links/class-link-reindex-post-endpoint.php +0 -71
  26. admin/links/class-link-reindex-post-service.php +0 -95
  27. admin/links/class-link-storage.php +0 -158
  28. admin/links/class-link-table-accessible.php +0 -103
  29. admin/links/class-link-type-classifier.php +0 -103
  30. admin/links/class-link-utils.php +0 -30
  31. admin/links/class-link-watcher-loader.php +0 -25
  32. admin/links/class-link-watcher.php +0 -149
  33. admin/links/class-link.php +0 -87
  34. admin/metabox/class-metabox.php +3 -1
  35. admin/pages/tools.php +0 -2
  36. admin/recalculate/class-recalculate-posts.php +0 -151
  37. admin/recalculate/class-recalculate-terms.php +0 -151
  38. admin/recalculate/class-recalculate.php +0 -104
  39. admin/ryte/class-ryte.php +9 -11
  40. admin/views/licenses.php +4 -4
  41. admin/views/tabs/metas/paper-content/post_type/woocommerce-shop-page.php +3 -4
  42. admin/views/tool-file-editor.php +10 -4
  43. cli/class-cli-redirect-upsell-command-namespace.php +0 -15
  44. cli/class-cli-yoast-command-namespace.php +0 -15
  45. css/dist/{admin-global-1481-rtl.css → admin-global-1490-rtl.css} +0 -0
  46. css/dist/{admin-global-1481.css → admin-global-1490.css} +0 -0
  47. css/dist/{adminbar-1481-rtl.css → adminbar-1490-rtl.css} +0 -0
  48. css/dist/{adminbar-1481.css → adminbar-1490.css} +0 -0
  49. css/dist/{alerts-1481-rtl.css → alerts-1490-rtl.css} +0 -0
  50. css/dist/{alerts-1481.css → alerts-1490.css} +0 -0
  51. css/dist/{dashboard-1481-rtl.css → dashboard-1490-rtl.css} +0 -0
  52. css/dist/{dashboard-1481.css → dashboard-1490.css} +0 -0
  53. css/dist/{edit-page-1481-rtl.css → edit-page-1490-rtl.css} +0 -0
  54. css/dist/{edit-page-1481.css → edit-page-1490.css} +0 -0
  55. css/dist/{featured-image-1481-rtl.css → featured-image-1490-rtl.css} +0 -0
  56. css/dist/{featured-image-1481.css → featured-image-1490.css} +0 -0
  57. css/dist/{filter-explanation-1481-rtl.css → filter-explanation-1490-rtl.css} +0 -0
  58. css/dist/{filter-explanation-1481.css → filter-explanation-1490.css} +0 -0
  59. css/dist/{icons-1481-rtl.css → icons-1490-rtl.css} +0 -0
  60. css/dist/{icons-1481.css → icons-1490.css} +0 -0
  61. css/dist/{inside-editor-1481-rtl.css → inside-editor-1490-rtl.css} +0 -0
  62. css/dist/{inside-editor-1481.css → inside-editor-1490.css} +0 -0
  63. css/dist/metabox-1481-rtl.css +0 -1
  64. css/dist/metabox-1490-rtl.css +1 -0
  65. css/dist/{metabox-1481.css → metabox-1490.css} +1 -1
  66. css/dist/{metabox-primary-category-1481-rtl.css → metabox-primary-category-1490-rtl.css} +0 -0
  67. css/dist/{metabox-primary-category-1481.css → metabox-primary-category-1490.css} +0 -0
  68. css/dist/modal-1490-rtl.css +1 -0
  69. css/dist/modal-1490.css +1 -0
  70. css/dist/monorepo-1481-rtl.css +0 -1
  71. css/dist/monorepo-1481.css +0 -1
  72. css/dist/monorepo-1490-rtl.css +1 -0
  73. css/dist/monorepo-1490.css +1 -0
  74. css/dist/{notifications-1481-rtl.css → notifications-1490-rtl.css} +0 -0
  75. css/dist/{notifications-1481.css → notifications-1490.css} +0 -0
  76. css/dist/{score_icon-1481-rtl.css → score_icon-1490-rtl.css} +0 -0
  77. css/dist/{score_icon-1481.css → score_icon-1490.css} +0 -0
  78. css/dist/{search-appearance-1481-rtl.css → search-appearance-1490-rtl.css} +0 -0
  79. css/dist/{search-appearance-1481.css → search-appearance-1490.css} +0 -0
  80. css/dist/{structured-data-blocks-1481-rtl.css → structured-data-blocks-1490-rtl.css} +0 -0
  81. css/dist/{structured-data-blocks-1481.css → structured-data-blocks-1490.css} +0 -0
  82. css/dist/{toggle-switch-1481-rtl.css → toggle-switch-1490-rtl.css} +0 -0
  83. css/dist/{toggle-switch-1481.css → toggle-switch-1490.css} +0 -0
  84. css/dist/{wpseo-dismissible-1481-rtl.css → wpseo-dismissible-1490-rtl.css} +0 -0
  85. css/dist/{wpseo-dismissible-1481.css → wpseo-dismissible-1490.css} +0 -0
  86. css/dist/{yoast-components-1481-rtl.css → yoast-components-1490-rtl.css} +0 -0
  87. css/dist/{yoast-components-1481.css → yoast-components-1490.css} +0 -0
  88. css/dist/{yoast-extensions-1481-rtl.css → yoast-extensions-1490-rtl.css} +0 -0
  89. css/dist/{yoast-extensions-1481.css → yoast-extensions-1490.css} +0 -0
  90. css/dist/{yst_plugin_tools-1481-rtl.css → yst_plugin_tools-1490-rtl.css} +0 -0
  91. css/dist/{yst_plugin_tools-1481.css → yst_plugin_tools-1490.css} +0 -0
  92. css/dist/{yst_seo_score-1481-rtl.css → yst_seo_score-1490-rtl.css} +0 -0
  93. css/dist/{yst_seo_score-1481.css → yst_seo_score-1490.css} +0 -0
  94. css/src/metabox.css +1 -0
  95. css/src/modal.css +375 -0
  96. deprecated/admin/ajax/class-recalculate-scores-ajax.php +63 -0
  97. deprecated/admin/class-recalculate-scores.php +47 -0
  98. deprecated/admin/recalculate/class-recalculate-posts.php +71 -0
  99. deprecated/admin/recalculate/class-recalculate-terms.php +71 -0
  100. deprecated/admin/recalculate/class-recalculate.php +64 -0
  101. {frontend → deprecated/frontend}/class-frontend-page-type.php +33 -18
  102. deprecated/frontend/class-woocommerce-shop-page.php +61 -0
  103. frontend/class-woocommerce-shop-page.php +0 -86
  104. frontend/index.php +0 -4
  105. inc/class-post-type.php +3 -22
  106. inc/class-upgrade.php +10 -59
  107. inc/class-wpseo-replace-vars.php +1 -1
  108. inc/class-wpseo-utils.php +4 -33
  109. inc/health-check-links-table-not-accessible.php +3 -10
  110. inc/indexables/class-post-indexable.php +0 -5
  111. inc/options/class-wpseo-option-titles.php +1 -1
  112. inc/options/class-wpseo-option-wpseo.php +6 -5
  113. inc/sitemaps/class-post-type-sitemap-provider.php +20 -14
  114. inc/sitemaps/class-sitemap-image-parser.php +1 -1
  115. js/dist/{admin-global-1481.js → admin-global-1490.js} +1 -1
  116. js/dist/analysis-1481.js +0 -21
admin/admin-settings-changed-listener.php CHANGED
@@ -32,7 +32,7 @@ class WPSEO_Admin_Settings_Changed_Listener implements WPSEO_WordPress_Integrati
32
  public function intercept_save_update_notification() {
33
  global $pagenow;
34
 
35
- if ( $pagenow !== 'admin.php' || ! WPSEO_Utils::is_yoast_seo_page() ) {
36
  return;
37
  }
38
 
32
  public function intercept_save_update_notification() {
33
  global $pagenow;
34
 
35
+ if ( $pagenow !== 'admin.php' || ! YoastSEO()->helpers->current_page->is_yoast_seo_page() ) {
36
  return;
37
  }
38
 
admin/ajax.php CHANGED
@@ -331,16 +331,10 @@ function wpseo_register_ajax_integrations() {
331
 
332
  wpseo_register_ajax_integrations();
333
 
334
- // SEO Score Recalculations.
335
- new WPSEO_Recalculate_Scores_Ajax();
336
-
337
  new WPSEO_Shortcode_Filter();
338
 
339
  new WPSEO_Taxonomy_Columns();
340
 
341
- // Setting the notice for the recalculate the posts.
342
- new Yoast_Dismissable_Notice_Ajax( 'recalculate', Yoast_Dismissable_Notice_Ajax::FOR_SITE );
343
-
344
  /* ********************* DEPRECATED FUNCTIONS ********************* */
345
 
346
  /**
331
 
332
  wpseo_register_ajax_integrations();
333
 
 
 
 
334
  new WPSEO_Shortcode_Filter();
335
 
336
  new WPSEO_Taxonomy_Columns();
337
 
 
 
 
338
  /* ********************* DEPRECATED FUNCTIONS ********************* */
339
 
340
  /**
admin/ajax/class-recalculate-scores-ajax.php DELETED
@@ -1,123 +0,0 @@
1
- <?php
2
- /**
3
- * WPSEO plugin file.
4
- *
5
- * @package WPSEO\Admin\Ajax
6
- */
7
-
8
- /**
9
- * Class WPSEO_Recalculate_Scores.
10
- *
11
- * This class handles the SEO score recalculation for all posts with a filled focus keyword.
12
- */
13
- class WPSEO_Recalculate_Scores_Ajax {
14
-
15
- /**
16
- * Initialize the AJAX hooks.
17
- */
18
- public function __construct() {
19
- add_action( 'wp_ajax_wpseo_recalculate_scores', [ $this, 'recalculate_scores' ] );
20
- add_action( 'wp_ajax_wpseo_update_score', [ $this, 'save_score' ] );
21
- add_action( 'wp_ajax_wpseo_recalculate_total', [ $this, 'get_total' ] );
22
- }
23
-
24
- /**
25
- * Get the totals for the posts and the terms.
26
- */
27
- public function get_total() {
28
- check_ajax_referer( 'wpseo_recalculate', 'nonce' );
29
-
30
- wp_die(
31
- // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Reason: WPSEO_Utils::format_json_encode is considered safe.
32
- WPSEO_Utils::format_json_encode(
33
- [
34
- 'posts' => $this->calculate_posts(),
35
- 'terms' => $this->calculate_terms(),
36
- ]
37
- )
38
- );
39
- }
40
-
41
- /**
42
- * Start recalculation.
43
- */
44
- public function recalculate_scores() {
45
- check_ajax_referer( 'wpseo_recalculate', 'nonce' );
46
-
47
- $fetch_object = $this->get_fetch_object();
48
- if ( ! empty( $fetch_object ) ) {
49
- $paged = filter_input( INPUT_POST, 'paged', FILTER_VALIDATE_INT );
50
- $response = $fetch_object->get_items_to_recalculate( $paged );
51
-
52
- if ( ! empty( $response ) ) {
53
- // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Reason: WPSEO_Utils::format_json_encode is considered safe.
54
- wp_die( WPSEO_Utils::format_json_encode( $response ) );
55
- }
56
- }
57
-
58
- wp_die( '' );
59
- }
60
-
61
- /**
62
- * Saves the new linkdex score for given post.
63
- */
64
- public function save_score() {
65
- check_ajax_referer( 'wpseo_recalculate', 'nonce' );
66
-
67
- $fetch_object = $this->get_fetch_object();
68
- if ( ! empty( $fetch_object ) ) {
69
- $scores = filter_input( INPUT_POST, 'scores', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
70
- $fetch_object->save_scores( $scores );
71
- }
72
-
73
- wp_die();
74
- }
75
-
76
- /**
77
- * Returns the needed object for recalculating scores.
78
- *
79
- * @return WPSEO_Recalculate_Posts|WPSEO_Recalculate_Terms
80
- */
81
- private function get_fetch_object() {
82
- switch ( filter_input( INPUT_POST, 'type' ) ) {
83
- case 'post':
84
- return new WPSEO_Recalculate_Posts();
85
- case 'term':
86
- return new WPSEO_Recalculate_Terms();
87
- }
88
-
89
- return null;
90
- }
91
-
92
- /**
93
- * Gets the total number of posts.
94
- *
95
- * @return int
96
- */
97
- private function calculate_posts() {
98
- $count_posts_query = new WP_Query(
99
- [
100
- 'post_type' => 'any',
101
- 'meta_key' => '_yoast_wpseo_focuskw',
102
- 'posts_per_page' => 1,
103
- 'fields' => 'ids',
104
- ]
105
- );
106
-
107
- return $count_posts_query->found_posts;
108
- }
109
-
110
- /**
111
- * Get the total number of terms.
112
- *
113
- * @return int
114
- */
115
- private function calculate_terms() {
116
- $total = 0;
117
- foreach ( get_taxonomies( [], 'objects' ) as $taxonomy ) {
118
- $total += wp_count_terms( $taxonomy->name, [ 'hide_empty' => false ] );
119
- }
120
-
121
- return $total;
122
- }
123
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/class-admin-asset-manager.php CHANGED
@@ -270,28 +270,48 @@ class WPSEO_Admin_Asset_Manager {
270
  ],
271
  'in_footer' => false,
272
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  [
274
  'name' => 'post-edit',
275
  'src' => 'post-edit-' . $flat_version,
276
  'deps' => [
277
  'jquery',
278
- 'wp-annotations',
279
  'wp-api',
280
  'wp-api-fetch',
281
- 'wp-blocks',
282
- 'wp-components',
283
- 'wp-compose',
284
  'wp-data',
285
- 'wp-element',
286
  'wp-i18n',
287
  'wp-is-shallow-equal',
288
  'wp-sanitize',
289
  'wp-url',
290
  'wp-util',
291
- self::PREFIX . 'redux',
292
  self::PREFIX . 'analysis',
293
- self::PREFIX . 'components',
294
  self::PREFIX . 'commons',
 
295
  self::PREFIX . 'select2',
296
  self::PREFIX . 'select2-translations',
297
  ],
@@ -304,19 +324,16 @@ class WPSEO_Admin_Asset_Manager {
304
  'jquery',
305
  'wp-api',
306
  'wp-api-fetch',
307
- 'wp-components',
308
- 'wp-compose',
309
  'wp-data',
310
- 'wp-element',
311
  'wp-i18n',
312
  'wp-is-shallow-equal',
313
  'wp-sanitize',
314
  'wp-url',
315
  'wp-util',
316
- self::PREFIX . 'redux',
317
  self::PREFIX . 'analysis',
318
- self::PREFIX . 'components',
319
  self::PREFIX . 'commons',
 
320
  self::PREFIX . 'select2',
321
  self::PREFIX . 'select2-translations',
322
  ],
@@ -338,23 +355,12 @@ class WPSEO_Admin_Asset_Manager {
338
  self::PREFIX . 'redux',
339
  self::PREFIX . 'analysis',
340
  self::PREFIX . 'components',
 
341
  self::PREFIX . 'commons',
342
  self::PREFIX . 'select2',
343
  self::PREFIX . 'select2-translations',
344
  ],
345
  ],
346
- [
347
- 'name' => 'recalculate',
348
- 'src' => 'recalculate-' . $flat_version,
349
- 'deps' => [
350
- 'jquery',
351
- 'jquery-ui-core',
352
- 'jquery-ui-progressbar',
353
- self::PREFIX . 'jed',
354
- self::PREFIX . 'analysis',
355
- self::PREFIX . 'commons',
356
- ],
357
- ],
358
  [
359
  'name' => 'select2',
360
  'src' => 'select2/select2.full',
270
  ],
271
  'in_footer' => false,
272
  ],
273
+ [
274
+ 'name' => 'block-editor',
275
+ 'src' => 'block-editor-' . $flat_version,
276
+ 'deps' => [
277
+ 'wp-annotations',
278
+ 'wp-blocks',
279
+ 'wp-components',
280
+ 'wp-compose',
281
+ 'wp-edit-post',
282
+ 'wp-element',
283
+ self::PREFIX . 'components',
284
+ ],
285
+ 'in_footer' => false,
286
+ ],
287
+ [
288
+ 'name' => 'classic-editor',
289
+ 'src' => 'classic-editor-' . $flat_version,
290
+ 'deps' => [
291
+ 'wp-components',
292
+ 'wp-compose',
293
+ 'wp-element',
294
+ self::PREFIX . 'components',
295
+ ],
296
+ 'in_footer' => false,
297
+ ],
298
  [
299
  'name' => 'post-edit',
300
  'src' => 'post-edit-' . $flat_version,
301
  'deps' => [
302
  'jquery',
 
303
  'wp-api',
304
  'wp-api-fetch',
 
 
 
305
  'wp-data',
 
306
  'wp-i18n',
307
  'wp-is-shallow-equal',
308
  'wp-sanitize',
309
  'wp-url',
310
  'wp-util',
 
311
  self::PREFIX . 'analysis',
312
+ self::PREFIX . 'block-editor',
313
  self::PREFIX . 'commons',
314
+ self::PREFIX . 'redux',
315
  self::PREFIX . 'select2',
316
  self::PREFIX . 'select2-translations',
317
  ],
324
  'jquery',
325
  'wp-api',
326
  'wp-api-fetch',
 
 
327
  'wp-data',
 
328
  'wp-i18n',
329
  'wp-is-shallow-equal',
330
  'wp-sanitize',
331
  'wp-url',
332
  'wp-util',
 
333
  self::PREFIX . 'analysis',
334
+ self::PREFIX . 'classic-editor',
335
  self::PREFIX . 'commons',
336
+ self::PREFIX . 'redux',
337
  self::PREFIX . 'select2',
338
  self::PREFIX . 'select2-translations',
339
  ],
355
  self::PREFIX . 'redux',
356
  self::PREFIX . 'analysis',
357
  self::PREFIX . 'components',
358
+ self::PREFIX . 'classic-editor',
359
  self::PREFIX . 'commons',
360
  self::PREFIX . 'select2',
361
  self::PREFIX . 'select2-translations',
362
  ],
363
  ],
 
 
 
 
 
 
 
 
 
 
 
 
364
  [
365
  'name' => 'select2',
366
  'src' => 'select2/select2.full',
admin/class-admin-init.php CHANGED
@@ -36,6 +36,7 @@ class WPSEO_Admin_Init {
36
 
37
  add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_dismissible' ] );
38
  add_action( 'admin_init', [ $this, 'yoast_plugin_suggestions_notification' ], 15 );
 
39
  add_action( 'admin_init', [ $this, 'unsupported_php_notice' ], 15 );
40
  add_action( 'admin_init', [ $this->asset_manager, 'register_assets' ] );
41
  add_action( 'admin_init', [ $this, 'show_hook_deprecation_warnings' ] );
@@ -130,6 +131,104 @@ class WPSEO_Admin_Init {
130
  );
131
  }
132
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  /**
134
  * Creates an unsupported PHP version notification in the notification center.
135
  *
36
 
37
  add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_dismissible' ] );
38
  add_action( 'admin_init', [ $this, 'yoast_plugin_suggestions_notification' ], 15 );
39
+ add_action( 'admin_init', [ $this, 'yoast_plugin_update_notification' ] );
40
  add_action( 'admin_init', [ $this, 'unsupported_php_notice' ], 15 );
41
  add_action( 'admin_init', [ $this->asset_manager, 'register_assets' ] );
42
  add_action( 'admin_init', [ $this, 'show_hook_deprecation_warnings' ] );
131
  );
132
  }
133
 
134
+ /**
135
+ * Determines whether a update notification needs to be displayed.
136
+ *
137
+ * @return void
138
+ */
139
+ public function yoast_plugin_update_notification() {
140
+ $notification_center = Yoast_Notification_Center::get();
141
+ $current_minor_version = $this->get_major_minor_version( WPSEO_Options::get( 'version', WPSEO_VERSION ) );
142
+ $file = plugin_dir_path( WPSEO_FILE ) . 'release-info.json';
143
+
144
+ // Remove if file is not present.
145
+ if ( ! file_exists( $file ) ) {
146
+ $notification_center->remove_notification_by_id( 'wpseo-plugin-updated' );
147
+ return;
148
+ }
149
+
150
+ $release_json = file_get_contents( $file );
151
+ /**
152
+ * Filter: 'wpseo_update_notice_content' - Allow filtering of the content
153
+ * of the update notice read from the release-info.json file.
154
+ *
155
+ * @api object The object from the release-info.json file.
156
+ */
157
+ $release_info = apply_filters( 'wpseo_update_notice_content', json_decode( $release_json ) );
158
+
159
+ // Remove if file is malformed or for a different version.
160
+ if ( is_null( $release_info )
161
+ || empty( $release_info->version )
162
+ || version_compare( $this->get_major_minor_version( $release_info->version ), $current_minor_version, '!=' )
163
+ || empty( $release_info->release_description )
164
+ ) {
165
+ $notification_center->remove_notification_by_id( 'wpseo-plugin-updated' );
166
+ return;
167
+ }
168
+
169
+ $notification = $this->get_yoast_seo_update_notification( $release_info );
170
+
171
+ // Restore notification if it was dismissed in a previous minor version.
172
+ $last_dismissed_version = get_user_option( $notification->get_dismissal_key() );
173
+ if ( ! $last_dismissed_version
174
+ || version_compare( $this->get_major_minor_version( $last_dismissed_version ), $current_minor_version, '<' )
175
+ ) {
176
+ Yoast_Notification_Center::restore_notification( $notification );
177
+ }
178
+ $notification_center->add_notification( $notification );
179
+ }
180
+
181
+ /**
182
+ * Helper to truncate the version string up to the minor number
183
+ *
184
+ * @param string $version The version string to extract the major.minor number from.
185
+ * @return string The version string up to the minor number.
186
+ */
187
+ private function get_major_minor_version( $version ) {
188
+ $version_parts = preg_split( '/[^0-9]+/', $version, 3 );
189
+ return join( '.', array_slice( $version_parts, 0, 2 ) );
190
+ }
191
+
192
+ /**
193
+ * Builds Yoast SEO update notification.
194
+ *
195
+ * @param object $release_info The release information.
196
+ *
197
+ * @return Yoast_Notification The notification for the present version
198
+ */
199
+ private function get_yoast_seo_update_notification( $release_info ) {
200
+ $info_message = '<strong>' .
201
+ sprintf(
202
+ /* translators: %1$s expands to Yoast SEO, %2$s expands to the plugin version. */
203
+ __( 'New in %1$s %2$s: ', 'wordpress-seo' ),
204
+ 'Yoast SEO',
205
+ $release_info->version
206
+ ) .
207
+ '</strong>' .
208
+ $release_info->release_description;
209
+
210
+ if ( ! empty( $release_info->shortlink ) ) {
211
+ $link = esc_url( WPSEO_Shortlinker::get( $release_info->shortlink ) );
212
+ $info_message .= ' <a href="' . esc_url( $link ) . '" target="_blank">' .
213
+ sprintf(
214
+ /* translators: %s expands to the plugin version. */
215
+ __( 'Read all about version %s here', 'wordpress-seo' ),
216
+ $release_info->version
217
+ ) .
218
+ '</a>';
219
+ }
220
+
221
+ return new Yoast_Notification(
222
+ $info_message,
223
+ [
224
+ 'id' => 'wpseo-plugin-updated',
225
+ 'type' => Yoast_Notification::UPDATED,
226
+ 'data_json' => [ 'dismiss_value' => WPSEO_Options::get( 'version', WPSEO_VERSION ) ],
227
+ 'dismissal_key' => 'wpseo-plugin-updated',
228
+ ]
229
+ );
230
+ }
231
+
232
  /**
233
  * Creates an unsupported PHP version notification in the notification center.
234
  *
admin/class-admin-media-purge-notification.php CHANGED
@@ -27,7 +27,7 @@ class WPSEO_Admin_Media_Purge_Notification implements WPSEO_WordPress_Integratio
27
  add_filter( 'wpseo_option_tab-metas_media', [ $this, 'output_hidden_setting' ] );
28
 
29
  // Dismissing is just setting the relevancy to false, which cancels out any functionality.
30
- if ( WPSEO_Utils::is_yoast_seo_page() && filter_input( INPUT_GET, 'dismiss' ) === $this->notification_id ) {
31
  WPSEO_Options::set( 'is-media-purge-relevant', false );
32
  }
33
  }
27
  add_filter( 'wpseo_option_tab-metas_media', [ $this, 'output_hidden_setting' ] );
28
 
29
  // Dismissing is just setting the relevancy to false, which cancels out any functionality.
30
+ if ( YoastSEO()->helpers->current_page->is_yoast_seo_page() && filter_input( INPUT_GET, 'dismiss' ) === $this->notification_id ) {
31
  WPSEO_Options::set( 'is-media-purge-relevant', false );
32
  }
33
  }
admin/class-admin.php CHANGED
@@ -51,10 +51,6 @@ class WPSEO_Admin {
51
  add_filter( 'wpseo_accessible_post_types', [ 'WPSEO_Post_Type', 'filter_attachment_post_type' ] );
52
  }
53
 
54
- if ( filter_input( INPUT_GET, 'page' ) === 'wpseo_tools' && filter_input( INPUT_GET, 'tool' ) === null ) {
55
- new WPSEO_Recalculate_Scores();
56
- }
57
-
58
  add_filter( 'plugin_action_links_' . WPSEO_BASENAME, [ $this, 'add_action_link' ], 10, 2 );
59
 
60
  add_action( 'admin_enqueue_scripts', [ $this, 'config_page_scripts' ] );
@@ -74,7 +70,7 @@ class WPSEO_Admin {
74
  WPSEO_Sitemaps_Cache::register_clear_on_option_update( 'wpseo' );
75
  WPSEO_Sitemaps_Cache::register_clear_on_option_update( 'home' );
76
 
77
- if ( WPSEO_Utils::is_yoast_seo_page() ) {
78
  add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
79
  }
80
 
@@ -117,7 +113,6 @@ class WPSEO_Admin {
117
  $integrations = array_merge(
118
  $integrations,
119
  $this->get_admin_features(),
120
- $this->initialize_seo_links(),
121
  $this->initialize_cornerstone_content()
122
  );
123
 
@@ -369,42 +364,6 @@ class WPSEO_Admin {
369
  ];
370
  }
371
 
372
- /**
373
- * Initializes the seo link watcher.
374
- *
375
- * @returns WPSEO_WordPress_Integration[]
376
- */
377
- protected function initialize_seo_links() {
378
- $integrations = [];
379
-
380
- if ( ! WPSEO_Options::get( 'enable_text_link_counter' ) ) {
381
- return $integrations;
382
- }
383
-
384
- $integrations[] = new WPSEO_Link_Cleanup_Transient();
385
-
386
- if ( ! WPSEO_Link_Table_Accessible::is_accessible() ) {
387
- WPSEO_Link_Table_Accessible::cleanup();
388
- }
389
-
390
- if ( ! WPSEO_Meta_Table_Accessible::is_accessible() ) {
391
- WPSEO_Meta_Table_Accessible::cleanup();
392
- }
393
-
394
- if ( ! WPSEO_Link_Table_Accessible::is_accessible() || ! WPSEO_Meta_Table_Accessible::is_accessible() ) {
395
- return $integrations;
396
- }
397
-
398
- $integrations[] = new WPSEO_Link_Columns( new WPSEO_Meta_Storage() );
399
- $integrations[] = new WPSEO_Link_Reindex_Dashboard();
400
- $integrations[] = new WPSEO_Link_Notifier();
401
-
402
- // Adds a filter to exclude the attachments from the link count.
403
- add_filter( 'wpseo_link_count_post_types', [ 'WPSEO_Post_Type', 'filter_attachment_post_type' ] );
404
-
405
- return $integrations;
406
- }
407
-
408
  /**
409
  * Retrieves an instance of the HelpScout beacon class for Yoast SEO.
410
  *
51
  add_filter( 'wpseo_accessible_post_types', [ 'WPSEO_Post_Type', 'filter_attachment_post_type' ] );
52
  }
53
 
 
 
 
 
54
  add_filter( 'plugin_action_links_' . WPSEO_BASENAME, [ $this, 'add_action_link' ], 10, 2 );
55
 
56
  add_action( 'admin_enqueue_scripts', [ $this, 'config_page_scripts' ] );
70
  WPSEO_Sitemaps_Cache::register_clear_on_option_update( 'wpseo' );
71
  WPSEO_Sitemaps_Cache::register_clear_on_option_update( 'home' );
72
 
73
+ if ( YoastSEO()->helpers->current_page->is_yoast_seo_page() ) {
74
  add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
75
  }
76
 
113
  $integrations = array_merge(
114
  $integrations,
115
  $this->get_admin_features(),
 
116
  $this->initialize_cornerstone_content()
117
  );
118
 
364
  ];
365
  }
366
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
  /**
368
  * Retrieves an instance of the HelpScout beacon class for Yoast SEO.
369
  *
admin/class-license-page-manager.php CHANGED
@@ -10,13 +10,6 @@
10
  */
11
  class WPSEO_License_Page_Manager implements WPSEO_WordPress_Integration {
12
 
13
- /**
14
- * Version number for License Page Manager.
15
- *
16
- * @var string
17
- */
18
- const VERSION_LEGACY = '1';
19
-
20
  /**
21
  * Version number for License Page Manager.
22
  *
@@ -124,7 +117,7 @@ class WPSEO_License_Page_Manager implements WPSEO_WordPress_Integration {
124
  * @return int The version number
125
  */
126
  protected function get_version() {
127
- return get_option( $this->get_option_name(), self::VERSION_BACKWARDS_COMPATIBILITY );
128
  }
129
 
130
  /**
@@ -133,7 +126,7 @@ class WPSEO_License_Page_Manager implements WPSEO_WordPress_Integration {
133
  * @return string The option name.
134
  */
135
  protected function get_option_name() {
136
- return 'wpseo_license_server_version';
137
  }
138
 
139
  /**
@@ -153,7 +146,7 @@ class WPSEO_License_Page_Manager implements WPSEO_WordPress_Integration {
153
  * @param string $server_version The version number to save.
154
  */
155
  protected function set_version( $server_version ) {
156
- update_option( $this->get_option_name(), $server_version );
157
  }
158
 
159
  /**
@@ -200,7 +193,7 @@ class WPSEO_License_Page_Manager implements WPSEO_WordPress_Integration {
200
  'capabilities' => 'wpseo_manage_options',
201
  ];
202
 
203
- $notification = new Yoast_Notification(
204
  sprintf(
205
  /* translators: %1$s expands to the product name. %2$s expands to a link to My Yoast */
206
  __( 'You are not receiving updates or support! Fix this problem by adding this site and enabling %1$s for it in %2$s.', 'wordpress-seo' ),
@@ -209,7 +202,5 @@ class WPSEO_License_Page_Manager implements WPSEO_WordPress_Integration {
209
  ),
210
  $notification_options
211
  );
212
-
213
- return $notification;
214
  }
215
  }
10
  */
11
  class WPSEO_License_Page_Manager implements WPSEO_WordPress_Integration {
12
 
 
 
 
 
 
 
 
13
  /**
14
  * Version number for License Page Manager.
15
  *
117
  * @return int The version number
118
  */
119
  protected function get_version() {
120
+ return WPSEO_Options::get( $this->get_option_name(), self::VERSION_BACKWARDS_COMPATIBILITY );
121
  }
122
 
123
  /**
126
  * @return string The option name.
127
  */
128
  protected function get_option_name() {
129
+ return 'license_server_version';
130
  }
131
 
132
  /**
146
  * @param string $server_version The version number to save.
147
  */
148
  protected function set_version( $server_version ) {
149
+ WPSEO_Options::set( $this->get_option_name(), $server_version );
150
  }
151
 
152
  /**
193
  'capabilities' => 'wpseo_manage_options',
194
  ];
195
 
196
+ return new Yoast_Notification(
197
  sprintf(
198
  /* translators: %1$s expands to the product name. %2$s expands to a link to My Yoast */
199
  __( 'You are not receiving updates or support! Fix this problem by adding this site and enabling %1$s for it in %2$s.', 'wordpress-seo' ),
202
  ),
203
  $notification_options
204
  );
 
 
205
  }
206
  }
admin/class-meta-columns.php CHANGED
@@ -6,6 +6,8 @@
6
  */
7
 
8
  use Yoast\WP\SEO\Context\Meta_Tags_Context;
 
 
9
 
10
  /**
11
  * Class WPSEO_Meta_Columns.
@@ -33,6 +35,13 @@ class WPSEO_Meta_Columns {
33
  */
34
  private $analysis_readability;
35
 
 
 
 
 
 
 
 
36
  /**
37
  * When page analysis is enabled, just initialize the hooks.
38
  */
@@ -43,6 +52,7 @@ class WPSEO_Meta_Columns {
43
 
44
  $this->analysis_seo = new WPSEO_Metabox_Analysis_SEO();
45
  $this->analysis_readability = new WPSEO_Metabox_Analysis_Readability();
 
46
  }
47
 
48
  /**
@@ -60,35 +70,6 @@ class WPSEO_Meta_Columns {
60
  }
61
 
62
  add_filter( 'request', [ $this, 'column_sort_orderby' ] );
63
-
64
- // Hook into tablenav to get the indexable context, at this point we can get the post ids.
65
- add_action( 'manage_posts_extra_tablenav', [ $this, 'get_post_ids_and_set_context' ] );
66
- }
67
-
68
- /**
69
- * Retrieves the post ids and sets the context objects for all the indexables belonging
70
- * to the post ids.
71
- *
72
- * @param string $target Extra table navigation location which is triggered.
73
- */
74
- public function get_post_ids_and_set_context( $target ) {
75
- if ( $target !== 'top' ) {
76
- return;
77
- }
78
-
79
- global $wp_query;
80
-
81
- $posts = empty( $wp_query->posts ) ? $wp_query->get_posts() : $wp_query->posts;
82
- $post_ids = [];
83
-
84
- // Post lists return a list of objects.
85
- if ( isset( $posts[0] ) && is_object( $posts[0] ) ) {
86
- $post_ids = wp_list_pluck( $posts, 'ID' );
87
- }
88
- elseif ( ! empty( $posts ) ) {
89
- // Page list returns an array of post IDs.
90
- $post_ids = array_keys( $posts );
91
- }
92
  }
93
 
94
  /**
@@ -146,11 +127,11 @@ class WPSEO_Meta_Columns {
146
  return;
147
 
148
  case 'wpseo-title':
149
- echo esc_html( YoastSEO()->meta->for_post( $post_id )->title );
150
  return;
151
 
152
  case 'wpseo-metadesc':
153
- $metadesc_val = YoastSEO()->meta->for_post( $post_id )->meta_description;
154
 
155
  if ( $metadesc_val === '' ) {
156
  echo '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">',
@@ -290,6 +271,19 @@ class WPSEO_Meta_Columns {
290
  return '<option ' . $selected . ' value="' . esc_attr( $value ) . '">' . esc_html( $label ) . '</option>';
291
  }
292
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  /**
294
  * Determines the SEO score filter to be later used in the meta query, based on the passed SEO filter.
295
  *
6
  */
7
 
8
  use Yoast\WP\SEO\Context\Meta_Tags_Context;
9
+ use Yoast\WP\SEO\Integrations\Admin\Admin_Columns_Cache_Integration;
10
+ use Yoast\WP\SEO\Surfaces\Values\Meta;
11
 
12
  /**
13
  * Class WPSEO_Meta_Columns.
35
  */
36
  private $analysis_readability;
37
 
38
+ /**
39
+ * Admin columns cache.
40
+ *
41
+ * @var Admin_Columns_Cache_Integration
42
+ */
43
+ private $admin_columns_cache;
44
+
45
  /**
46
  * When page analysis is enabled, just initialize the hooks.
47
  */
52
 
53
  $this->analysis_seo = new WPSEO_Metabox_Analysis_SEO();
54
  $this->analysis_readability = new WPSEO_Metabox_Analysis_Readability();
55
+ $this->admin_columns_cache = YoastSEO()->classes->get( Admin_Columns_Cache_Integration::class );
56
  }
57
 
58
  /**
70
  }
71
 
72
  add_filter( 'request', [ $this, 'column_sort_orderby' ] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  }
74
 
75
  /**
127
  return;
128
 
129
  case 'wpseo-title':
130
+ echo esc_html( $this->get_meta( $post_id )->title );
131
  return;
132
 
133
  case 'wpseo-metadesc':
134
+ $metadesc_val = $this->get_meta( $post_id )->meta_description;
135
 
136
  if ( $metadesc_val === '' ) {
137
  echo '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">',
271
  return '<option ' . $selected . ' value="' . esc_attr( $value ) . '">' . esc_html( $label ) . '</option>';
272
  }
273
 
274
+ /**
275
+ * Returns the meta object for a given post ID.
276
+ *
277
+ * @param int $post_id The post ID.
278
+ *
279
+ * @return Meta The meta object.
280
+ */
281
+ protected function get_meta( $post_id ) {
282
+ $indexable = $this->admin_columns_cache->get_indexable( $post_id );
283
+
284
+ return YoastSEO()->meta->for_indexable( $indexable, 'Post_Type' );
285
+ }
286
+
287
  /**
288
  * Determines the SEO score filter to be later used in the meta query, based on the passed SEO filter.
289
  *
admin/class-meta-storage.php DELETED
@@ -1,126 +0,0 @@
1
- <?php
2
- /**
3
- * WPSEO plugin file.
4
- *
5
- * @package WPSEO\Admin\Links
6
- */
7
-
8
- /**
9
- * Represents the link count storage.
10
- */
11
- class WPSEO_Meta_Storage implements WPSEO_Installable {
12
-
13
- /**
14
- * Table name for the meta storage.
15
- *
16
- * @var string
17
- */
18
- const TABLE_NAME = 'yoast_seo_meta';
19
-
20
- /**
21
- * Holds the database's proxy.
22
- *
23
- * @var WPSEO_Database_Proxy
24
- */
25
- protected $database_proxy;
26
-
27
- /**
28
- * Holds the prefix of the table.
29
- *
30
- * @deprecated 7.4
31
- *
32
- * @var null|string
33
- */
34
- protected $table_prefix;
35
-
36
- /**
37
- * Initializes the database table.
38
- *
39
- * @param string $table_prefix Optional. Deprecated argument.
40
- */
41
- public function __construct( $table_prefix = null ) {
42
- if ( $table_prefix !== null ) {
43
- _deprecated_argument( __METHOD__, 'WPSEO 7.4' );
44
- }
45
-
46
- $this->database_proxy = new WPSEO_Database_Proxy( $GLOBALS['wpdb'], self::TABLE_NAME, true );
47
- }
48
-
49
- /**
50
- * Returns the table name to use.
51
- *
52
- * @return string The table name.
53
- */
54
- public function get_table_name() {
55
- return $this->database_proxy->get_table_name();
56
- }
57
-
58
- /**
59
- * Creates the database table.
60
- *
61
- * @return boolean True if the table was created, false if something went wrong.
62
- */
63
- public function install() {
64
- return $this->database_proxy->create_table(
65
- [
66
- 'object_id bigint(20) UNSIGNED NOT NULL',
67
- 'internal_link_count int(10) UNSIGNED NULL DEFAULT NULL',
68
- 'incoming_link_count int(10) UNSIGNED NULL DEFAULT NULL',
69
- ],
70
- [
71
- 'UNIQUE KEY object_id (object_id)',
72
- ]
73
- );
74
- }
75
-
76
- /**
77
- * Saves the link count to the database.
78
- *
79
- * @param int $meta_id The id to save the link count for.
80
- * @param array $meta_data The total amount of links.
81
- */
82
- public function save_meta_data( $meta_id, array $meta_data ) {
83
- $where = [ 'object_id' => $meta_id ];
84
-
85
- $saved = $this->database_proxy->upsert(
86
- array_merge( $where, $meta_data ),
87
- $where
88
- );
89
-
90
- if ( $saved === false ) {
91
- WPSEO_Meta_Table_Accessible::set_inaccessible();
92
- }
93
- }
94
-
95
- /**
96
- * Updates the incoming link count.
97
- *
98
- * @param array $post_ids The posts to update the incoming link count for.
99
- * @param WPSEO_Link_Storage $storage The link storage object.
100
- */
101
- public function update_incoming_link_count( array $post_ids, WPSEO_Link_Storage $storage ) {
102
- global $wpdb;
103
-
104
- $query = $wpdb->prepare(
105
- '
106
- SELECT COUNT( id ) AS incoming, target_post_id AS post_id
107
- FROM ' . $storage->get_table_name() . '
108
- WHERE target_post_id IN(' . implode( ',', array_fill( 0, count( $post_ids ), '%d' ) ) . ')
109
- GROUP BY target_post_id',
110
- $post_ids
111
- );
112
-
113
- $results = $wpdb->get_results( $query );
114
-
115
- $post_ids_non_zero = [];
116
- foreach ( $results as $result ) {
117
- $this->save_meta_data( $result->post_id, [ 'incoming_link_count' => $result->incoming ] );
118
- $post_ids_non_zero[] = $result->post_id;
119
- }
120
-
121
- $post_ids_zero = array_diff( $post_ids, $post_ids_non_zero );
122
- foreach ( $post_ids_zero as $post_id ) {
123
- $this->save_meta_data( $post_id, [ 'incoming_link_count' => 0 ] );
124
- }
125
- }
126
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/class-meta-table-accessible.php DELETED
@@ -1,103 +0,0 @@
1
- <?php
2
- /**
3
- * WPSEO plugin file.
4
- *
5
- * @package WPSEO\Admin\Links
6
- */
7
-
8
- /**
9
- * Represents the state of the table being accessible.
10
- */
11
- class WPSEO_Meta_Table_Accessible {
12
-
13
- /**
14
- * Indicates that the table is accessible.
15
- *
16
- * @var string
17
- */
18
- const ACCESSIBLE = '0';
19
-
20
- /**
21
- * Indicates that the table is inaccessible.
22
- *
23
- * @var string
24
- */
25
- const INACCESSBILE = '1';
26
-
27
- /**
28
- * Checks if the given table name exists.
29
- *
30
- * @return bool True when table is accessible.
31
- */
32
- public static function is_accessible() {
33
- $value = get_transient( self::transient_name() );
34
-
35
- // If the value is not set, check the table.
36
- if ( $value === false ) {
37
- return self::check_table();
38
- }
39
-
40
- return $value === self::ACCESSIBLE;
41
- }
42
-
43
- /**
44
- * Sets the transient value to 1, to indicate the table is not accessible.
45
- *
46
- * @return void
47
- */
48
- public static function set_inaccessible() {
49
- set_transient( self::transient_name(), self::INACCESSBILE, HOUR_IN_SECONDS );
50
- }
51
-
52
- /**
53
- * Removes the transient.
54
- *
55
- * @return void
56
- */
57
- public static function cleanup() {
58
- delete_transient( self::transient_name() );
59
- }
60
-
61
- /**
62
- * Sets the transient value to 0, to indicate the table is accessible.
63
- *
64
- * @return void
65
- */
66
- protected static function set_accessible() {
67
- /*
68
- * Prefer to set a 0 timeout, but if the timeout was set before WordPress will not delete the transient
69
- * correctly when overridden with a zero value.
70
- *
71
- * Setting a YEAR_IN_SECONDS instead.
72
- */
73
- set_transient( self::transient_name(), self::ACCESSIBLE, YEAR_IN_SECONDS );
74
- }
75
-
76
- /**
77
- * Checks if the table exists if not, set the transient to indicate the inaccessible table.
78
- *
79
- * @return bool True if table is accessible.
80
- */
81
- protected static function check_table() {
82
- global $wpdb;
83
-
84
- $storage = new WPSEO_Meta_Storage();
85
- $query = $wpdb->prepare( 'SHOW TABLES LIKE %s', $storage->get_table_name() );
86
- if ( $wpdb->get_var( $query ) !== $storage->get_table_name() ) {
87
- self::set_inaccessible();
88
- return false;
89
- }
90
-
91
- self::set_accessible();
92
- return true;
93
- }
94
-
95
- /**
96
- * Returns the name of the transient.
97
- *
98
- * @return string The name of the transient to use.
99
- */
100
- protected static function transient_name() {
101
- return 'wpseo_meta_table_inaccessible';
102
- }
103
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/class-recalculate-scores.php DELETED
@@ -1,54 +0,0 @@
1
- <?php
2
- /**
3
- * WPSEO plugin file.
4
- *
5
- * @package WPSEO\Admin
6
- */
7
-
8
- /**
9
- * Class WPSEO_Recalculate_Scores.
10
- *
11
- * This class handles the SEO score recalculation for all posts with a filled focus keyword.
12
- */
13
- class WPSEO_Recalculate_Scores {
14
-
15
- /**
16
- * Constructing the object by modalbox, the localization and the totals.
17
- */
18
- public function __construct() {
19
- add_action( 'admin_enqueue_scripts', [ $this, 'recalculate_assets' ] );
20
- add_action( 'admin_footer', [ $this, 'modal_box' ], 20 );
21
- }
22
-
23
- /**
24
- * Run the localize script.
25
- */
26
- public function recalculate_assets() {
27
- $asset_manager = new WPSEO_Admin_Asset_Manager();
28
- $asset_manager->enqueue_script( 'recalculate' );
29
- }
30
-
31
- /**
32
- * Initialize the modal box to be displayed when needed.
33
- */
34
- public function modal_box() {
35
- // Adding the thickbox.
36
- add_thickbox();
37
-
38
- $progress = sprintf(
39
- /* translators: 1: expands to a <span> containing the number of posts recalculated. 2: expands to a <strong> containing the total number of posts. */
40
- esc_html__( '%1$s of %2$s done.', 'wordpress-seo' ),
41
- '<span id="wpseo_count">0</span>',
42
- '<strong id="wpseo_count_total">0</strong>'
43
- );
44
-
45
- ?>
46
- <div id="wpseo_recalculate" class="hidden">
47
- <p><?php esc_html_e( 'Recalculating SEO scores for all pieces of content with a focus keyphrase.', 'wordpress-seo' ); ?></p>
48
-
49
- <div id="wpseo_progressbar"></div>
50
- <p><?php echo $progress; ?></p>
51
- </div>
52
- <?php
53
- }
54
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/class-yoast-notification-center.php CHANGED
@@ -164,8 +164,9 @@ class Yoast_Notification_Center {
164
  return true;
165
  }
166
 
167
- $dismissal_key = $notification->get_dismissal_key();
168
- $notification_id = $notification->get_id();
 
169
 
170
  $is_dismissing = ( $dismissal_key === self::get_user_input( 'notification' ) );
171
  if ( ! $is_dismissing ) {
@@ -186,6 +187,13 @@ class Yoast_Notification_Center {
186
  return false;
187
  }
188
 
 
 
 
 
 
 
 
189
  return self::dismiss_notification( $notification, $meta_value );
190
  }
191
 
164
  return true;
165
  }
166
 
167
+ $dismissal_key = $notification->get_dismissal_key();
168
+ $notification_id = $notification->get_id();
169
+ $notification_json = $notification->get_json();
170
 
171
  $is_dismissing = ( $dismissal_key === self::get_user_input( 'notification' ) );
172
  if ( ! $is_dismissing ) {
187
  return false;
188
  }
189
 
190
+ if ( ! empty( $notification_json ) ) {
191
+ $notification_data = json_decode( $notification_json );
192
+ if ( ! is_null( $notification_data ) && isset( $notification_data->dismiss_value ) ) {
193
+ $meta_value = $notification_data->dismiss_value;
194
+ }
195
+ }
196
+
197
  return self::dismiss_notification( $notification, $meta_value );
198
  }
199
 
admin/links/class-link-cleanup-transient.php DELETED
@@ -1,35 +0,0 @@
1
- <?php
2
- /**
3
- * WPSEO plugin file.
4
- *
5
- * @package WPSEO\Admin\Links
6
- */
7
-
8
- /**
9
- * Represents the cleanup logic when the text link counter features has been disabled.
10
- */
11
- class WPSEO_Link_Cleanup_Transient implements WPSEO_WordPress_Integration {
12
-
13
- /**
14
- * Registers the hooks.
15
- */
16
- public function register_hooks() {
17
- add_action( 'update_option_wpseo', [ $this, 'remove_transients_on_updated_option' ], 10, 2 );
18
- }
19
-
20
- /**
21
- * Removes the transient when the option is updated.
22
- *
23
- * @param mixed $old_value The old value.
24
- * @param mixed $value The new value.
25
- *
26
- * @return void
27
- */
28
- public function remove_transients_on_updated_option( $old_value, $value ) {
29
- $option_name = 'enable_text_link_counter';
30
- if ( $value[ $option_name ] === false && $old_value[ $option_name ] !== $value[ $option_name ] ) {
31
- WPSEO_Link_Table_Accessible::cleanup();
32
- WPSEO_Meta_Table_Accessible::cleanup();
33
- }
34
- }
35
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/links/class-link-column-count.php DELETED
@@ -1,93 +0,0 @@
1
- <?php
2
- /**
3
- * WPSEO plugin file.
4
- *
5
- * @package WPSEO\Admin\Links
6
- */
7
-
8
- /**
9
- * Represents the link column count. This class contains the count for each post id on the current page.
10
- */
11
- class WPSEO_Link_Column_Count {
12
-
13
- /**
14
- * The link counts for each post id on the current page.
15
- *
16
- * @var array
17
- */
18
- protected $count = [];
19
-
20
- /**
21
- * Sets the counts for the set target field.
22
- *
23
- * @param array $post_ids The posts to get the count for.
24
- */
25
- public function set( $post_ids ) {
26
- if ( empty( $post_ids ) ) {
27
- return;
28
- }
29
-
30
- $this->count = $this->get_results( $post_ids );
31
- }
32
-
33
- /**
34
- * Gets the link count for given post id.
35
- *
36
- * @param int $post_id The post id.
37
- * @param string $target_field The field to show.
38
- *
39
- * @return int|null The total amount of links or null if the target field
40
- * does not exist for the given post id.
41
- */
42
- public function get( $post_id, $target_field = 'internal_link_count' ) {
43
- if ( array_key_exists( $post_id, $this->count ) && array_key_exists( $target_field, $this->count[ $post_id ] ) ) {
44
- return $this->count[ $post_id ][ $target_field ];
45
- }
46
-
47
- return null;
48
- }
49
-
50
- /**
51
- * Gets the link count for the given post ids.
52
- *
53
- * @param array $post_ids Array with post_ids.
54
- *
55
- * @return array
56
- */
57
- protected function get_results( $post_ids ) {
58
- global $wpdb;
59
-
60
- $storage = new WPSEO_Meta_Storage();
61
-
62
- $results = $wpdb->get_results(
63
- $wpdb->prepare(
64
- '
65
- SELECT internal_link_count, incoming_link_count, object_id
66
- FROM ' . $storage->get_table_name() . '
67
- WHERE object_id IN (' . implode( ',', array_fill( 0, count( $post_ids ), '%d' ) ) . ')',
68
- $post_ids
69
- ),
70
- ARRAY_A
71
- );
72
-
73
- $output = [];
74
- foreach ( $results as $result ) {
75
- $output[ (int) $result['object_id'] ] = [
76
- 'internal_link_count' => $result['internal_link_count'],
77
- 'incoming_link_count' => (int) $result['incoming_link_count'],
78
- ];
79
- }
80
-
81
- // Set unfound items to zero.
82
- foreach ( $post_ids as $post_id ) {
83
- if ( ! array_key_exists( $post_id, $output ) ) {
84
- $output[ $post_id ] = [
85
- 'internal_link_count' => null,
86
- 'incoming_link_count' => 0,
87
- ];
88
- }
89
- }
90
-
91
- return $output;
92
- }
93
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/links/class-link-content-processor.php DELETED
@@ -1,143 +0,0 @@
1
- <?php
2
- /**
3
- * WPSEO plugin file.
4
- *
5
- * @package WPSEO\Admin\Links
6
- */
7
-
8
- /**
9
- * Represents the content processor. It will extract links from the content and
10
- * saves them for the given post id.
11
- */
12
- class WPSEO_Link_Content_Processor {
13
-
14
- /**
15
- * Holds the link storage instance.
16
- *
17
- * @var WPSEO_Link_Storage
18
- */
19
- protected $storage;
20
-
21
- /**
22
- * Holds the meta storage instance.
23
- *
24
- * @var WPSEO_Meta_Storage
25
- */
26
- private $count_storage;
27
-
28
- /**
29
- * Sets an instance of a storage object.
30
- *
31
- * @param WPSEO_Link_Storage $storage The storage object to use.
32
- * @param WPSEO_Meta_Storage $count_storage The storage object for the link
33
- * counts.
34
- */
35
- public function __construct( WPSEO_Link_Storage $storage, WPSEO_Meta_Storage $count_storage ) {
36
- $this->storage = $storage;
37
- $this->count_storage = $count_storage;
38
- }
39
-
40
- /**
41
- * Process the content for the given post id.
42
- *
43
- * @param int $post_id The post id.
44
- * @param string $content The content to process.
45
- */
46
- public function process( $post_id, $content ) {
47
- $link_extractor = new WPSEO_Link_Extractor( $content );
48
- $link_processor = new WPSEO_Link_Factory(
49
- new WPSEO_Link_Type_Classifier( home_url() ),
50
- new WPSEO_Link_Internal_Lookup(),
51
- new WPSEO_Link_Filter( get_permalink( $post_id ) )
52
- );
53
-
54
- $extracted_links = $link_extractor->extract();
55
- $links = $link_processor->build( $extracted_links );
56
-
57
- $internal_links = array_filter( $links, [ $this, 'filter_internal_link' ] );
58
-
59
- $stored_links = $this->get_stored_internal_links( $post_id );
60
-
61
- $this->storage->cleanup( $post_id );
62
- $this->storage->save_links( $post_id, $links );
63
-
64
- $this->update_link_counts( $post_id, count( $internal_links ), array_merge( $stored_links, $internal_links ) );
65
- }
66
-
67
- /**
68
- * Updates the link counts for the post and referenced posts.
69
- *
70
- * @param int $post_id Post to update link counts for.
71
- * @param int|null $count Number of internal links.
72
- * @param array $links Links to process for incoming link count update.
73
- */
74
- public function update_link_counts( $post_id, $count, array $links ) {
75
- $this->store_internal_link_count( $post_id, $count );
76
- $this->update_incoming_links( $post_id, $links );
77
- }
78
-
79
- /**
80
- * Retrieves the stored internal links for the supplied post.
81
- *
82
- * @param int $post_id The post to fetch links for.
83
- *
84
- * @return WPSEO_Link[] List of internal links connected to the post.
85
- */
86
- public function get_stored_internal_links( $post_id ) {
87
- $links = $this->storage->get_links( $post_id );
88
- return array_filter( $links, [ $this, 'filter_internal_link' ] );
89
- }
90
-
91
- /**
92
- * Filters on INTERNAL links.
93
- *
94
- * @param WPSEO_Link $link Link to test type of.
95
- *
96
- * @return bool True for internal link, false for external link.
97
- */
98
- protected function filter_internal_link( WPSEO_Link $link ) {
99
- return $link->get_type() === WPSEO_Link::TYPE_INTERNAL;
100
- }
101
-
102
- /**
103
- * Stores the total links for the post.
104
- *
105
- * @param int $post_id The post id.
106
- * @param int $internal_link_count Total amount of links in the post.
107
- *
108
- * @return void
109
- */
110
- protected function store_internal_link_count( $post_id, $internal_link_count ) {
111
- $this->count_storage->save_meta_data( $post_id, [ 'internal_link_count' => $internal_link_count ] );
112
- }
113
-
114
- /**
115
- * Updates the incoming link count.
116
- *
117
- * @param int $post_id Post which is processed, this needs to be recalculated too.
118
- * @param WPSEO_Link[] $links Links to update the incoming link count of.
119
- *
120
- * @return void
121
- */
122
- protected function update_incoming_links( $post_id, $links ) {
123
- $post_ids = $this->get_internal_post_ids( $links );
124
- $post_ids = array_merge( [ $post_id ], $post_ids );
125
- $this->count_storage->update_incoming_link_count( $post_ids, $this->storage );
126
- }
127
-
128
- /**
129
- * Extract the post IDs from the links.
130
- *
131
- * @param WPSEO_Link[] $links Links to update the incoming link count of.
132
- *
133
- * @return int[] List of post IDs.
134
- */
135
- protected function get_internal_post_ids( $links ) {
136
- $post_ids = [];
137
- foreach ( $links as $link ) {
138
- $post_ids[] = $link->get_target_post_id();
139
- }
140
-
141
- return array_filter( $post_ids );
142
- }
143
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/links/class-link-extractor.php DELETED
@@ -1,52 +0,0 @@
1
- <?php
2
- /**
3
- * WPSEO plugin file.
4
- *
5
- * @package WPSEO\Admin\Links
6
- */
7
-
8
- /**
9
- * Represents the link extractor.
10
- */
11
- class WPSEO_Link_Extractor {
12
-
13
- /**
14
- * The content to extract the links from.
15
- *
16
- * @var string
17
- */
18
- protected $content;
19
-
20
- /**
21
- * Sets the content.
22
- *
23
- * @param string $content The content to extract the links from.
24
- */
25
- public function __construct( $content ) {
26
- $this->content = $content;
27
- }
28
-
29
- /**
30
- * Extracts the hrefs from the content and returns them as an array.
31
- *
32
- * @return array All the extracted links
33
- */
34
- public function extract() {
35
- $links = [];
36
-
37
- if ( strpos( $this->content, 'href' ) === false ) {
38
- return $links;
39
- }
40
-
41
- $regexp = '<a\s[^>]*href=("??)([^" >]*?)\\1[^>]*>';
42
-
43
- // Used modifiers iU to match case insensitive and make greedy quantifiers lazy.
44
- if ( preg_match_all( "/$regexp/iU", $this->content, $matches, PREG_SET_ORDER ) ) {
45
- foreach ( $matches as $match ) {
46
- $links[] = trim( $match[2], "'" );
47
- }
48
- }
49
-
50
- return $links;
51
- }
52
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/links/class-link-factory.php DELETED
@@ -1,94 +0,0 @@
1
- <?php
2
- /**
3
- * WPSEO plugin file.
4
- *
5
- * @package WPSEO\Admin\Links
6
- */
7
-
8
- /**
9
- * Represents the conversion from array with string links into WPSEO_Link objects.
10
- */
11
- class WPSEO_Link_Factory {
12
-
13
- /**
14
- * Represents the classifier for a link. Determines of a link is an outbound or internal one.
15
- *
16
- * @var WPSEO_Link_Type_Classifier
17
- */
18
- protected $classifier;
19
-
20
- /**
21
- * Represents the internal link lookup. This class tries get the postid for a given internal link.
22
- *
23
- * @var WPSEO_Link_Internal_Lookup
24
- */
25
- protected $internal_lookup;
26
-
27
- /**
28
- * Represents the filter for filtering links.
29
- *
30
- * @var WPSEO_Link_Filter
31
- */
32
- protected $filter;
33
-
34
- /**
35
- * Sets the dependencies for this object.
36
- *
37
- * @param WPSEO_Link_Type_Classifier $classifier The classifier to use.
38
- * @param WPSEO_Link_Internal_Lookup $internal_lookup The internal lookup to use.
39
- * @param WPSEO_Link_Filter $filter The link filter.
40
- */
41
- public function __construct( WPSEO_Link_Type_Classifier $classifier, WPSEO_Link_Internal_Lookup $internal_lookup, WPSEO_Link_Filter $filter ) {
42
- $this->classifier = $classifier;
43
- $this->internal_lookup = $internal_lookup;
44
- $this->filter = $filter;
45
- }
46
-
47
- /**
48
- * Formats an array of links to WPSEO_Link object.
49
- *
50
- * @param array $extracted_links The links for format.
51
- *
52
- * @return WPSEO_Link[] The formatted links.
53
- */
54
- public function build( array $extracted_links ) {
55
- $extracted_links = array_map( [ $this, 'build_link' ], $extracted_links );
56
- $filtered_links = array_filter(
57
- $extracted_links,
58
- [ $this->filter, 'internal_link_with_fragment_filter' ]
59
- );
60
-
61
- return $filtered_links;
62
- }
63
-
64
- /**
65
- * Builds the link.
66
- *
67
- * @param string $link The link to build.
68
- *
69
- * @return WPSEO_Link The built link.
70
- */
71
- public function build_link( $link ) {
72
- $link_type = $this->classifier->classify( $link );
73
-
74
- $target_post_id = 0;
75
- if ( $link_type === WPSEO_Link::TYPE_INTERNAL ) {
76
- $target_post_id = $this->internal_lookup->lookup( $link );
77
- }
78
-
79
- return self::get_link( $link, $target_post_id, $link_type );
80
- }
81
-
82
- /**
83
- * Returns the link object.
84
- *
85
- * @param string $url The URL of the link.
86
- * @param int $target_post_id The target post ID.
87
- * @param string $type The link type.
88
- *
89
- * @return WPSEO_Link Generated link object.
90
- */
91
- public static function get_link( $url, $target_post_id, $type ) {
92
- return new WPSEO_Link( $url, $target_post_id, $type );
93
- }
94
- }