Yoast SEO - Version 19.11

Version Description

Release date: November 29th, 2022

Yoast SEO 19.11 is out now. We're optimizing the Yoast SEO plugin to use fewer resources. This helps make your site faster and more efficient. In this release, we're doing this by streamlining your database. Find out more about what's new in Yoast SEO 19.11 in our release post!

Enhancements

  • Adds a WP-CLI command to clean up unused data from our custom database tables: wp yoast cleanup.
  • Performs a cleanup of indexables when a public post type (or taxonomy) becomes non-public.
  • Notifies users to run the SEO optimization when a non-public post type (or taxonomy) becomes public.

Bugfixes

  • Fixes a bug where a fatal error would be thrown when the SEO optimization was run after a post type had been manually excluded via a filter.
  • Fixes a bug where an entry would be added to our indexables table when saving, updating, or accessing a post (or term) for a non-public post type (or taxonomy).
  • Fixes a bug where duplicate indexable records would be created for the same object.
  • Fixes a bug where indexables for users would not get removed when a user did not have any publicly viewable posts anymore.
  • Fixes a bug where indexables for users would not get removed when author archives were disabled.
  • Fixes a bug where indexables would be created for users when author archives were disabled.
  • Fixes a bug where indexables would be created for users who did not have any publicly viewable posts.

Other

  • Introduces the wpseo_indexable_excluded_taxonomies filter, to allow manually excluding taxonomies from being indexed.
Download this release

Release Info

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

Code changes from version 19.10 to 19.11

Files changed (105) hide show
  1. admin/class-gutenberg-compatibility.php +2 -2
  2. admin/views/tabs/metas/post-types.php +3 -0
  3. css/dist/{admin-global-19100-rtl.css → admin-global-19110-rtl.css} +0 -0
  4. css/dist/{admin-global-19100.css → admin-global-19110.css} +0 -0
  5. css/dist/{adminbar-19100-rtl.css → adminbar-19110-rtl.css} +0 -0
  6. css/dist/{adminbar-19100.css → adminbar-19110.css} +0 -0
  7. css/dist/{alerts-19100-rtl.css → alerts-19110-rtl.css} +0 -0
  8. css/dist/{alerts-19100.css → alerts-19110.css} +0 -0
  9. css/dist/{dashboard-19100-rtl.css → dashboard-19110-rtl.css} +0 -0
  10. css/dist/{dashboard-19100.css → dashboard-19110.css} +0 -0
  11. css/dist/{edit-page-19100-rtl.css → edit-page-19110-rtl.css} +0 -0
  12. css/dist/{edit-page-19100.css → edit-page-19110.css} +0 -0
  13. css/dist/{elementor-19100-rtl.css → elementor-19110-rtl.css} +0 -0
  14. css/dist/{elementor-19100.css → elementor-19110.css} +0 -0
  15. css/dist/{featured-image-19100-rtl.css → featured-image-19110-rtl.css} +0 -0
  16. css/dist/{featured-image-19100.css → featured-image-19110.css} +0 -0
  17. css/dist/{filter-explanation-19100-rtl.css → filter-explanation-19110-rtl.css} +0 -0
  18. css/dist/{filter-explanation-19100.css → filter-explanation-19110.css} +0 -0
  19. css/dist/{icons-19100-rtl.css → icons-19110-rtl.css} +0 -0
  20. css/dist/{icons-19100.css → icons-19110.css} +0 -0
  21. css/dist/{inside-editor-19100-rtl.css → inside-editor-19110-rtl.css} +0 -0
  22. css/dist/{inside-editor-19100.css → inside-editor-19110.css} +0 -0
  23. css/dist/{metabox-19100-rtl.css → metabox-19110-rtl.css} +0 -0
  24. css/dist/{metabox-19100.css → metabox-19110.css} +0 -0
  25. css/dist/{metabox-primary-category-19100-rtl.css → metabox-primary-category-19110-rtl.css} +0 -0
  26. css/dist/{metabox-primary-category-19100.css → metabox-primary-category-19110.css} +0 -0
  27. css/dist/{modal-19100-rtl.css → modal-19110-rtl.css} +0 -0
  28. css/dist/{modal-19100.css → modal-19110.css} +0 -0
  29. css/dist/{monorepo-19100-rtl.css → monorepo-19110-rtl.css} +0 -0
  30. css/dist/{monorepo-19100.css → monorepo-19110.css} +0 -0
  31. css/dist/{new-settings-19100-rtl.css → new-settings-19110-rtl.css} +0 -0
  32. css/dist/{new-settings-19100.css → new-settings-19110.css} +0 -0
  33. css/dist/{notifications-19100-rtl.css → notifications-19110-rtl.css} +0 -0
  34. css/dist/{notifications-19100.css → notifications-19110.css} +0 -0
  35. css/dist/{notifications-new-19100-rtl.css → notifications-new-19110-rtl.css} +0 -0
  36. css/dist/{notifications-new-19100.css → notifications-new-19110.css} +0 -0
  37. css/dist/{schema-blocks-19100-rtl.css → schema-blocks-19110-rtl.css} +0 -0
  38. css/dist/{schema-blocks-19100.css → schema-blocks-19110.css} +0 -0
  39. css/dist/{score_icon-19100-rtl.css → score_icon-19110-rtl.css} +0 -0
  40. css/dist/{score_icon-19100.css → score_icon-19110.css} +0 -0
  41. css/dist/{search-appearance-19100-rtl.css → search-appearance-19110-rtl.css} +0 -0
  42. css/dist/{search-appearance-19100.css → search-appearance-19110.css} +0 -0
  43. css/dist/{structured-data-blocks-19100-rtl.css → structured-data-blocks-19110-rtl.css} +0 -0
  44. css/dist/{structured-data-blocks-19100.css → structured-data-blocks-19110.css} +0 -0
  45. css/dist/{tailwind-19100-rtl.css → tailwind-19110-rtl.css} +0 -0
  46. css/dist/{tailwind-19100.css → tailwind-19110.css} +0 -0
  47. css/dist/{toggle-switch-19100-rtl.css → toggle-switch-19110-rtl.css} +0 -0
  48. css/dist/{toggle-switch-19100.css → toggle-switch-19110.css} +0 -0
  49. css/dist/{tooltips-19100-rtl.css → tooltips-19110-rtl.css} +0 -0
  50. css/dist/{tooltips-19100.css → tooltips-19110.css} +0 -0
  51. css/dist/{workouts-19100-rtl.css → workouts-19110-rtl.css} +0 -0
  52. css/dist/{workouts-19100.css → workouts-19110.css} +0 -0
  53. css/dist/{wpseo-dismissible-19100-rtl.css → wpseo-dismissible-19110-rtl.css} +0 -0
  54. css/dist/{wpseo-dismissible-19100.css → wpseo-dismissible-19110.css} +0 -0
  55. css/dist/{yoast-components-19100-rtl.css → yoast-components-19110-rtl.css} +0 -0
  56. css/dist/{yoast-components-19100.css → yoast-components-19110.css} +0 -0
  57. css/dist/{yoast-extensions-19100-rtl.css → yoast-extensions-19110-rtl.css} +0 -0
  58. css/dist/{yoast-extensions-19100.css → yoast-extensions-19110.css} +0 -0
  59. css/dist/{yst_plugin_tools-19100-rtl.css → yst_plugin_tools-19110-rtl.css} +0 -0
  60. css/dist/{yst_plugin_tools-19100.css → yst_plugin_tools-19110.css} +0 -0
  61. css/dist/{yst_seo_score-19100-rtl.css → yst_seo_score-19110-rtl.css} +0 -0
  62. css/dist/{yst_seo_score-19100.css → yst_seo_score-19110.css} +0 -0
  63. inc/class-post-type.php +20 -0
  64. inc/class-upgrade.php +241 -3
  65. inc/options/class-wpseo-option-wpseo.php +4 -0
  66. inc/sitemaps/class-author-sitemap-provider.php +1 -3
  67. readme.txt +33 -33
  68. src/actions/indexing/indexable-post-indexation-action.php +2 -15
  69. src/actions/indexing/indexable-term-indexation-action.php +5 -4
  70. src/actions/indexing/post-link-indexing-action.php +2 -2
  71. src/actions/indexing/term-link-indexing-action.php +5 -4
  72. src/builders/indexable-author-builder.php +39 -0
  73. src/builders/indexable-builder.php +52 -23
  74. src/builders/indexable-post-builder.php +4 -2
  75. src/builders/indexable-term-builder.php +8 -1
  76. src/commands/cleanup-command.php +196 -0
  77. src/config/indexing-reasons.php +10 -0
  78. src/exceptions/indexable/author-not-built-exception.php +51 -0
  79. src/exceptions/indexable/not-built-exception.php +23 -0
  80. src/exceptions/indexable/post-not-built-exception.php +34 -0
  81. src/exceptions/indexable/term-not-built-exception.php +22 -0
  82. src/generated/container.php +71 -7
  83. src/generators/schema/breadcrumb.php +4 -0
  84. src/generators/schema/webpage.php +3 -0
  85. src/helpers/author-archive-helper.php +66 -0
  86. src/helpers/post-helper.php +22 -3
  87. src/helpers/post-type-helper.php +13 -0
  88. src/helpers/taxonomy-helper.php +47 -0
  89. src/integrations/admin/indexables-exclude-taxonomy-integration.php +53 -0
  90. src/integrations/cleanup-integration.php +207 -1
  91. src/integrations/watchers/indexable-author-archive-watcher.php +58 -0
  92. src/integrations/watchers/indexable-post-type-change-watcher.php +184 -0
  93. src/integrations/watchers/indexable-post-watcher.php +35 -4
  94. src/integrations/watchers/indexable-taxonomy-change-watcher.php +186 -0
  95. src/presentations/indexable-term-archive-presentation.php +5 -1
  96. src/presenters/admin/indexing-notification-presenter.php +6 -0
  97. src/routes/indexing-route.php +0 -2
  98. src/routes/yoast-head-rest-field.php +2 -2
  99. vendor/autoload.php +1 -1
  100. vendor/composer/autoload_classmap.php +9 -0
  101. vendor/composer/autoload_real.php +4 -4
  102. vendor/composer/autoload_static.php +13 -4
  103. vendor/composer/installed.php +2 -2
  104. wp-seo-main.php +2 -2
  105. wp-seo.php +1 -1
admin/class-gutenberg-compatibility.php CHANGED
@@ -15,14 +15,14 @@ class WPSEO_Gutenberg_Compatibility {
15
  *
16
  * @var string
17
  */
18
- const CURRENT_RELEASE = '14.4.0';
19
 
20
  /**
21
  * The minimally supported version of Gutenberg by the plugin.
22
  *
23
  * @var string
24
  */
25
- const MINIMUM_SUPPORTED = '14.4.0';
26
 
27
  /**
28
  * Holds the current version.
15
  *
16
  * @var string
17
  */
18
+ const CURRENT_RELEASE = '14.5.0';
19
 
20
  /**
21
  * The minimally supported version of Gutenberg by the plugin.
22
  *
23
  * @var string
24
  */
25
+ const MINIMUM_SUPPORTED = '14.5.0';
26
 
27
  /**
28
  * Holds the current version.
admin/views/tabs/metas/post-types.php CHANGED
@@ -11,6 +11,9 @@ if ( ! defined( 'WPSEO_VERSION' ) ) {
11
  exit();
12
  }
13
 
 
 
 
14
  /*
15
  * WPSEO_Post_Type::get_accessible_post_types() should *not* be used here.
16
  * Otherwise setting a post-type to `noindex` will remove it from the list,
11
  exit();
12
  }
13
 
14
+ WPSEO_Post_Type::remove_post_types_made_public_notification();
15
+ WPSEO_Post_Type::remove_taxonomies_made_public_notification();
16
+
17
  /*
18
  * WPSEO_Post_Type::get_accessible_post_types() should *not* be used here.
19
  * Otherwise setting a post-type to `noindex` will remove it from the list,
css/dist/{admin-global-19100-rtl.css → admin-global-19110-rtl.css} RENAMED
File without changes
css/dist/{admin-global-19100.css → admin-global-19110.css} RENAMED
File without changes
css/dist/{adminbar-19100-rtl.css → adminbar-19110-rtl.css} RENAMED
File without changes
css/dist/{adminbar-19100.css → adminbar-19110.css} RENAMED
File without changes
css/dist/{alerts-19100-rtl.css → alerts-19110-rtl.css} RENAMED
File without changes
css/dist/{alerts-19100.css → alerts-19110.css} RENAMED
File without changes
css/dist/{dashboard-19100-rtl.css → dashboard-19110-rtl.css} RENAMED
File without changes
css/dist/{dashboard-19100.css → dashboard-19110.css} RENAMED
File without changes
css/dist/{edit-page-19100-rtl.css → edit-page-19110-rtl.css} RENAMED
File without changes
css/dist/{edit-page-19100.css → edit-page-19110.css} RENAMED
File without changes
css/dist/{elementor-19100-rtl.css → elementor-19110-rtl.css} RENAMED
File without changes
css/dist/{elementor-19100.css → elementor-19110.css} RENAMED
File without changes
css/dist/{featured-image-19100-rtl.css → featured-image-19110-rtl.css} RENAMED
File without changes
css/dist/{featured-image-19100.css → featured-image-19110.css} RENAMED
File without changes
css/dist/{filter-explanation-19100-rtl.css → filter-explanation-19110-rtl.css} RENAMED
File without changes
css/dist/{filter-explanation-19100.css → filter-explanation-19110.css} RENAMED
File without changes
css/dist/{icons-19100-rtl.css → icons-19110-rtl.css} RENAMED
File without changes
css/dist/{icons-19100.css → icons-19110.css} RENAMED
File without changes
css/dist/{inside-editor-19100-rtl.css → inside-editor-19110-rtl.css} RENAMED
File without changes
css/dist/{inside-editor-19100.css → inside-editor-19110.css} RENAMED
File without changes
css/dist/{metabox-19100-rtl.css → metabox-19110-rtl.css} RENAMED
File without changes
css/dist/{metabox-19100.css → metabox-19110.css} RENAMED
File without changes
css/dist/{metabox-primary-category-19100-rtl.css → metabox-primary-category-19110-rtl.css} RENAMED
File without changes
css/dist/{metabox-primary-category-19100.css → metabox-primary-category-19110.css} RENAMED
File without changes
css/dist/{modal-19100-rtl.css → modal-19110-rtl.css} RENAMED
File without changes
css/dist/{modal-19100.css → modal-19110.css} RENAMED
File without changes
css/dist/{monorepo-19100-rtl.css → monorepo-19110-rtl.css} RENAMED
File without changes
css/dist/{monorepo-19100.css → monorepo-19110.css} RENAMED
File without changes
css/dist/{new-settings-19100-rtl.css → new-settings-19110-rtl.css} RENAMED
File without changes
css/dist/{new-settings-19100.css → new-settings-19110.css} RENAMED
File without changes
css/dist/{notifications-19100-rtl.css → notifications-19110-rtl.css} RENAMED
File without changes
css/dist/{notifications-19100.css → notifications-19110.css} RENAMED
File without changes
css/dist/{notifications-new-19100-rtl.css → notifications-new-19110-rtl.css} RENAMED
File without changes
css/dist/{notifications-new-19100.css → notifications-new-19110.css} RENAMED
File without changes
css/dist/{schema-blocks-19100-rtl.css → schema-blocks-19110-rtl.css} RENAMED
File without changes
css/dist/{schema-blocks-19100.css → schema-blocks-19110.css} RENAMED
File without changes
css/dist/{score_icon-19100-rtl.css → score_icon-19110-rtl.css} RENAMED
File without changes
css/dist/{score_icon-19100.css → score_icon-19110.css} RENAMED
File without changes
css/dist/{search-appearance-19100-rtl.css → search-appearance-19110-rtl.css} RENAMED
File without changes
css/dist/{search-appearance-19100.css → search-appearance-19110.css} RENAMED
File without changes
css/dist/{structured-data-blocks-19100-rtl.css → structured-data-blocks-19110-rtl.css} RENAMED
File without changes
css/dist/{structured-data-blocks-19100.css → structured-data-blocks-19110.css} RENAMED
File without changes
css/dist/{tailwind-19100-rtl.css → tailwind-19110-rtl.css} RENAMED
File without changes
css/dist/{tailwind-19100.css → tailwind-19110.css} RENAMED
File without changes
css/dist/{toggle-switch-19100-rtl.css → toggle-switch-19110-rtl.css} RENAMED
File without changes
css/dist/{toggle-switch-19100.css → toggle-switch-19110.css} RENAMED
File without changes
css/dist/{tooltips-19100-rtl.css → tooltips-19110-rtl.css} RENAMED
File without changes
css/dist/{tooltips-19100.css → tooltips-19110.css} RENAMED
File without changes
css/dist/{workouts-19100-rtl.css → workouts-19110-rtl.css} RENAMED
File without changes
css/dist/{workouts-19100.css → workouts-19110.css} RENAMED
File without changes
css/dist/{wpseo-dismissible-19100-rtl.css → wpseo-dismissible-19110-rtl.css} RENAMED
File without changes
css/dist/{wpseo-dismissible-19100.css → wpseo-dismissible-19110.css} RENAMED
File without changes
css/dist/{yoast-components-19100-rtl.css → yoast-components-19110-rtl.css} RENAMED
File without changes
css/dist/{yoast-components-19100.css → yoast-components-19110.css} RENAMED
File without changes
css/dist/{yoast-extensions-19100-rtl.css → yoast-extensions-19110-rtl.css} RENAMED
File without changes
css/dist/{yoast-extensions-19100.css → yoast-extensions-19110.css} RENAMED
File without changes
css/dist/{yst_plugin_tools-19100-rtl.css → yst_plugin_tools-19110-rtl.css} RENAMED
File without changes
css/dist/{yst_plugin_tools-19100.css → yst_plugin_tools-19110.css} RENAMED
File without changes
css/dist/{yst_seo_score-19100-rtl.css → yst_seo_score-19110-rtl.css} RENAMED
File without changes
css/dist/{yst_seo_score-19100.css → yst_seo_score-19110.css} RENAMED
File without changes
inc/class-post-type.php CHANGED
@@ -98,4 +98,24 @@ class WPSEO_Post_Type {
98
  public static function has_metabox_enabled( $post_type ) {
99
  return WPSEO_Options::get( 'display-metabox-pt-' . $post_type, false );
100
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  }
98
  public static function has_metabox_enabled( $post_type ) {
99
  return WPSEO_Options::get( 'display-metabox-pt-' . $post_type, false );
100
  }
101
+
102
+ /**
103
+ * Removes the notification related to the post types which have been made public.
104
+ *
105
+ * @return void
106
+ */
107
+ public static function remove_post_types_made_public_notification() {
108
+ $notification_center = Yoast_Notification_Center::get();
109
+ $notification_center->remove_notification_by_id( 'post-types-made-public' );
110
+ }
111
+
112
+ /**
113
+ * Removes the notification related to the taxonomies which have been made public.
114
+ *
115
+ * @return void
116
+ */
117
+ public static function remove_taxonomies_made_public_notification() {
118
+ $notification_center = Yoast_Notification_Center::get();
119
+ $notification_center->remove_notification_by_id( 'taxonomies-made-public' );
120
+ }
121
  }
inc/class-upgrade.php CHANGED
@@ -6,6 +6,12 @@
6
  */
7
 
8
  use Yoast\WP\Lib\Model;
 
 
 
 
 
 
9
 
10
  /**
11
  * This code handles the option upgrades.
@@ -82,10 +88,10 @@ class WPSEO_Upgrade {
82
  '19.1-RC0' => 'upgrade_191',
83
  '19.3-RC0' => 'upgrade_193',
84
  '19.6-RC0' => 'upgrade_196',
 
85
  ];
86
 
87
  array_walk( $routines, [ $this, 'run_upgrade_routine' ], $version );
88
-
89
  if ( version_compare( $version, '12.5-RC0', '<' ) ) {
90
  /*
91
  * We have to run this by hook, because otherwise:
@@ -847,8 +853,8 @@ class WPSEO_Upgrade {
847
  \wp_unschedule_hook( 'wpseo_cleanup_orphaned_indexables' );
848
  \wp_unschedule_hook( 'wpseo_cleanup_indexables' );
849
 
850
- if ( ! \wp_next_scheduled( \Yoast\WP\SEO\Integrations\Cleanup_Integration::START_HOOK ) ) {
851
- \wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), \Yoast\WP\SEO\Integrations\Cleanup_Integration::START_HOOK );
852
  }
853
  }
854
 
@@ -948,6 +954,19 @@ class WPSEO_Upgrade {
948
  wp_clear_scheduled_hook( 'wpseo_ryte_fetch' );
949
  }
950
 
 
 
 
 
 
 
 
 
 
 
 
 
 
951
  /**
952
  * Sets the home_url option for the 15.1 upgrade routine.
953
  *
@@ -1341,4 +1360,223 @@ class WPSEO_Upgrade {
1341
 
1342
  update_option( 'wpseo_titles', $wpseo_titles );
1343
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1344
  }
6
  */
7
 
8
  use Yoast\WP\Lib\Model;
9
+ use Yoast\WP\SEO\Helpers\Author_Archive_Helper;
10
+ use Yoast\WP\SEO\Helpers\Options_Helper;
11
+ use Yoast\WP\SEO\Helpers\Post_Type_Helper;
12
+ use Yoast\WP\SEO\Helpers\String_Helper;
13
+ use Yoast\WP\SEO\Helpers\Taxonomy_Helper;
14
+ use Yoast\WP\SEO\Integrations\Cleanup_Integration;
15
 
16
  /**
17
  * This code handles the option upgrades.
88
  '19.1-RC0' => 'upgrade_191',
89
  '19.3-RC0' => 'upgrade_193',
90
  '19.6-RC0' => 'upgrade_196',
91
+ '19.11-RC0' => 'upgrade_1911',
92
  ];
93
 
94
  array_walk( $routines, [ $this, 'run_upgrade_routine' ], $version );
 
95
  if ( version_compare( $version, '12.5-RC0', '<' ) ) {
96
  /*
97
  * We have to run this by hook, because otherwise:
853
  \wp_unschedule_hook( 'wpseo_cleanup_orphaned_indexables' );
854
  \wp_unschedule_hook( 'wpseo_cleanup_indexables' );
855
 
856
+ if ( ! \wp_next_scheduled( Cleanup_Integration::START_HOOK ) ) {
857
+ \wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
858
  }
859
  }
860
 
954
  wp_clear_scheduled_hook( 'wpseo_ryte_fetch' );
955
  }
956
 
957
+ /**
958
+ * Performs the 19.11 upgrade routine.
959
+ */
960
+ private function upgrade_1911() {
961
+ \add_action( 'shutdown', [ $this, 'remove_indexable_rows_for_non_public_post_types' ] );
962
+ \add_action( 'shutdown', [ $this, 'remove_indexable_rows_for_non_public_taxonomies' ] );
963
+ $this->deduplicate_unindexed_indexable_rows();
964
+ $this->remove_indexable_rows_for_disabled_authors_archive();
965
+ if ( ! \wp_next_scheduled( Cleanup_Integration::START_HOOK ) ) {
966
+ \wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
967
+ }
968
+ }
969
+
970
  /**
971
  * Sets the home_url option for the 15.1 upgrade routine.
972
  *
1360
 
1361
  update_option( 'wpseo_titles', $wpseo_titles );
1362
  }
1363
+
1364
+ /**
1365
+ * Removes all indexables for posts that are not publicly viewable.
1366
+ * This method should be called after init, because post_types can still be registered.
1367
+ *
1368
+ * @return void
1369
+ */
1370
+ public function remove_indexable_rows_for_non_public_post_types() {
1371
+ global $wpdb;
1372
+
1373
+ // If migrations haven't been completed successfully the following may give false errors. So suppress them.
1374
+ $show_errors = $wpdb->show_errors;
1375
+ $wpdb->show_errors = false;
1376
+
1377
+ $indexable_table = Model::get_table_name( 'Indexable' );
1378
+
1379
+ $included_post_types = \YoastSEO()->helpers->post_type->get_indexable_post_types();
1380
+
1381
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: Too hard to fix.
1382
+ if ( empty( $included_post_types ) ) {
1383
+ $delete_query =
1384
+ "DELETE FROM $indexable_table
1385
+ WHERE object_type = 'post'
1386
+ AND object_sub_type IS NOT NULL";
1387
+ }
1388
+ else {
1389
+ $delete_query = $wpdb->prepare(
1390
+ "DELETE FROM $indexable_table
1391
+ WHERE object_type = 'post'
1392
+ AND object_sub_type IS NOT NULL
1393
+ AND object_sub_type NOT IN ( " . \implode( ', ', \array_fill( 0, \count( $included_post_types ), '%s' ) ) . ' )',
1394
+ $included_post_types
1395
+ );
1396
+ }
1397
+ // phpcs:enable
1398
+
1399
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: Most performant way.
1400
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
1401
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Reason: Is it prepared already.
1402
+ $wpdb->query( $delete_query );
1403
+ // phpcs:enable
1404
+
1405
+ $wpdb->show_errors = $show_errors;
1406
+ }
1407
+
1408
+ /**
1409
+ * Removes all indexables for terms that are not publicly viewable.
1410
+ * This method should be called after init, because taxonomies can still be registered.
1411
+ *
1412
+ * @return void
1413
+ */
1414
+ public function remove_indexable_rows_for_non_public_taxonomies() {
1415
+ global $wpdb;
1416
+
1417
+ // If migrations haven't been completed successfully the following may give false errors. So suppress them.
1418
+ $show_errors = $wpdb->show_errors;
1419
+ $wpdb->show_errors = false;
1420
+
1421
+ $indexable_table = Model::get_table_name( 'Indexable' );
1422
+
1423
+ $included_taxonomies = \YoastSEO()->helpers->taxonomy->get_indexable_taxonomies();
1424
+
1425
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: Too hard to fix.
1426
+ if ( empty( $included_taxonomies ) ) {
1427
+ $delete_query = "DELETE FROM $indexable_table
1428
+ WHERE object_type = 'term'
1429
+ AND object_sub_type IS NOT NULL";
1430
+ }
1431
+ else {
1432
+ $delete_query = $wpdb->prepare(
1433
+ "DELETE FROM $indexable_table
1434
+ WHERE object_type = 'term'
1435
+ AND object_sub_type IS NOT NULL
1436
+ AND object_sub_type NOT IN ( " . \implode( ', ', \array_fill( 0, \count( $included_taxonomies ), '%s' ) ) . ' )',
1437
+ $included_taxonomies
1438
+ );
1439
+ }
1440
+ // phpcs:enable
1441
+
1442
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: Most performant way.
1443
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
1444
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Reason: Is it prepared already.
1445
+ $wpdb->query( $delete_query );
1446
+ // phpcs:enable
1447
+
1448
+ $wpdb->show_errors = $show_errors;
1449
+ }
1450
+
1451
+ /**
1452
+ * De-duplicates indexables that have more than one "unindexed" rows for the same object. Keeps the newest indexable.
1453
+ *
1454
+ * @return void
1455
+ */
1456
+ private function deduplicate_unindexed_indexable_rows() {
1457
+ global $wpdb;
1458
+
1459
+ // If migrations haven't been completed successfully the following may give false errors. So suppress them.
1460
+ $show_errors = $wpdb->show_errors;
1461
+ $wpdb->show_errors = false;
1462
+
1463
+ $indexable_table = Model::get_table_name( 'Indexable' );
1464
+
1465
+ $query =
1466
+ "SELECT
1467
+ MAX(id) as newest_id,
1468
+ object_id,
1469
+ object_type
1470
+ FROM
1471
+ $indexable_table
1472
+ WHERE
1473
+ post_status = 'unindexed'
1474
+ AND object_type IN ( 'term', 'post', 'user' )
1475
+ GROUP BY
1476
+ object_id,
1477
+ object_type
1478
+ HAVING
1479
+ count(*) > 1";
1480
+
1481
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: Most performant way.
1482
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
1483
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Reason: Is it prepared already.
1484
+ $duplicates = $wpdb->get_results( $query, ARRAY_A );
1485
+ // phpcs:enable
1486
+
1487
+ if ( empty( $duplicates ) ) {
1488
+ $wpdb->show_errors = $show_errors;
1489
+
1490
+ return;
1491
+ }
1492
+
1493
+ // Users, terms and posts may share the same object_id. So delete them in separate, more performant, queries.
1494
+ $delete_queries = [
1495
+ $this->get_indexable_deduplication_query_for_type( 'post', $duplicates, $wpdb ),
1496
+ $this->get_indexable_deduplication_query_for_type( 'term', $duplicates, $wpdb ),
1497
+ $this->get_indexable_deduplication_query_for_type( 'user', $duplicates, $wpdb ),
1498
+ ];
1499
+
1500
+ foreach ( $delete_queries as $delete_query ) {
1501
+ if ( ! empty( $delete_query ) ) {
1502
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: Most performant way.
1503
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
1504
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Reason: Is it prepared already.
1505
+ $wpdb->query( $delete_query );
1506
+ // phpcs:enable
1507
+ }
1508
+ }
1509
+
1510
+ $wpdb->show_errors = $show_errors;
1511
+ }
1512
+
1513
+ /**
1514
+ * Removes all user indexable rows when the author archive is disabled.
1515
+ *
1516
+ * @return void
1517
+ */
1518
+ private function remove_indexable_rows_for_disabled_authors_archive() {
1519
+ global $wpdb;
1520
+
1521
+ if ( ! \YoastSEO()->helpers->author_archive->are_disabled() ) {
1522
+ return;
1523
+ }
1524
+
1525
+ // If migrations haven't been completed successfully the following may give false errors. So suppress them.
1526
+ $show_errors = $wpdb->show_errors;
1527
+ $wpdb->show_errors = false;
1528
+
1529
+ $indexable_table = Model::get_table_name( 'Indexable' );
1530
+
1531
+ $delete_query = "DELETE FROM $indexable_table WHERE object_type = 'user'";
1532
+ // phpcs:enable
1533
+
1534
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
1535
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: Most performant way.
1536
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Reason: Is it prepared already.
1537
+ $wpdb->query( $delete_query );
1538
+ // phpcs:enable
1539
+
1540
+ $wpdb->show_errors = $show_errors;
1541
+ }
1542
+
1543
+ /**
1544
+ * Creates a query for de-duplicating indexables for a particular type.
1545
+ *
1546
+ * @param string $object_type The object type to deduplicate.
1547
+ * @param array $duplicates The result of the duplicate query.
1548
+ * @param wpdb $wpdb The wpdb object.
1549
+ *
1550
+ * @return string The query that removes all but one duplicate for each object of the object type.
1551
+ */
1552
+ private function get_indexable_deduplication_query_for_type( $object_type, $duplicates, $wpdb ) {
1553
+ $indexable_table = Model::get_table_name( 'Indexable' );
1554
+
1555
+ $filtered_duplicates = \array_filter(
1556
+ $duplicates,
1557
+ static function ( $duplicate ) use ( $object_type ) {
1558
+ return $duplicate['object_type'] === $object_type;
1559
+ }
1560
+ );
1561
+
1562
+ if ( empty( $filtered_duplicates ) ) {
1563
+ return '';
1564
+ }
1565
+
1566
+ $object_ids = wp_list_pluck( $filtered_duplicates, 'object_id' );
1567
+ $newest_indexable_ids = wp_list_pluck( $filtered_duplicates, 'newest_id' );
1568
+
1569
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: Too hard to fix.
1570
+ // phpcs:disable WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber -- Reason: we're passing an array instead.
1571
+ return $wpdb->prepare(
1572
+ "DELETE FROM
1573
+ $indexable_table
1574
+ WHERE
1575
+ object_id IN ( " . \implode( ', ', \array_fill( 0, \count( $filtered_duplicates ), '%d' ) ) . ' )
1576
+ AND id NOT IN ( ' . \implode( ', ', \array_fill( 0, \count( $filtered_duplicates ), '%d' ) ) . ' )
1577
+ AND object_type = %s',
1578
+ array_merge( array_values( $object_ids ), array_values( $newest_indexable_ids ), [ $object_type ] )
1579
+ );
1580
+ // phpcs:enable
1581
+ }
1582
  }
inc/options/class-wpseo-option-wpseo.php CHANGED
@@ -131,6 +131,8 @@ class WPSEO_Option_Wpseo extends WPSEO_Option {
131
  'least_linked_ignore_list' => [],
132
  'indexables_page_reading_list' => [ false, false, false, false, false ],
133
  'indexables_overview_state' => 'dashboard-not-visited',
 
 
134
  ];
135
 
136
  /**
@@ -400,6 +402,8 @@ class WPSEO_Option_Wpseo extends WPSEO_Option {
400
  case 'most_linked_ignore_list':
401
  case 'least_linked_ignore_list':
402
  case 'indexables_page_reading_list':
 
 
403
  $clean[ $key ] = $old[ $key ];
404
 
405
  if ( isset( $dirty[ $key ] ) ) {
131
  'least_linked_ignore_list' => [],
132
  'indexables_page_reading_list' => [ false, false, false, false, false ],
133
  'indexables_overview_state' => 'dashboard-not-visited',
134
+ 'last_known_public_post_types' => [],
135
+ 'last_known_public_taxonomies' => [],
136
  ];
137
 
138
  /**
402
  case 'most_linked_ignore_list':
403
  case 'least_linked_ignore_list':
404
  case 'indexables_page_reading_list':
405
+ case 'last_known_public_post_types':
406
+ case 'last_known_public_taxonomies':
407
  $clean[ $key ] = $old[ $key ];
408
 
409
  if ( isset( $dirty[ $key ] ) ) {
inc/sitemaps/class-author-sitemap-provider.php CHANGED
@@ -5,7 +5,6 @@
5
  * @package WPSEO\XML_Sitemaps
6
  */
7
 
8
- use Yoast\WP\SEO\Helpers\Author_Archive_Helper;
9
  use Yoast\WP\SEO\Helpers\Wordpress_Helper;
10
 
11
  /**
@@ -131,8 +130,7 @@ class WPSEO_Author_Sitemap_Provider implements WPSEO_Sitemap_Provider {
131
 
132
  if ( WPSEO_Options::get( 'noindex-author-noposts-wpseo', true ) ) {
133
  unset( $defaults['who'], $defaults['capability'] ); // Otherwise it cancels out next argument.
134
- $author_archive = new Author_Archive_Helper();
135
- $defaults['has_published_posts'] = $author_archive->get_author_archive_post_types();
136
  }
137
 
138
  return get_users( array_merge( $defaults, $arguments ) );
5
  * @package WPSEO\XML_Sitemaps
6
  */
7
 
 
8
  use Yoast\WP\SEO\Helpers\Wordpress_Helper;
9
 
10
  /**
130
 
131
  if ( WPSEO_Options::get( 'noindex-author-noposts-wpseo', true ) ) {
132
  unset( $defaults['who'], $defaults['capability'] ); // Otherwise it cancels out next argument.
133
+ $defaults['has_published_posts'] = YoastSEO()->helpers->author_archive->get_author_archive_post_types();
 
134
  }
135
 
136
  return get_users( array_merge( $defaults, $arguments ) );
readme.txt CHANGED
@@ -5,7 +5,7 @@ License: GPLv3
5
  License URI: http://www.gnu.org/licenses/gpl.html
6
  Tags: SEO, XML sitemap, Content analysis, Readability, Schema
7
  Tested up to: 6.1
8
- Stable tag: 19.10
9
  Requires PHP: 5.6.20
10
 
11
  Improve your WordPress SEO: Write better content and have a fully optimized WordPress site using the Yoast SEO plugin.
@@ -245,53 +245,53 @@ Your question has most likely been answered on our help center: [yoast.com/help/
245
 
246
  == Changelog ==
247
 
248
- = 19.10 =
249
- Release Date: November 8th, 2022
250
 
251
- Yoast SEO 19.10 is out today. This release mostly consists of bug fixes and enhancements. In addition, we're getting our WordPress plugins ready for the upcoming High Performance Order Storage feature in WooCommerce 7.1+. Update now! Read more about what's new in Yoast SEO 19.9 in [our release post in English](https://yoa.st/release-8-11-22) or [our release post in Spanish](https://yoa.st/release-8-11-22-spanish)!
252
 
253
- Enhancements:
 
 
254
 
255
- * Improves the call-to-action feedback string of the _Flesch Reading Ease_ insight when the text is recognized as fairly difficult.
 
 
256
 
257
- Bugfixes:
258
 
259
- * Fixes a bug where a fatal error would be thrown in the classic editor in combination with certain plugins that misuse metabox hooks.
260
- * Fixes a bug where users with site-wide basic access authentication would be prompted to insert their credentials when saving a post in Elementor if they didn't have the `manage_options` capability.
261
- * Fixes a bug where Yoast SEO-related post meta data would not be saved if a user without the `manage_options` capability would save a post in Elementor.
 
 
 
 
262
 
263
- Other:
264
 
265
- * Deprecates the hooks used to add custom content to the Yoast SEO settings pages, in preparation for future releases. The following hooks have been deprecated: `wpseo_tools_overview_list_items`, `wpseo_settings_tab_crawl_cleanup`, `wpseo_settings_tab_site_analysis`, `Yoast\WP\SEO\admin_author_archives_meta`, `Yoast\WP\SEO\admin_date_archives_meta`, `Yoast\WP\SEO\admin_post_types_beforearchive`, `Yoast\WP\SEO\admin_post_types_archive`, `Yoast\WP\SEO\admin_taxonomies_meta`, `wpseo_admin_other_section`, `wpseo_admin_opengraph_section`, `wpseo_admin_pinterest_section`, `wpseo_admin_twitter_section`, `wpseo_import_other_plugins`.
266
- * Ensures compatibility with the _High Performance Order Storage_ feature in WooCommerce 7.1+.
267
- * Sets the WordPress tested up to version to 6.1.
268
 
269
- = 19.9 =
270
- Release Date: October 25th, 2022
271
 
272
- Yoast SEO 19.9 is out today. Yoast SEO already supports the Schema necessary for Google's Site Names update, but we've expanded support for it in this release. In addition, we give users more control over what names they can add, including an alternate title. Of course, there's a lot more, so check it out! Read more about what's new in Yoast SEO 19.9 in [our release post in English](https://yoa.st/release-25-10-22) or [our release post in Spanish](https://yoa.st/release-25-10-22-spanish)!
273
 
274
- Enhancements:
275
 
276
- * Adds input fields to overwrite the site name, as well as an extra input field for a (potentially shorter) alternate name. Google introduced new support for [site names in Google Search](https://developers.google.com/search/blog/2022/10/introducing-site-names-on-search). Yoast SEO already outputs this value correctly, using the WordPress site name. With these changes, we have increased the control site owners have over this value.
277
- * Improves the Schema output for Organization by no longer putting out an empty array if no social profiles have been added for it.
278
- * Adds immediate keyphrase tracking after connecting to Wincher.
279
 
280
- Bugfixes:
281
 
282
- * Fixes a bug where a fatal error would be thrown when using the `wpseo_breadcrumb_links` filter in the wrong way on PHP 8.0+.
283
- * Fixes a bug where social or canonical URLs containing `@` would lead to encoding issues. Props to [@stodorovic](https://github.com/stodorovic).
284
- * Fixes a bug where the buttons in the _FAQ_ and in the _how-to_ block would be hardly visible when using a dark theme.
285
- * Fixes a bug where the number of words would be counted incorrectly when using Cyrillic script. Props to [kudinovfedor](https://github.com/kudinovfedor).
286
- * Fixes a bug where the _previously used keyphrase_ assessment would also appear under the readability analysis tab when the cornerstone content toggle would be switched on.
287
- * Fixes a bug where the SEO optimization routine would give an error when an image file of an image linked in a post could not be retrieved.
288
- * Fixes a bug where the wrong canonical URL would be set on attachment pages.
289
 
290
- Other:
 
 
 
 
291
 
292
- * Adds taxonomy information to breadcrumbs of type "term" to be able to filter them better with the `wpseo_breadcrumb_links` filter. Props to [@svenvonarx](https://github.com/svenvonarx).
293
- * Adds a `wpseo_primary_category_admin_pages` filter to enable the use of the primary category in the post URL of additional admin pages besides the default ones. Props to [@ssvet](https://github.com/ssvet).
294
- * Reinstates the `wpseo_twitter_card_type` filter that was wrongly deprecated in 19.8.
295
 
296
  = Earlier versions =
297
  For the changelog of earlier versions, please refer to [the changelog on yoast.com](https://yoa.st/yoast-seo-changelog).
5
  License URI: http://www.gnu.org/licenses/gpl.html
6
  Tags: SEO, XML sitemap, Content analysis, Readability, Schema
7
  Tested up to: 6.1
8
+ Stable tag: 19.11
9
  Requires PHP: 5.6.20
10
 
11
  Improve your WordPress SEO: Write better content and have a fully optimized WordPress site using the Yoast SEO plugin.
245
 
246
  == Changelog ==
247
 
248
+ = 19.11 =
 
249
 
250
+ Release date: November 29th, 2022
251
 
252
+ Yoast SEO 19.11 is out now. We're optimizing the Yoast SEO plugin to use fewer resources. This helps make your site faster and more efficient. In this release, we're doing this by streamlining your database. Find out more about what's new in Yoast SEO 19.11 in [our release post](https://yoa.st/release-29-11-22)!
253
+
254
+ #### Enhancements
255
 
256
+ * Adds a WP-CLI command to clean up unused data from our custom database tables: `wp yoast cleanup`.
257
+ * Performs a cleanup of indexables when a public post type (or taxonomy) becomes non-public.
258
+ * Notifies users to run the SEO optimization when a non-public post type (or taxonomy) becomes public.
259
 
260
+ #### Bugfixes
261
 
262
+ * Fixes a bug where a fatal error would be thrown when the SEO optimization was run after a post type had been manually excluded via a filter.
263
+ * Fixes a bug where an entry would be added to our indexables table when saving, updating, or accessing a post (or term) for a non-public post type (or taxonomy).
264
+ * Fixes a bug where duplicate indexable records would be created for the same object.
265
+ * Fixes a bug where indexables for users would not get removed when a user did not have any publicly viewable posts anymore.
266
+ * Fixes a bug where indexables for users would not get removed when author archives were disabled.
267
+ * Fixes a bug where indexables would be created for users when author archives were disabled.
268
+ * Fixes a bug where indexables would be created for users who did not have any publicly viewable posts.
269
 
270
+ #### Other
271
 
272
+ * Introduces the `wpseo_indexable_excluded_taxonomies` filter, to allow manually excluding taxonomies from being indexed.
 
 
273
 
274
+ = 19.10 =
 
275
 
276
+ Release date: November 8th, 2022
277
 
278
+ Yoast SEO 19.10 is out today. This release mostly consists of bug fixes and enhancements. In addition, we're getting our WordPress plugins ready for the upcoming High Performance Order Storage feature in WooCommerce 7.1+. Update now! Read more about what's new in Yoast SEO 19.10 in [our release post in English](https://yoa.st/release-8-11-22) or [our release post in Spanish](https://yoa.st/release-8-11-22-spanish)!
279
 
280
+ #### Enhancements
 
 
281
 
282
+ * Improves the call-to-action feedback string of the Flesch Reading Ease insight when the text is recognized as fairly difficult.
283
 
284
+ #### Bugfixes
 
 
 
 
 
 
285
 
286
+ * Fixes a bug where a fatal error would be thrown in the classic editor in combination with certain plugins that misuse metabox hooks.
287
+ * Fixes a bug where users with site-wide basic access authentication would be prompted to insert their credentials when saving a post in Elementor if they didn’t have the manage_options capability.
288
+ * Fixes a bug where Yoast SEO-related post meta data would not be saved if a user without the manage_options capability would save a post in Elementor.
289
+
290
+ #### Other
291
 
292
+ * Deprecates the hooks used to add custom content to the Yoast SEO settings pages, in preparation for future releases. The following hooks have been deprecated: wpseo_tools_overview_list_items, wpseo_settings_tab_crawl_cleanup, wpseo_settings_tab_site_analysis, Yoast\WP\SEOdmin_author_archives_meta, Yoast\WP\SEOdmin_date_archives_meta, Yoast\WP\SEOdmin_post_types_beforearchive, Yoast\WP\SEOdmin_post_types_archive, Yoast\WP\SEOdmin_taxonomies_meta, wpseo_admin_other_section, wpseo_admin_opengraph_section, wpseo_admin_pinterest_section, wpseo_admin_twitter_section, wpseo_import_other_plugins.
293
+ * Ensures compatibility with the High Performance Order Storage feature in WooCommerce 7.1+.
294
+ * Sets the WordPress tested up to version to 6.1.
295
 
296
  = Earlier versions =
297
  For the changelog of earlier versions, please refer to [the changelog on yoast.com](https://yoa.st/yoast-seo-changelog).
src/actions/indexing/indexable-post-indexation-action.php CHANGED
@@ -139,7 +139,7 @@ class Indexable_Post_Indexation_Action extends Abstract_Indexing_Action {
139
  protected function get_count_query() {
140
  $indexable_table = Model::get_table_name( 'Indexable' );
141
 
142
- $post_types = $this->get_post_types();
143
  $excluded_post_statuses = $this->post_helper->get_excluded_post_statuses();
144
  $replacements = \array_merge(
145
  $post_types,
@@ -174,7 +174,7 @@ class Indexable_Post_Indexation_Action extends Abstract_Indexing_Action {
174
  protected function get_select_query( $limit = false ) {
175
  $indexable_table = Model::get_table_name( 'Indexable' );
176
 
177
- $post_types = $this->get_post_types();
178
  $excluded_post_statuses = $this->post_helper->get_excluded_post_statuses();
179
  $replacements = \array_merge(
180
  $post_types,
@@ -204,17 +204,4 @@ class Indexable_Post_Indexation_Action extends Abstract_Indexing_Action {
204
  $replacements
205
  );
206
  }
207
-
208
- /**
209
- * Returns the post types that should be indexed.
210
- *
211
- * @return array The post types that should be indexed.
212
- */
213
- protected function get_post_types() {
214
- $public_post_types = $this->post_type_helper->get_public_post_types();
215
- $excluded_post_types = $this->post_type_helper->get_excluded_post_types_for_indexables();
216
-
217
- // `array_values`, to make sure that the keys are reset.
218
- return \array_values( \array_diff( $public_post_types, $excluded_post_types ) );
219
- }
220
  }
139
  protected function get_count_query() {
140
  $indexable_table = Model::get_table_name( 'Indexable' );
141
 
142
+ $post_types = $this->post_type_helper->get_indexable_post_types();
143
  $excluded_post_statuses = $this->post_helper->get_excluded_post_statuses();
144
  $replacements = \array_merge(
145
  $post_types,
174
  protected function get_select_query( $limit = false ) {
175
  $indexable_table = Model::get_table_name( 'Indexable' );
176
 
177
+ $post_types = $this->post_type_helper->get_indexable_post_types();
178
  $excluded_post_statuses = $this->post_helper->get_excluded_post_statuses();
179
  $replacements = \array_merge(
180
  $post_types,
204
  $replacements
205
  );
206
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  }
src/actions/indexing/indexable-term-indexation-action.php CHANGED
@@ -124,9 +124,10 @@ class Indexable_Term_Indexation_Action extends Abstract_Indexing_Action {
124
  * @return string The prepared query string.
125
  */
126
  protected function get_count_query() {
127
- $indexable_table = Model::get_table_name( 'Indexable' );
128
- $taxonomy_table = $this->wpdb->term_taxonomy;
129
- $public_taxonomies = \array_keys( $this->taxonomy->get_public_taxonomies() );
 
130
  $taxonomies_placeholders = \implode( ', ', \array_fill( 0, \count( $public_taxonomies ), '%s' ) );
131
 
132
  $replacements = [ $this->version ];
@@ -157,7 +158,7 @@ class Indexable_Term_Indexation_Action extends Abstract_Indexing_Action {
157
  protected function get_select_query( $limit = false ) {
158
  $indexable_table = Model::get_table_name( 'Indexable' );
159
  $taxonomy_table = $this->wpdb->term_taxonomy;
160
- $public_taxonomies = \array_keys( $this->taxonomy->get_public_taxonomies() );
161
  $placeholders = \implode( ', ', \array_fill( 0, \count( $public_taxonomies ), '%s' ) );
162
 
163
  $replacements = [ $this->version ];
124
  * @return string The prepared query string.
125
  */
126
  protected function get_count_query() {
127
+ $indexable_table = Model::get_table_name( 'Indexable' );
128
+ $taxonomy_table = $this->wpdb->term_taxonomy;
129
+ $public_taxonomies = $this->taxonomy->get_indexable_taxonomies();
130
+
131
  $taxonomies_placeholders = \implode( ', ', \array_fill( 0, \count( $public_taxonomies ), '%s' ) );
132
 
133
  $replacements = [ $this->version ];
158
  protected function get_select_query( $limit = false ) {
159
  $indexable_table = Model::get_table_name( 'Indexable' );
160
  $taxonomy_table = $this->wpdb->term_taxonomy;
161
+ $public_taxonomies = $this->taxonomy->get_indexable_taxonomies();
162
  $placeholders = \implode( ', ', \array_fill( 0, \count( $public_taxonomies ), '%s' ) );
163
 
164
  $replacements = [ $this->version ];
src/actions/indexing/post-link-indexing-action.php CHANGED
@@ -73,7 +73,7 @@ class Post_Link_Indexing_Action extends Abstract_Link_Indexing_Action {
73
  * @return string The prepared query string.
74
  */
75
  protected function get_count_query() {
76
- $public_post_types = $this->post_type_helper->get_accessible_post_types();
77
  $indexable_table = Model::get_table_name( 'Indexable' );
78
  $links_table = Model::get_table_name( 'SEO_Links' );
79
 
@@ -106,7 +106,7 @@ class Post_Link_Indexing_Action extends Abstract_Link_Indexing_Action {
106
  * @return string The prepared query string.
107
  */
108
  protected function get_select_query( $limit = false ) {
109
- $public_post_types = $this->post_type_helper->get_accessible_post_types();
110
  $indexable_table = Model::get_table_name( 'Indexable' );
111
  $links_table = Model::get_table_name( 'SEO_Links' );
112
  $replacements = $public_post_types;
73
  * @return string The prepared query string.
74
  */
75
  protected function get_count_query() {
76
+ $public_post_types = $this->post_type_helper->get_indexable_post_types();
77
  $indexable_table = Model::get_table_name( 'Indexable' );
78
  $links_table = Model::get_table_name( 'SEO_Links' );
79
 
106
  * @return string The prepared query string.
107
  */
108
  protected function get_select_query( $limit = false ) {
109
+ $public_post_types = $this->post_type_helper->get_indexable_post_types();
110
  $indexable_table = Model::get_table_name( 'Indexable' );
111
  $links_table = Model::get_table_name( 'SEO_Links' );
112
  $replacements = $public_post_types;
src/actions/indexing/term-link-indexing-action.php CHANGED
@@ -73,7 +73,7 @@ class Term_Link_Indexing_Action extends Abstract_Link_Indexing_Action {
73
  * @return string The prepared query string.
74
  */
75
  protected function get_count_query() {
76
- $public_taxonomies = $this->taxonomy_helper->get_public_taxonomies();
77
  $placeholders = \implode( ', ', \array_fill( 0, \count( $public_taxonomies ), '%s' ) );
78
  $indexable_table = Model::get_table_name( 'Indexable' );
79
 
@@ -100,9 +100,10 @@ class Term_Link_Indexing_Action extends Abstract_Link_Indexing_Action {
100
  * @return string The prepared query string.
101
  */
102
  protected function get_select_query( $limit = false ) {
103
- $public_taxonomies = $this->taxonomy_helper->get_public_taxonomies();
104
- $indexable_table = Model::get_table_name( 'Indexable' );
105
- $replacements = $public_taxonomies;
 
106
 
107
  $limit_query = '';
108
  if ( $limit ) {
73
  * @return string The prepared query string.
74
  */
75
  protected function get_count_query() {
76
+ $public_taxonomies = $this->taxonomy_helper->get_indexable_taxonomies();
77
  $placeholders = \implode( ', ', \array_fill( 0, \count( $public_taxonomies ), '%s' ) );
78
  $indexable_table = Model::get_table_name( 'Indexable' );
79
 
100
  * @return string The prepared query string.
101
  */
102
  protected function get_select_query( $limit = false ) {
103
+ $public_taxonomies = $this->taxonomy_helper->get_indexable_taxonomies();
104
+
105
+ $indexable_table = Model::get_table_name( 'Indexable' );
106
+ $replacements = $public_taxonomies;
107
 
108
  $limit_query = '';
109
  if ( $limit ) {
src/builders/indexable-author-builder.php CHANGED
@@ -3,6 +3,7 @@
3
  namespace Yoast\WP\SEO\Builders;
4
 
5
  use wpdb;
 
6
  use Yoast\WP\SEO\Helpers\Author_Archive_Helper;
7
  use Yoast\WP\SEO\Helpers\Post_Helper;
8
  use Yoast\WP\SEO\Models\Indexable;
@@ -72,8 +73,15 @@ class Indexable_Author_Builder {
72
  * @param Indexable $indexable The indexable to format.
73
  *
74
  * @return Indexable The extended indexable.
 
 
75
  */
76
  public function build( $user_id, Indexable $indexable ) {
 
 
 
 
 
77
  $meta_data = $this->get_meta_data( $user_id );
78
 
79
  $indexable->object_id = $user_id;
@@ -190,4 +198,35 @@ class Indexable_Author_Builder {
190
  // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- We are using wpdb prepare.
191
  return $this->wpdb->get_row( $this->wpdb->prepare( $sql, $replacements ) );
192
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  }
3
  namespace Yoast\WP\SEO\Builders;
4
 
5
  use wpdb;
6
+ use Yoast\WP\SEO\Exceptions\Indexable\Author_Not_Built_Exception;
7
  use Yoast\WP\SEO\Helpers\Author_Archive_Helper;
8
  use Yoast\WP\SEO\Helpers\Post_Helper;
9
  use Yoast\WP\SEO\Models\Indexable;
73
  * @param Indexable $indexable The indexable to format.
74
  *
75
  * @return Indexable The extended indexable.
76
+ *
77
+ * @throws Author_Not_Built_Exception When author is not built.
78
  */
79
  public function build( $user_id, Indexable $indexable ) {
80
+ $exception = $this->check_if_user_should_be_indexed( $user_id );
81
+ if ( $exception ) {
82
+ throw $exception;
83
+ }
84
+
85
  $meta_data = $this->get_meta_data( $user_id );
86
 
87
  $indexable->object_id = $user_id;
198
  // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- We are using wpdb prepare.
199
  return $this->wpdb->get_row( $this->wpdb->prepare( $sql, $replacements ) );
200
  }
201
+
202
+ /**
203
+ * Checks if the user should be indexed.
204
+ * Returns an exception with an appropriate message if not.
205
+ *
206
+ * @param string $user_id The user id.
207
+ *
208
+ * @return Author_Not_Built_Exception|null The exception if it should not be indexed, or `null` if it should.
209
+ */
210
+ protected function check_if_user_should_be_indexed( $user_id ) {
211
+ $exception = null;
212
+
213
+ if ( $this->author_archive->are_disabled() ) {
214
+ $exception = Author_Not_Built_Exception::author_archives_are_disabled( $user_id );
215
+ }
216
+
217
+ // We will check if the author has public posts the WP way, instead of the indexable way, to make sure we get proper results even if SEO optimization is not run.
218
+ if ( $this->author_archive->author_has_public_posts_wp( $user_id ) === false ) {
219
+ $exception = Author_Not_Built_Exception::author_archives_are_not_indexed_for_users_without_posts( $user_id );
220
+ }
221
+
222
+ /**
223
+ * Filter: Include or exclude a user from being build and saved as an indexable.
224
+ * Return an `Author_Not_Built_Exception` when the indexable should not be build, with an appropriate message telling why it should not be built.
225
+ * Return `null` if the indexable should be build.
226
+ *
227
+ * @param Author_Not_Built_Exception|null $exception An exception if the indexable is not being built, `null` if the indexable should be built.
228
+ * @param string $user_id The ID of the user that should or should not be excluded.
229
+ */
230
+ return \apply_filters( 'wpseo_should_build_and_save_user_indexable', $exception, $user_id );
231
+ }
232
  }
src/builders/indexable-builder.php CHANGED
@@ -2,6 +2,7 @@
2
 
3
  namespace Yoast\WP\SEO\Builders;
4
 
 
5
  use Yoast\WP\SEO\Exceptions\Indexable\Source_Exception;
6
  use Yoast\WP\SEO\Helpers\Indexable_Helper;
7
  use Yoast\WP\SEO\Models\Indexable;
@@ -299,6 +300,32 @@ class Indexable_Builder {
299
  return $indexable;
300
  }
301
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
  /**
303
  * Rebuilds an Indexable from scratch.
304
  *
@@ -315,6 +342,9 @@ class Indexable_Builder {
315
  $indexable = $this->ensure_indexable( $indexable, $defaults );
316
 
317
  try {
 
 
 
318
  switch ( $indexable->object_type ) {
319
 
320
  case 'post':
@@ -330,19 +360,11 @@ class Indexable_Builder {
330
  // Always rebuild the hierarchy; this needs the primary term to run correctly.
331
  $this->hierarchy_builder->build( $indexable );
332
 
333
- // Rebuild the author indexable only when necessary.
334
- $author_indexable = $this->indexable_repository->find_by_id_and_type(
335
- $indexable->author_id,
336
- 'user',
337
- false
338
- );
339
- if ( ! $author_indexable || $this->version_manager->indexable_needs_upgrade( $author_indexable ) ) {
340
- $author_defaults = [
341
- 'object_type' => 'user',
342
- 'object_id' => $indexable->author_id,
343
- ];
344
- $this->build( $author_indexable, $author_defaults );
345
- }
346
  break;
347
 
348
  case 'user':
@@ -351,6 +373,7 @@ class Indexable_Builder {
351
 
352
  case 'term':
353
  $indexable = $this->term_builder->build( $indexable->object_id, $indexable );
 
354
  $this->hierarchy_builder->build( $indexable );
355
  break;
356
 
@@ -380,20 +403,26 @@ class Indexable_Builder {
380
  *
381
  * @var Indexable $indexable
382
  */
383
- $indexable = $this->indexable_repository
384
- ->query()
385
- ->create(
386
- [
387
- 'object_id' => $indexable->object_id,
388
- 'object_type' => $indexable->object_type,
389
- 'post_status' => 'unindexed',
390
- 'version' => 0,
391
- ]
392
- );
 
393
  // Make sure that the indexing process doesn't get stuck in a loop on this broken indexable.
394
  $indexable = $this->version_manager->set_latest( $indexable );
395
 
396
  return $this->save_indexable( $indexable, $indexable_before );
397
  }
 
 
 
398
  }
 
 
399
  }
2
 
3
  namespace Yoast\WP\SEO\Builders;
4
 
5
+ use Yoast\WP\SEO\Exceptions\Indexable\Not_Built_Exception;
6
  use Yoast\WP\SEO\Exceptions\Indexable\Source_Exception;
7
  use Yoast\WP\SEO\Helpers\Indexable_Helper;
8
  use Yoast\WP\SEO\Models\Indexable;
300
  return $indexable;
301
  }
302
 
303
+ /**
304
+ * Build and author indexable from an author id if it does not exist yet, or if the author indexable needs to be upgraded.
305
+ *
306
+ * @param int $author_id The author id.
307
+ *
308
+ * @return Indexable|false The author indexable if it has been built, `false` if it could not be built.
309
+ */
310
+ protected function maybe_build_author_indexable( $author_id ) {
311
+ $author_indexable = $this->indexable_repository->find_by_id_and_type(
312
+ $author_id,
313
+ 'user',
314
+ false
315
+ );
316
+ if ( ! $author_indexable || $this->version_manager->indexable_needs_upgrade( $author_indexable ) ) {
317
+ // Try to build the author.
318
+ $author_defaults = [
319
+ 'object_type' => 'user',
320
+ 'object_id' => $author_id,
321
+ ];
322
+ $author_indexable = $this->build( $author_indexable, $author_defaults );
323
+ }
324
+ return $author_indexable;
325
+ }
326
+
327
+ // phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.Missing -- Exceptions are handled by the catch statement in the method.
328
+
329
  /**
330
  * Rebuilds an Indexable from scratch.
331
  *
342
  $indexable = $this->ensure_indexable( $indexable, $defaults );
343
 
344
  try {
345
+ if ( $indexable->object_id === 0 ) {
346
+ throw Not_Built_Exception::invalid_object_id( $indexable->object_id );
347
+ }
348
  switch ( $indexable->object_type ) {
349
 
350
  case 'post':
360
  // Always rebuild the hierarchy; this needs the primary term to run correctly.
361
  $this->hierarchy_builder->build( $indexable );
362
 
363
+ // Save indexable, to make sure that it can be queried when determining if an author has public posts.
364
+ $indexable = $this->save_indexable( $indexable, $indexable_before );
365
+
366
+ $this->maybe_build_author_indexable( $indexable->author_id );
367
+
 
 
 
 
 
 
 
 
368
  break;
369
 
370
  case 'user':
373
 
374
  case 'term':
375
  $indexable = $this->term_builder->build( $indexable->object_id, $indexable );
376
+
377
  $this->hierarchy_builder->build( $indexable );
378
  break;
379
 
403
  *
404
  * @var Indexable $indexable
405
  */
406
+ $indexable = $this->ensure_indexable(
407
+ $indexable,
408
+ [
409
+ 'object_id' => $indexable->object_id,
410
+ 'object_type' => $indexable->object_type,
411
+ 'post_status' => 'unindexed',
412
+ 'version' => 0,
413
+ ]
414
+ );
415
+ // If we already had an existing indexable, mark it as unindexed. We cannot rely on its validity anymore.
416
+ $indexable->post_status = 'unindexed';
417
  // Make sure that the indexing process doesn't get stuck in a loop on this broken indexable.
418
  $indexable = $this->version_manager->set_latest( $indexable );
419
 
420
  return $this->save_indexable( $indexable, $indexable_before );
421
  }
422
+ catch ( Not_Built_Exception $exception ) {
423
+ return false;
424
+ }
425
  }
426
+
427
+ // phpcs:enable
428
  }
src/builders/indexable-post-builder.php CHANGED
@@ -11,6 +11,7 @@ use Yoast\WP\SEO\Helpers\Post_Type_Helper;
11
  use Yoast\WP\SEO\Models\Indexable;
12
  use Yoast\WP\SEO\Repositories\Indexable_Repository;
13
  use Yoast\WP\SEO\Values\Indexables\Indexable_Builder_Versions;
 
14
 
15
  /**
16
  * Post Builder for the indexables.
@@ -96,10 +97,11 @@ class Indexable_Post_Builder {
96
  * @return bool|Indexable The extended indexable. False when unable to build.
97
  *
98
  * @throws Post_Not_Found_Exception When the post could not be found.
 
99
  */
100
  public function build( $post_id, $indexable ) {
101
  if ( ! $this->post_helper->is_post_indexable( $post_id ) ) {
102
- return false;
103
  }
104
 
105
  $post = $this->post_helper->get_post( $post_id );
@@ -109,7 +111,7 @@ class Indexable_Post_Builder {
109
  }
110
 
111
  if ( $this->should_exclude_post( $post ) ) {
112
- return false;
113
  }
114
 
115
  $indexable->object_id = $post_id;
11
  use Yoast\WP\SEO\Models\Indexable;
12
  use Yoast\WP\SEO\Repositories\Indexable_Repository;
13
  use Yoast\WP\SEO\Values\Indexables\Indexable_Builder_Versions;
14
+ use Yoast\WP\SEO\Exceptions\Indexable\Post_Not_Built_Exception;
15
 
16
  /**
17
  * Post Builder for the indexables.
97
  * @return bool|Indexable The extended indexable. False when unable to build.
98
  *
99
  * @throws Post_Not_Found_Exception When the post could not be found.
100
+ * @throws Post_Not_Built_Exception When the post should not be indexed.
101
  */
102
  public function build( $post_id, $indexable ) {
103
  if ( ! $this->post_helper->is_post_indexable( $post_id ) ) {
104
+ throw Post_Not_Built_Exception::because_not_indexable( $post_id );
105
  }
106
 
107
  $post = $this->post_helper->get_post( $post_id );
111
  }
112
 
113
  if ( $this->should_exclude_post( $post ) ) {
114
+ throw Post_Not_Built_Exception::because_post_type_excluded( $post_id );
115
  }
116
 
117
  $indexable->object_id = $post_id;
src/builders/indexable-term-builder.php CHANGED
@@ -5,6 +5,7 @@ namespace Yoast\WP\SEO\Builders;
5
  use wpdb;
6
  use Yoast\WP\SEO\Exceptions\Indexable\Invalid_Term_Exception;
7
  use Yoast\WP\SEO\Exceptions\Indexable\Term_Not_Found_Exception;
 
8
  use Yoast\WP\SEO\Helpers\Post_Helper;
9
  use Yoast\WP\SEO\Helpers\Taxonomy_Helper;
10
  use Yoast\WP\SEO\Models\Indexable;
@@ -75,7 +76,8 @@ class Indexable_Term_Builder {
75
  *
76
  * @return bool|Indexable The extended indexable. False when unable to build.
77
  *
78
- * @throws Invalid_Term_Exception When the term is invalid.
 
79
  * @throws Term_Not_Found_Exception When the term is not found.
80
  */
81
  public function build( $term_id, $indexable ) {
@@ -89,6 +91,11 @@ class Indexable_Term_Builder {
89
  throw new Invalid_Term_Exception( $term->get_error_message() );
90
  }
91
 
 
 
 
 
 
92
  $term_link = \get_term_link( $term, $term->taxonomy );
93
 
94
  if ( \is_wp_error( $term_link ) ) {
5
  use wpdb;
6
  use Yoast\WP\SEO\Exceptions\Indexable\Invalid_Term_Exception;
7
  use Yoast\WP\SEO\Exceptions\Indexable\Term_Not_Found_Exception;
8
+ use Yoast\WP\SEO\Exceptions\Indexable\Term_Not_Built_Exception;
9
  use Yoast\WP\SEO\Helpers\Post_Helper;
10
  use Yoast\WP\SEO\Helpers\Taxonomy_Helper;
11
  use Yoast\WP\SEO\Models\Indexable;
76
  *
77
  * @return bool|Indexable The extended indexable. False when unable to build.
78
  *
79
+ * @throws Invalid_Term_Exception When the term is invalid.
80
+ * @throws Term_Not_Built_Exception When the term is not viewable.
81
  * @throws Term_Not_Found_Exception When the term is not found.
82
  */
83
  public function build( $term_id, $indexable ) {
91
  throw new Invalid_Term_Exception( $term->get_error_message() );
92
  }
93
 
94
+ $indexable_taxonomies = $this->taxonomy_helper->get_indexable_taxonomies();
95
+ if ( ! \in_array( $term->taxonomy, $indexable_taxonomies, true ) ) {
96
+ throw Term_Not_Built_Exception::because_not_indexable( $term_id );
97
+ }
98
+
99
  $term_link = \get_term_link( $term, $term->taxonomy );
100
 
101
  if ( \is_wp_error( $term_link ) ) {
src/commands/cleanup-command.php ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Yoast\WP\SEO\Commands;
4
+
5
+ use WP_CLI\ExitException;
6
+ use Yoast\WP\SEO\Integrations\Cleanup_Integration;
7
+ use Yoast\WP\SEO\Main;
8
+ use function get_sites;
9
+ use function WP_CLI\Utils\make_progress_bar;
10
+
11
+ /**
12
+ * A WP CLI command that helps with cleaning up unwanted records from our custom tables.
13
+ */
14
+ final class Cleanup_Command implements Command_Interface {
15
+
16
+ /**
17
+ * The integration that cleans up on cron.
18
+ *
19
+ * @var Cleanup_Integration
20
+ */
21
+ private $cleanup_integration;
22
+
23
+ /**
24
+ * The constructor.
25
+ *
26
+ * @param Cleanup_Integration $cleanup_integration The integration that cleans up on cron.
27
+ */
28
+ public function __construct( Cleanup_Integration $cleanup_integration ) {
29
+ $this->cleanup_integration = $cleanup_integration;
30
+ }
31
+
32
+ /**
33
+ * Returns the namespace of this command.
34
+ *
35
+ * @return string
36
+ */
37
+ public static function get_namespace() {
38
+ return Main::WP_CLI_NAMESPACE;
39
+ }
40
+
41
+ /**
42
+ * Performs a cleanup of custom Yoast tables.
43
+ *
44
+ * This removes unused, unwanted or orphaned database records, which ensures the best performance. Including:
45
+ * - Indexables
46
+ * - Indexable hierarchy
47
+ * - SEO links
48
+ *
49
+ * ## OPTIONS
50
+ *
51
+ * [--batch-size=<batch-size>]
52
+ * : The number of database records to clean up in a single sql query.
53
+ * ---
54
+ * default: 1000
55
+ * ---
56
+ *
57
+ * [--interval=<interval>]
58
+ * : The number of microseconds (millionths of a second) to wait between cleanup batches.
59
+ * ---
60
+ * default: 500000
61
+ * ---
62
+ *
63
+ * [--network]
64
+ * : Performs the cleanup on all sites within the network.
65
+ *
66
+ * ## EXAMPLES
67
+ *
68
+ * wp yoast cleanup
69
+ *
70
+ * @when after_wp_load
71
+ *
72
+ * @param array|null $args The arguments.
73
+ * @param array|null $assoc_args The associative arguments.
74
+ *
75
+ * @return void
76
+ *
77
+ * @throws ExitException When the input args are invalid.
78
+ */
79
+ public function cleanup( $args = null, $assoc_args = null ) {
80
+ if ( isset( $assoc_args['interval'] ) && (int) $assoc_args['interval'] < 0 ) {
81
+ \WP_CLI::error( __( 'The value for \'interval\' must be a positive integer.', 'wordpress-seo' ) );
82
+ }
83
+ if ( isset( $assoc_args['batch-size'] ) && (int) $assoc_args['batch-size'] < 1 ) {
84
+ \WP_CLI::error( __( 'The value for \'batch-size\' must be a positive integer higher than equal to 1.', 'wordpress-seo' ) );
85
+ }
86
+
87
+ if ( isset( $assoc_args['network'] ) && \is_multisite() ) {
88
+ $total_removed = $this->cleanup_network( $assoc_args );
89
+ }
90
+ else {
91
+ $total_removed = $this->cleanup_current_site( $assoc_args );
92
+ }
93
+
94
+ \WP_CLI::success(
95
+ \sprintf(
96
+ /* translators: %1$d is the number of records that are removed. */
97
+ \_n(
98
+ 'Cleaned up %1$d record.',
99
+ 'Cleaned up %1$d records.',
100
+ $total_removed,
101
+ 'wordpress-seo'
102
+ ),
103
+ $total_removed
104
+ )
105
+ );
106
+ }
107
+
108
+ /**
109
+ * Performs the cleanup for the entire network.
110
+ *
111
+ * @param array|null $assoc_args The associative arguments.
112
+ *
113
+ * @return int The number of cleaned up records.
114
+ */
115
+ private function cleanup_network( $assoc_args ) {
116
+ $criteria = [
117
+ 'fields' => 'ids',
118
+ 'spam' => 0,
119
+ 'deleted' => 0,
120
+ 'archived' => 0,
121
+ ];
122
+ $blog_ids = \get_sites( $criteria );
123
+ $total_removed = 0;
124
+ foreach ( $blog_ids as $blog_id ) {
125
+ \switch_to_blog( $blog_id );
126
+ $total_removed += $this->cleanup_current_site( $assoc_args );
127
+ \restore_current_blog();
128
+ }
129
+
130
+ return $total_removed;
131
+ }
132
+
133
+ /**
134
+ * Performs the cleanup for a single site.
135
+ *
136
+ * @param array|null $assoc_args The associative arguments.
137
+ *
138
+ * @return int The number of cleaned up records.
139
+ */
140
+ private function cleanup_current_site( $assoc_args ) {
141
+ $site_url = \site_url();
142
+ $total_removed = 0;
143
+
144
+ if ( ! \is_plugin_active( WPSEO_BASENAME ) ) {
145
+ /* translators: %1$s is the site url of the site that is skipped. %2$s is Yoast SEO. */
146
+ \WP_CLI::warning( \sprintf( \__( 'Skipping %1$s. %2$s is not active on this site.', 'wordpress-seo' ), $site_url, 'Yoast SEO' ) );
147
+
148
+ return $total_removed;
149
+ }
150
+
151
+ // Make sure the DB is up to date first.
152
+ \do_action( '_yoast_run_migrations' );
153
+
154
+ $tasks = $this->cleanup_integration->get_cleanup_tasks();
155
+ $limit = (int) $assoc_args['batch-size'];
156
+ $interval = (int) $assoc_args['interval'];
157
+
158
+ /* translators: %1$s is the site url of the site that is cleaned up. %2$s is the name of the cleanup task that is currently running. */
159
+ $progress_bar_title_format = \__( 'Cleaning up %1$s [%2$s]', 'wordpress-seo' );
160
+ $progress = make_progress_bar( \sprintf( $progress_bar_title_format, $site_url, \key( $tasks ) ), count( $tasks ) );
161
+
162
+ foreach ( $tasks as $task_name => $task ) {
163
+ // Update the progressbar title with the current task name.
164
+ $progress->tick( 0, \sprintf( $progress_bar_title_format, $site_url, $task_name ) );
165
+ do {
166
+ $items_cleaned = $task( $limit );
167
+ if ( \is_int( $items_cleaned ) ) {
168
+ $total_removed += $items_cleaned;
169
+ }
170
+ \usleep( $interval );
171
+
172
+ // Update the timer.
173
+ $progress->tick( 0 );
174
+ } while ( $items_cleaned !== false && $items_cleaned > 0 );
175
+ $progress->tick();
176
+ }
177
+ $progress->finish();
178
+
179
+ $this->cleanup_integration->reset_cleanup();
180
+ \WP_CLI::log(
181
+ \sprintf(
182
+ /* translators: %1$d is the number of records that were removed. %2$s is the site url. */
183
+ \_n(
184
+ 'Cleaned up %1$d record from %2$s.',
185
+ 'Cleaned up %1$d records from %2$s.',
186
+ $total_removed,
187
+ 'wordpress-seo'
188
+ ),
189
+ $total_removed,
190
+ $site_url
191
+ )
192
+ );
193
+
194
+ return $total_removed;
195
+ }
196
+ }
src/config/indexing-reasons.php CHANGED
@@ -31,4 +31,14 @@ class Indexing_Reasons {
31
  * Represents the reason that the home url option is changed.
32
  */
33
  const REASON_HOME_URL_OPTION = 'home_url_option_changed';
 
 
 
 
 
 
 
 
 
 
34
  }
31
  * Represents the reason that the home url option is changed.
32
  */
33
  const REASON_HOME_URL_OPTION = 'home_url_option_changed';
34
+
35
+ /**
36
+ * Represents the reason that a post type has been made public.
37
+ */
38
+ const REASON_POST_TYPE_MADE_PUBLIC = 'post_type_made_public';
39
+
40
+ /**
41
+ * Represents the reason that a post type has been made viewable.
42
+ */
43
+ const REASON_TAXONOMY_MADE_PUBLIC = 'taxonomy_made_public';
44
  }
src/exceptions/indexable/author-not-built-exception.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Yoast\WP\SEO\Exceptions\Indexable;
4
+
5
+ /**
6
+ * For when an author indexable is not being built.
7
+ */
8
+ class Author_Not_Built_Exception extends Not_Built_Exception {
9
+
10
+ /**
11
+ * Named constructor for creating an Author_Not_Built_Exception
12
+ * when author archives are disabled for users without posts.
13
+ *
14
+ * @param string $user_id The user id.
15
+ *
16
+ * @return Author_Not_Built_Exception The exception.
17
+ */
18
+ public static function author_archives_are_not_indexed_for_users_without_posts( $user_id ) {
19
+ return new Author_Not_Built_Exception(
20
+ 'Indexable for author with id ' . $user_id . ' is not being built, since author archives are not indexed for users without posts.'
21
+ );
22
+ }
23
+
24
+ /**
25
+ * Named constructor for creating an Author_Not_Built_Exception
26
+ * when author archives are disabled.
27
+ *
28
+ * @param string $user_id The user id.
29
+ *
30
+ * @return Author_Not_Built_Exception The exception.
31
+ */
32
+ public static function author_archives_are_disabled( $user_id ) {
33
+ return new Author_Not_Built_Exception(
34
+ 'Indexable for author with id ' . $user_id . ' is not being built, since author archives are disabled.'
35
+ );
36
+ }
37
+
38
+ /**
39
+ * Named constructor for creating an Author_Not_Build_Exception
40
+ * when an author is excluded because of the `'wpseo_should_build_and_save_user_indexable'` filter.
41
+ *
42
+ * @param string $user_id The user id.
43
+ *
44
+ * @return Author_Not_Built_Exception The exception.
45
+ */
46
+ public static function author_not_built_because_of_filter( $user_id ) {
47
+ return new Author_Not_Built_Exception(
48
+ 'Indexable for author with id ' . $user_id . ' is not being built, since it is excluded because of the \'wpseo_should_build_and_save_user_indexable\' filter.'
49
+ );
50
+ }
51
+ }
src/exceptions/indexable/not-built-exception.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Yoast\WP\SEO\Exceptions\Indexable;
4
+
5
+ /**
6
+ * Class Not_Built_Exception
7
+ */
8
+ class Not_Built_Exception extends Indexable_Exception {
9
+
10
+ /**
11
+ * Creates an exception that should be thrown when an indexable
12
+ * was not built because of an invalid object id.
13
+ *
14
+ * @param int $object_id The invalid object id.
15
+ *
16
+ * @return Not_Built_Exception The exception.
17
+ */
18
+ public static function invalid_object_id( $object_id ) {
19
+ return new Not_Built_Exception(
20
+ "Indexable was not built because it had an invalid object id of $object_id."
21
+ );
22
+ }
23
+ }
src/exceptions/indexable/post-not-built-exception.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Yoast\WP\SEO\Exceptions\Indexable;
4
+
5
+ /**
6
+ * Exception that is thrown whenever a post could not be built
7
+ * in the context of the indexables.
8
+ */
9
+ class Post_Not_Built_Exception extends Not_Built_Exception {
10
+
11
+ /**
12
+ * Throws an exception if the post is not indexable.
13
+ *
14
+ * @param int $post_id ID of the post.
15
+ *
16
+ * @throws Post_Not_Built_Exception When the post is not indexable.
17
+ */
18
+ public static function because_not_indexable( $post_id ) {
19
+ /* translators: %s: expands to the post id */
20
+ return new Post_Not_Built_Exception( sprintf( __( 'The post %s could not be indexed because it does not meet indexing requirements.', 'wordpress-seo' ), $post_id ) );
21
+ }
22
+
23
+ /**
24
+ * Throws an exception if the post type is excluded from indexing.
25
+ *
26
+ * @param int $post_id ID of the post.
27
+ *
28
+ * @throws Post_Not_Built_Exception When the post type is excluded.
29
+ */
30
+ public static function because_post_type_excluded( $post_id ) {
31
+ /* translators: %s: expands to the post id */
32
+ return new Post_Not_Built_Exception( sprintf( __( 'The post %s could not be indexed because it\'s post type is excluded from indexing.', 'wordpress-seo' ), $post_id ) );
33
+ }
34
+ }
src/exceptions/indexable/term-not-built-exception.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Yoast\WP\SEO\Exceptions\Indexable;
4
+
5
+ /**
6
+ * Exception that is thrown whenever a term could not be built
7
+ * in the context of the indexables.
8
+ */
9
+ class Term_Not_Built_Exception extends Not_Built_Exception {
10
+
11
+ /**
12
+ * Throws an exception if the term is not indexable.
13
+ *
14
+ * @param int $term_id ID of the term.
15
+ *
16
+ * @throws Term_Not_Built_Exception When the term is not built.
17
+ */
18
+ public static function because_not_indexable( $term_id ) {
19
+ /* translators: %s: expands to the term id */
20
+ return new Term_Not_Built_Exception( sprintf( __( 'The term %s could not be built because it\'s not indexable.', 'wordpress-seo' ), $term_id ) );
21
+ }
22
+ }
src/generated/container.php CHANGED
@@ -75,6 +75,7 @@ class Cached_Container extends Container
75
  'yoast\\wp\\seo\\builders\\indexable_system_page_builder' => 'Yoast\\WP\\SEO\\Builders\\Indexable_System_Page_Builder',
76
  'yoast\\wp\\seo\\builders\\indexable_term_builder' => 'Yoast\\WP\\SEO\\Builders\\Indexable_Term_Builder',
77
  'yoast\\wp\\seo\\builders\\primary_term_builder' => 'Yoast\\WP\\SEO\\Builders\\Primary_Term_Builder',
 
78
  'yoast\\wp\\seo\\commands\\index_command' => 'Yoast\\WP\\SEO\\Commands\\Index_Command',
79
  'yoast\\wp\\seo\\conditionals\\addon_installation_conditional' => 'Yoast\\WP\\SEO\\Conditionals\\Addon_Installation_Conditional',
80
  'yoast\\wp\\seo\\conditionals\\admin\\doing_post_quick_edit_save_conditional' => 'Yoast\\WP\\SEO\\Conditionals\\Admin\\Doing_Post_Quick_Edit_Save_Conditional',
@@ -256,6 +257,7 @@ class Cached_Container extends Container
256
  'yoast\\wp\\seo\\integrations\\admin\\health_check_integration' => 'Yoast\\WP\\SEO\\Integrations\\Admin\\Health_Check_Integration',
257
  'yoast\\wp\\seo\\integrations\\admin\\helpscout_beacon' => 'Yoast\\WP\\SEO\\Integrations\\Admin\\HelpScout_Beacon',
258
  'yoast\\wp\\seo\\integrations\\admin\\import_integration' => 'Yoast\\WP\\SEO\\Integrations\\Admin\\Import_Integration',
 
259
  'yoast\\wp\\seo\\integrations\\admin\\indexables_page_integration' => 'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Page_Integration',
260
  'yoast\\wp\\seo\\integrations\\admin\\indexing_notification_integration' => 'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Notification_Integration',
261
  'yoast\\wp\\seo\\integrations\\admin\\indexing_tool_integration' => 'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Tool_Integration',
@@ -321,6 +323,7 @@ class Cached_Container extends Container
321
  'yoast\\wp\\seo\\integrations\\watchers\\addon_update_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Addon_Update_Watcher',
322
  'yoast\\wp\\seo\\integrations\\watchers\\auto_update_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Auto_Update_Watcher',
323
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_ancestor_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Ancestor_Watcher',
 
324
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_author_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Watcher',
325
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_category_permalink_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Category_Permalink_Watcher',
326
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_date_archive_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Date_Archive_Watcher',
@@ -329,9 +332,11 @@ class Cached_Container extends Container
329
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_permalink_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Permalink_Watcher',
330
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_post_meta_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Meta_Watcher',
331
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_post_type_archive_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Archive_Watcher',
 
332
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_post_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Watcher',
333
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_static_home_page_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Static_Home_Page_Watcher',
334
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_system_page_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_System_Page_Watcher',
 
335
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_term_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Term_Watcher',
336
  'yoast\\wp\\seo\\integrations\\watchers\\option_titles_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Titles_Watcher',
337
  'yoast\\wp\\seo\\integrations\\watchers\\option_wpseo_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Wpseo_Watcher',
@@ -462,6 +467,7 @@ class Cached_Container extends Container
462
  'Yoast\\WP\\SEO\\Builders\\Indexable_System_Page_Builder' => 'getIndexableSystemPageBuilderService',
463
  'Yoast\\WP\\SEO\\Builders\\Indexable_Term_Builder' => 'getIndexableTermBuilderService',
464
  'Yoast\\WP\\SEO\\Builders\\Primary_Term_Builder' => 'getPrimaryTermBuilderService',
 
465
  'Yoast\\WP\\SEO\\Commands\\Index_Command' => 'getIndexCommandService',
466
  'Yoast\\WP\\SEO\\Conditionals\\Addon_Installation_Conditional' => 'getAddonInstallationConditionalService',
467
  'Yoast\\WP\\SEO\\Conditionals\\Admin\\Doing_Post_Quick_Edit_Save_Conditional' => 'getDoingPostQuickEditSaveConditionalService',
@@ -643,6 +649,7 @@ class Cached_Container extends Container
643
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Health_Check_Integration' => 'getHealthCheckIntegrationService',
644
  'Yoast\\WP\\SEO\\Integrations\\Admin\\HelpScout_Beacon' => 'getHelpScoutBeaconService',
645
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Import_Integration' => 'getImportIntegrationService',
 
646
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Page_Integration' => 'getIndexablesPageIntegrationService',
647
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Notification_Integration' => 'getIndexingNotificationIntegrationService',
648
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Tool_Integration' => 'getIndexingToolIntegrationService',
@@ -708,6 +715,7 @@ class Cached_Container extends Container
708
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Addon_Update_Watcher' => 'getAddonUpdateWatcherService',
709
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Auto_Update_Watcher' => 'getAutoUpdateWatcherService',
710
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Ancestor_Watcher' => 'getIndexableAncestorWatcherService',
 
711
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Watcher' => 'getIndexableAuthorWatcherService',
712
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Category_Permalink_Watcher' => 'getIndexableCategoryPermalinkWatcherService',
713
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Date_Archive_Watcher' => 'getIndexableDateArchiveWatcherService',
@@ -716,9 +724,11 @@ class Cached_Container extends Container
716
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Permalink_Watcher' => 'getIndexablePermalinkWatcherService',
717
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Meta_Watcher' => 'getIndexablePostMetaWatcherService',
718
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Archive_Watcher' => 'getIndexablePostTypeArchiveWatcherService',
 
719
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Watcher' => 'getIndexablePostWatcherService',
720
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Static_Home_Page_Watcher' => 'getIndexableStaticHomePageWatcherService',
721
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_System_Page_Watcher' => 'getIndexableSystemPageWatcherService',
 
722
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Term_Watcher' => 'getIndexableTermWatcherService',
723
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Titles_Watcher' => 'getOptionTitlesWatcherService',
724
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Wpseo_Watcher' => 'getOptionWpseoWatcherService',
@@ -813,7 +823,6 @@ class Cached_Container extends Container
813
  'Psr\\Container\\ContainerInterface' => true,
814
  'YoastSEO_Vendor\\Symfony\\Component\\DependencyInjection\\ContainerInterface' => true,
815
  'YoastSEO_Vendor\\YoastSEO_Vendor\\Symfony\\Component\\DependencyInjection\\ContainerInterface' => true,
816
- 'Yoast\\WP\\SEO\\Commands\\Command_Interface' => true,
817
  'wpdb' => true,
818
  ];
819
  }
@@ -1343,7 +1352,7 @@ class Cached_Container extends Container
1343
  return $this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Author_Builder'];
1344
  }
1345
 
1346
- $this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Author_Builder'] = $instance = new \Yoast\WP\SEO\Builders\Indexable_Author_Builder(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper'] = new \Yoast\WP\SEO\Helpers\Author_Archive_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Values\\Indexables\\Indexable_Builder_Versions']) ? $this->services['Yoast\\WP\\SEO\\Values\\Indexables\\Indexable_Builder_Versions'] : ($this->services['Yoast\\WP\\SEO\\Values\\Indexables\\Indexable_Builder_Versions'] = new \Yoast\WP\SEO\Values\Indexables\Indexable_Builder_Versions())) && false ?: '_'}, $a, ${($_ = isset($this->services['wpdb']) ? $this->services['wpdb'] : $this->getWpdbService()) && false ?: '_'});
1347
 
1348
  $instance->set_social_image_helpers(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Image_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Image_Helper'] : $this->getImageHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Open_Graph\\Image_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Open_Graph\\Image_Helper'] : $this->getImageHelper2Service()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Twitter\\Image_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Twitter\\Image_Helper'] : $this->getImageHelper4Service()) && false ?: '_'});
1349
 
@@ -1552,6 +1561,16 @@ class Cached_Container extends Container
1552
  return $this->services['Yoast\\WP\\SEO\\Builders\\Primary_Term_Builder'] = new \Yoast\WP\SEO\Builders\Primary_Term_Builder(${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Primary_Term_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Primary_Term_Repository'] : ($this->services['Yoast\\WP\\SEO\\Repositories\\Primary_Term_Repository'] = new \Yoast\WP\SEO\Repositories\Primary_Term_Repository())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Primary_Term_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Primary_Term_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Primary_Term_Helper'] = new \Yoast\WP\SEO\Helpers\Primary_Term_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Meta_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Meta_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Meta_Helper'] = new \Yoast\WP\SEO\Helpers\Meta_Helper())) && false ?: '_'});
1553
  }
1554
 
 
 
 
 
 
 
 
 
 
 
1555
  /**
1556
  * Gets the public 'Yoast\WP\SEO\Commands\Index_Command' shared autowired service.
1557
  *
@@ -2673,7 +2692,7 @@ class Cached_Container extends Container
2673
  */
2674
  protected function getAuthorArchiveHelperService()
2675
  {
2676
- return $this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper'] = new \Yoast\WP\SEO\Helpers\Author_Archive_Helper();
2677
  }
2678
 
2679
  /**
@@ -2940,7 +2959,7 @@ class Cached_Container extends Container
2940
  */
2941
  protected function getPostHelperService()
2942
  {
2943
- $this->services['Yoast\\WP\\SEO\\Helpers\\Post_Helper'] = $instance = new \Yoast\WP\SEO\Helpers\Post_Helper(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\String_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\String_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\String_Helper'] = new \Yoast\WP\SEO\Helpers\String_Helper())) && false ?: '_'});
2944
 
2945
  $instance->set_indexable_repository(${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository'] : $this->getIndexableRepositoryService()) && false ?: '_'});
2946
 
@@ -3403,6 +3422,16 @@ class Cached_Container extends Container
3403
  return $this->services['Yoast\\WP\\SEO\\Integrations\\Admin\\Import_Integration'] = new \Yoast\WP\SEO\Integrations\Admin\Import_Integration(${($_ = isset($this->services['WPSEO_Admin_Asset_Manager']) ? $this->services['WPSEO_Admin_Asset_Manager'] : $this->getWPSEOAdminAssetManagerService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Services\\Importing\\Importable_Detector_Service']) ? $this->services['Yoast\\WP\\SEO\\Services\\Importing\\Importable_Detector_Service'] : $this->getImportableDetectorServiceService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Routes\\Importing_Route']) ? $this->services['Yoast\\WP\\SEO\\Routes\\Importing_Route'] : $this->getImportingRouteService()) && false ?: '_'});
3404
  }
3405
 
 
 
 
 
 
 
 
 
 
 
3406
  /**
3407
  * Gets the public 'Yoast\WP\SEO\Integrations\Admin\Indexables_Page_Integration' shared autowired service.
3408
  *
@@ -3590,7 +3619,7 @@ class Cached_Container extends Container
3590
  */
3591
  protected function getCleanupIntegrationService()
3592
  {
3593
- return $this->services['Yoast\\WP\\SEO\\Integrations\\Cleanup_Integration'] = new \Yoast\WP\SEO\Integrations\Cleanup_Integration();
3594
  }
3595
 
3596
  /**
@@ -4075,6 +4104,16 @@ class Cached_Container extends Container
4075
  return $this->services['Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Ancestor_Watcher'] = new \Yoast\WP\SEO\Integrations\Watchers\Indexable_Ancestor_Watcher(${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository'] : $this->getIndexableRepositoryService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Hierarchy_Builder']) ? $this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Hierarchy_Builder'] : $this->getIndexableHierarchyBuilderService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Hierarchy_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Hierarchy_Repository'] : $this->getIndexableHierarchyRepositoryService()) && false ?: '_'}, ${($_ = isset($this->services['wpdb']) ? $this->services['wpdb'] : $this->getWpdbService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Permalink_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Permalink_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Permalink_Helper'] = new \Yoast\WP\SEO\Helpers\Permalink_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper'] : $this->getPostTypeHelperService()) && false ?: '_'});
4076
  }
4077
 
 
 
 
 
 
 
 
 
 
 
4078
  /**
4079
  * Gets the public 'Yoast\WP\SEO\Integrations\Watchers\Indexable_Author_Watcher' shared autowired service.
4080
  *
@@ -4155,6 +4194,16 @@ class Cached_Container extends Container
4155
  return $this->services['Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Archive_Watcher'] = new \Yoast\WP\SEO\Integrations\Watchers\Indexable_Post_Type_Archive_Watcher(${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository'] : $this->getIndexableRepositoryService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Builder']) ? $this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Builder'] : $this->getIndexableBuilderService()) && false ?: '_'});
4156
  }
4157
 
 
 
 
 
 
 
 
 
 
 
4158
  /**
4159
  * Gets the public 'Yoast\WP\SEO\Integrations\Watchers\Indexable_Post_Watcher' shared autowired service.
4160
  *
@@ -4162,7 +4211,7 @@ class Cached_Container extends Container
4162
  */
4163
  protected function getIndexablePostWatcherService()
4164
  {
4165
- return $this->services['Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Watcher'] = new \Yoast\WP\SEO\Integrations\Watchers\Indexable_Post_Watcher(${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository'] : $this->getIndexableRepositoryService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Builder']) ? $this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Builder'] : $this->getIndexableBuilderService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Hierarchy_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Hierarchy_Repository'] : $this->getIndexableHierarchyRepositoryService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Link_Builder']) ? $this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Link_Builder'] : $this->getIndexableLinkBuilderService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper'] = new \Yoast\WP\SEO\Helpers\Author_Archive_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Post_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Post_Helper'] : $this->getPostHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Loggers\\Logger']) ? $this->services['Yoast\\WP\\SEO\\Loggers\\Logger'] : ($this->services['Yoast\\WP\\SEO\\Loggers\\Logger'] = new \Yoast\WP\SEO\Loggers\Logger())) && false ?: '_'});
4166
  }
4167
 
4168
  /**
@@ -4185,6 +4234,16 @@ class Cached_Container extends Container
4185
  return $this->services['Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_System_Page_Watcher'] = new \Yoast\WP\SEO\Integrations\Watchers\Indexable_System_Page_Watcher(${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository'] : $this->getIndexableRepositoryService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Builder']) ? $this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Builder'] : $this->getIndexableBuilderService()) && false ?: '_'});
4186
  }
4187
 
 
 
 
 
 
 
 
 
 
 
4188
  /**
4189
  * Gets the public 'Yoast\WP\SEO\Integrations\Watchers\Indexable_Term_Watcher' shared autowired service.
4190
  *
@@ -4264,6 +4323,7 @@ class Cached_Container extends Container
4264
  {
4265
  $this->services['Yoast\\WP\\SEO\\Loader'] = $instance = new \Yoast\WP\SEO\Loader($this);
4266
 
 
4267
  $instance->register_command('Yoast\\WP\\SEO\\Commands\\Index_Command');
4268
  $instance->register_migration('free', '20171228151840', 'Yoast\\WP\\SEO\\Config\\Migrations\\WpYoastIndexable');
4269
  $instance->register_migration('free', '20171228151841', 'Yoast\\WP\\SEO\\Config\\Migrations\\WpYoastPrimaryTerm');
@@ -4305,6 +4365,7 @@ class Cached_Container extends Container
4305
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Admin\\Health_Check_Integration');
4306
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Admin\\HelpScout_Beacon');
4307
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Admin\\Import_Integration');
 
4308
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Page_Integration');
4309
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Notification_Integration');
4310
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Tool_Integration');
@@ -4368,6 +4429,7 @@ class Cached_Container extends Container
4368
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Addon_Update_Watcher');
4369
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Auto_Update_Watcher');
4370
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Ancestor_Watcher');
 
4371
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Watcher');
4372
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Category_Permalink_Watcher');
4373
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Date_Archive_Watcher');
@@ -4376,9 +4438,11 @@ class Cached_Container extends Container
4376
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Permalink_Watcher');
4377
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Meta_Watcher');
4378
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Archive_Watcher');
 
4379
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Watcher');
4380
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Static_Home_Page_Watcher');
4381
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_System_Page_Watcher');
 
4382
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Term_Watcher');
4383
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Titles_Watcher');
4384
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Wpseo_Watcher');
@@ -4450,7 +4514,7 @@ class Cached_Container extends Container
4450
  */
4451
  protected function getIndexableAuthorArchivePresentationService()
4452
  {
4453
- $this->services['Yoast\\WP\\SEO\\Presentations\\Indexable_Author_Archive_Presentation'] = $instance = new \Yoast\WP\SEO\Presentations\Indexable_Author_Archive_Presentation(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper'] : $this->getPostTypeHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper'] = new \Yoast\WP\SEO\Helpers\Author_Archive_Helper())) && false ?: '_'});
4454
 
4455
  $instance->set_generators(${($_ = isset($this->services['Yoast\\WP\\SEO\\Generators\\Schema_Generator']) ? $this->services['Yoast\\WP\\SEO\\Generators\\Schema_Generator'] : $this->getSchemaGeneratorService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Generators\\Open_Graph_Locale_Generator']) ? $this->services['Yoast\\WP\\SEO\\Generators\\Open_Graph_Locale_Generator'] : ($this->services['Yoast\\WP\\SEO\\Generators\\Open_Graph_Locale_Generator'] = new \Yoast\WP\SEO\Generators\Open_Graph_Locale_Generator())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Generators\\Open_Graph_Image_Generator']) ? $this->services['Yoast\\WP\\SEO\\Generators\\Open_Graph_Image_Generator'] : $this->getOpenGraphImageGeneratorService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Generators\\Twitter_Image_Generator']) ? $this->services['Yoast\\WP\\SEO\\Generators\\Twitter_Image_Generator'] : $this->getTwitterImageGeneratorService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Generators\\Breadcrumbs_Generator']) ? $this->services['Yoast\\WP\\SEO\\Generators\\Breadcrumbs_Generator'] : $this->getBreadcrumbsGeneratorService()) && false ?: '_'});
4456
  $instance->set_helpers(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Image_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Image_Helper'] : $this->getImageHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper'] = new \Yoast\WP\SEO\Helpers\Options_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Current_Page_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Current_Page_Helper'] : $this->getCurrentPageHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Url_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Url_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Url_Helper'] = new \Yoast\WP\SEO\Helpers\Url_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\User_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\User_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\User_Helper'] = new \Yoast\WP\SEO\Helpers\User_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Indexable_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Indexable_Helper'] : $this->getIndexableHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Permalink_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Permalink_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Permalink_Helper'] = new \Yoast\WP\SEO\Helpers\Permalink_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Open_Graph\\Values_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Open_Graph\\Values_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Open_Graph\\Values_Helper'] = new \Yoast\WP\SEO\Helpers\Open_Graph\Values_Helper())) && false ?: '_'});
75
  'yoast\\wp\\seo\\builders\\indexable_system_page_builder' => 'Yoast\\WP\\SEO\\Builders\\Indexable_System_Page_Builder',
76
  'yoast\\wp\\seo\\builders\\indexable_term_builder' => 'Yoast\\WP\\SEO\\Builders\\Indexable_Term_Builder',
77
  'yoast\\wp\\seo\\builders\\primary_term_builder' => 'Yoast\\WP\\SEO\\Builders\\Primary_Term_Builder',
78
+ 'yoast\\wp\\seo\\commands\\cleanup_command' => 'Yoast\\WP\\SEO\\Commands\\Cleanup_Command',
79
  'yoast\\wp\\seo\\commands\\index_command' => 'Yoast\\WP\\SEO\\Commands\\Index_Command',
80
  'yoast\\wp\\seo\\conditionals\\addon_installation_conditional' => 'Yoast\\WP\\SEO\\Conditionals\\Addon_Installation_Conditional',
81
  'yoast\\wp\\seo\\conditionals\\admin\\doing_post_quick_edit_save_conditional' => 'Yoast\\WP\\SEO\\Conditionals\\Admin\\Doing_Post_Quick_Edit_Save_Conditional',
257
  'yoast\\wp\\seo\\integrations\\admin\\health_check_integration' => 'Yoast\\WP\\SEO\\Integrations\\Admin\\Health_Check_Integration',
258
  'yoast\\wp\\seo\\integrations\\admin\\helpscout_beacon' => 'Yoast\\WP\\SEO\\Integrations\\Admin\\HelpScout_Beacon',
259
  'yoast\\wp\\seo\\integrations\\admin\\import_integration' => 'Yoast\\WP\\SEO\\Integrations\\Admin\\Import_Integration',
260
+ 'yoast\\wp\\seo\\integrations\\admin\\indexables_exclude_taxonomy_integration' => 'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Exclude_Taxonomy_Integration',
261
  'yoast\\wp\\seo\\integrations\\admin\\indexables_page_integration' => 'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Page_Integration',
262
  'yoast\\wp\\seo\\integrations\\admin\\indexing_notification_integration' => 'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Notification_Integration',
263
  'yoast\\wp\\seo\\integrations\\admin\\indexing_tool_integration' => 'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Tool_Integration',
323
  'yoast\\wp\\seo\\integrations\\watchers\\addon_update_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Addon_Update_Watcher',
324
  'yoast\\wp\\seo\\integrations\\watchers\\auto_update_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Auto_Update_Watcher',
325
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_ancestor_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Ancestor_Watcher',
326
+ 'yoast\\wp\\seo\\integrations\\watchers\\indexable_author_archive_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Archive_Watcher',
327
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_author_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Watcher',
328
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_category_permalink_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Category_Permalink_Watcher',
329
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_date_archive_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Date_Archive_Watcher',
332
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_permalink_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Permalink_Watcher',
333
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_post_meta_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Meta_Watcher',
334
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_post_type_archive_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Archive_Watcher',
335
+ 'yoast\\wp\\seo\\integrations\\watchers\\indexable_post_type_change_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Change_Watcher',
336
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_post_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Watcher',
337
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_static_home_page_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Static_Home_Page_Watcher',
338
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_system_page_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_System_Page_Watcher',
339
+ 'yoast\\wp\\seo\\integrations\\watchers\\indexable_taxonomy_change_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Taxonomy_Change_Watcher',
340
  'yoast\\wp\\seo\\integrations\\watchers\\indexable_term_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Term_Watcher',
341
  'yoast\\wp\\seo\\integrations\\watchers\\option_titles_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Titles_Watcher',
342
  'yoast\\wp\\seo\\integrations\\watchers\\option_wpseo_watcher' => 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Wpseo_Watcher',
467
  'Yoast\\WP\\SEO\\Builders\\Indexable_System_Page_Builder' => 'getIndexableSystemPageBuilderService',
468
  'Yoast\\WP\\SEO\\Builders\\Indexable_Term_Builder' => 'getIndexableTermBuilderService',
469
  'Yoast\\WP\\SEO\\Builders\\Primary_Term_Builder' => 'getPrimaryTermBuilderService',
470
+ 'Yoast\\WP\\SEO\\Commands\\Cleanup_Command' => 'getCleanupCommandService',
471
  'Yoast\\WP\\SEO\\Commands\\Index_Command' => 'getIndexCommandService',
472
  'Yoast\\WP\\SEO\\Conditionals\\Addon_Installation_Conditional' => 'getAddonInstallationConditionalService',
473
  'Yoast\\WP\\SEO\\Conditionals\\Admin\\Doing_Post_Quick_Edit_Save_Conditional' => 'getDoingPostQuickEditSaveConditionalService',
649
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Health_Check_Integration' => 'getHealthCheckIntegrationService',
650
  'Yoast\\WP\\SEO\\Integrations\\Admin\\HelpScout_Beacon' => 'getHelpScoutBeaconService',
651
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Import_Integration' => 'getImportIntegrationService',
652
+ 'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Exclude_Taxonomy_Integration' => 'getIndexablesExcludeTaxonomyIntegrationService',
653
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Page_Integration' => 'getIndexablesPageIntegrationService',
654
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Notification_Integration' => 'getIndexingNotificationIntegrationService',
655
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Tool_Integration' => 'getIndexingToolIntegrationService',
715
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Addon_Update_Watcher' => 'getAddonUpdateWatcherService',
716
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Auto_Update_Watcher' => 'getAutoUpdateWatcherService',
717
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Ancestor_Watcher' => 'getIndexableAncestorWatcherService',
718
+ 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Archive_Watcher' => 'getIndexableAuthorArchiveWatcherService',
719
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Watcher' => 'getIndexableAuthorWatcherService',
720
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Category_Permalink_Watcher' => 'getIndexableCategoryPermalinkWatcherService',
721
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Date_Archive_Watcher' => 'getIndexableDateArchiveWatcherService',
724
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Permalink_Watcher' => 'getIndexablePermalinkWatcherService',
725
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Meta_Watcher' => 'getIndexablePostMetaWatcherService',
726
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Archive_Watcher' => 'getIndexablePostTypeArchiveWatcherService',
727
+ 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Change_Watcher' => 'getIndexablePostTypeChangeWatcherService',
728
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Watcher' => 'getIndexablePostWatcherService',
729
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Static_Home_Page_Watcher' => 'getIndexableStaticHomePageWatcherService',
730
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_System_Page_Watcher' => 'getIndexableSystemPageWatcherService',
731
+ 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Taxonomy_Change_Watcher' => 'getIndexableTaxonomyChangeWatcherService',
732
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Term_Watcher' => 'getIndexableTermWatcherService',
733
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Titles_Watcher' => 'getOptionTitlesWatcherService',
734
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Wpseo_Watcher' => 'getOptionWpseoWatcherService',
823
  'Psr\\Container\\ContainerInterface' => true,
824
  'YoastSEO_Vendor\\Symfony\\Component\\DependencyInjection\\ContainerInterface' => true,
825
  'YoastSEO_Vendor\\YoastSEO_Vendor\\Symfony\\Component\\DependencyInjection\\ContainerInterface' => true,
 
826
  'wpdb' => true,
827
  ];
828
  }
1352
  return $this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Author_Builder'];
1353
  }
1354
 
1355
+ $this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Author_Builder'] = $instance = new \Yoast\WP\SEO\Builders\Indexable_Author_Builder(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper'] : $this->getAuthorArchiveHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Values\\Indexables\\Indexable_Builder_Versions']) ? $this->services['Yoast\\WP\\SEO\\Values\\Indexables\\Indexable_Builder_Versions'] : ($this->services['Yoast\\WP\\SEO\\Values\\Indexables\\Indexable_Builder_Versions'] = new \Yoast\WP\SEO\Values\Indexables\Indexable_Builder_Versions())) && false ?: '_'}, $a, ${($_ = isset($this->services['wpdb']) ? $this->services['wpdb'] : $this->getWpdbService()) && false ?: '_'});
1356
 
1357
  $instance->set_social_image_helpers(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Image_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Image_Helper'] : $this->getImageHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Open_Graph\\Image_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Open_Graph\\Image_Helper'] : $this->getImageHelper2Service()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Twitter\\Image_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Twitter\\Image_Helper'] : $this->getImageHelper4Service()) && false ?: '_'});
1358
 
1561
  return $this->services['Yoast\\WP\\SEO\\Builders\\Primary_Term_Builder'] = new \Yoast\WP\SEO\Builders\Primary_Term_Builder(${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Primary_Term_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Primary_Term_Repository'] : ($this->services['Yoast\\WP\\SEO\\Repositories\\Primary_Term_Repository'] = new \Yoast\WP\SEO\Repositories\Primary_Term_Repository())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Primary_Term_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Primary_Term_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Primary_Term_Helper'] = new \Yoast\WP\SEO\Helpers\Primary_Term_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Meta_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Meta_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Meta_Helper'] = new \Yoast\WP\SEO\Helpers\Meta_Helper())) && false ?: '_'});
1562
  }
1563
 
1564
+ /**
1565
+ * Gets the public 'Yoast\WP\SEO\Commands\Cleanup_Command' shared autowired service.
1566
+ *
1567
+ * @return \Yoast\WP\SEO\Commands\Cleanup_Command
1568
+ */
1569
+ protected function getCleanupCommandService()
1570
+ {
1571
+ return $this->services['Yoast\\WP\\SEO\\Commands\\Cleanup_Command'] = new \Yoast\WP\SEO\Commands\Cleanup_Command(${($_ = isset($this->services['Yoast\\WP\\SEO\\Integrations\\Cleanup_Integration']) ? $this->services['Yoast\\WP\\SEO\\Integrations\\Cleanup_Integration'] : $this->getCleanupIntegrationService()) && false ?: '_'});
1572
+ }
1573
+
1574
  /**
1575
  * Gets the public 'Yoast\WP\SEO\Commands\Index_Command' shared autowired service.
1576
  *
2692
  */
2693
  protected function getAuthorArchiveHelperService()
2694
  {
2695
+ return $this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper'] = new \Yoast\WP\SEO\Helpers\Author_Archive_Helper(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper'] = new \Yoast\WP\SEO\Helpers\Options_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper'] : $this->getPostTypeHelperService()) && false ?: '_'});
2696
  }
2697
 
2698
  /**
2959
  */
2960
  protected function getPostHelperService()
2961
  {
2962
+ $this->services['Yoast\\WP\\SEO\\Helpers\\Post_Helper'] = $instance = new \Yoast\WP\SEO\Helpers\Post_Helper(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\String_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\String_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\String_Helper'] = new \Yoast\WP\SEO\Helpers\String_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper'] : $this->getPostTypeHelperService()) && false ?: '_'});
2963
 
2964
  $instance->set_indexable_repository(${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository'] : $this->getIndexableRepositoryService()) && false ?: '_'});
2965
 
3422
  return $this->services['Yoast\\WP\\SEO\\Integrations\\Admin\\Import_Integration'] = new \Yoast\WP\SEO\Integrations\Admin\Import_Integration(${($_ = isset($this->services['WPSEO_Admin_Asset_Manager']) ? $this->services['WPSEO_Admin_Asset_Manager'] : $this->getWPSEOAdminAssetManagerService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Services\\Importing\\Importable_Detector_Service']) ? $this->services['Yoast\\WP\\SEO\\Services\\Importing\\Importable_Detector_Service'] : $this->getImportableDetectorServiceService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Routes\\Importing_Route']) ? $this->services['Yoast\\WP\\SEO\\Routes\\Importing_Route'] : $this->getImportingRouteService()) && false ?: '_'});
3423
  }
3424
 
3425
+ /**
3426
+ * Gets the public 'Yoast\WP\SEO\Integrations\Admin\Indexables_Exclude_Taxonomy_Integration' shared autowired service.
3427
+ *
3428
+ * @return \Yoast\WP\SEO\Integrations\Admin\Indexables_Exclude_Taxonomy_Integration
3429
+ */
3430
+ protected function getIndexablesExcludeTaxonomyIntegrationService()
3431
+ {
3432
+ return $this->services['Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Exclude_Taxonomy_Integration'] = new \Yoast\WP\SEO\Integrations\Admin\Indexables_Exclude_Taxonomy_Integration(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper'] = new \Yoast\WP\SEO\Helpers\Options_Helper())) && false ?: '_'});
3433
+ }
3434
+
3435
  /**
3436
  * Gets the public 'Yoast\WP\SEO\Integrations\Admin\Indexables_Page_Integration' shared autowired service.
3437
  *
3619
  */
3620
  protected function getCleanupIntegrationService()
3621
  {
3622
+ return $this->services['Yoast\\WP\\SEO\\Integrations\\Cleanup_Integration'] = new \Yoast\WP\SEO\Integrations\Cleanup_Integration(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Taxonomy_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Taxonomy_Helper'] : $this->getTaxonomyHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper'] : $this->getPostTypeHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper'] : $this->getAuthorArchiveHelperService()) && false ?: '_'});
3623
  }
3624
 
3625
  /**
4104
  return $this->services['Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Ancestor_Watcher'] = new \Yoast\WP\SEO\Integrations\Watchers\Indexable_Ancestor_Watcher(${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository'] : $this->getIndexableRepositoryService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Hierarchy_Builder']) ? $this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Hierarchy_Builder'] : $this->getIndexableHierarchyBuilderService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Hierarchy_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Hierarchy_Repository'] : $this->getIndexableHierarchyRepositoryService()) && false ?: '_'}, ${($_ = isset($this->services['wpdb']) ? $this->services['wpdb'] : $this->getWpdbService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Permalink_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Permalink_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Permalink_Helper'] = new \Yoast\WP\SEO\Helpers\Permalink_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper'] : $this->getPostTypeHelperService()) && false ?: '_'});
4105
  }
4106
 
4107
+ /**
4108
+ * Gets the public 'Yoast\WP\SEO\Integrations\Watchers\Indexable_Author_Archive_Watcher' shared autowired service.
4109
+ *
4110
+ * @return \Yoast\WP\SEO\Integrations\Watchers\Indexable_Author_Archive_Watcher
4111
+ */
4112
+ protected function getIndexableAuthorArchiveWatcherService()
4113
+ {
4114
+ return $this->services['Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Archive_Watcher'] = new \Yoast\WP\SEO\Integrations\Watchers\Indexable_Author_Archive_Watcher();
4115
+ }
4116
+
4117
  /**
4118
  * Gets the public 'Yoast\WP\SEO\Integrations\Watchers\Indexable_Author_Watcher' shared autowired service.
4119
  *
4194
  return $this->services['Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Archive_Watcher'] = new \Yoast\WP\SEO\Integrations\Watchers\Indexable_Post_Type_Archive_Watcher(${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository'] : $this->getIndexableRepositoryService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Builder']) ? $this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Builder'] : $this->getIndexableBuilderService()) && false ?: '_'});
4195
  }
4196
 
4197
+ /**
4198
+ * Gets the public 'Yoast\WP\SEO\Integrations\Watchers\Indexable_Post_Type_Change_Watcher' shared autowired service.
4199
+ *
4200
+ * @return \Yoast\WP\SEO\Integrations\Watchers\Indexable_Post_Type_Change_Watcher
4201
+ */
4202
+ protected function getIndexablePostTypeChangeWatcherService()
4203
+ {
4204
+ return $this->services['Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Change_Watcher'] = new \Yoast\WP\SEO\Integrations\Watchers\Indexable_Post_Type_Change_Watcher(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper'] = new \Yoast\WP\SEO\Helpers\Options_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Indexing_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Indexing_Helper'] : $this->getIndexingHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper'] : $this->getPostTypeHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast_Notification_Center']) ? $this->services['Yoast_Notification_Center'] : $this->getYoastNotificationCenterService()) && false ?: '_'});
4205
+ }
4206
+
4207
  /**
4208
  * Gets the public 'Yoast\WP\SEO\Integrations\Watchers\Indexable_Post_Watcher' shared autowired service.
4209
  *
4211
  */
4212
  protected function getIndexablePostWatcherService()
4213
  {
4214
+ return $this->services['Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Watcher'] = new \Yoast\WP\SEO\Integrations\Watchers\Indexable_Post_Watcher(${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository'] : $this->getIndexableRepositoryService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Builder']) ? $this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Builder'] : $this->getIndexableBuilderService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Hierarchy_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Hierarchy_Repository'] : $this->getIndexableHierarchyRepositoryService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Link_Builder']) ? $this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Link_Builder'] : $this->getIndexableLinkBuilderService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper'] : $this->getAuthorArchiveHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Post_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Post_Helper'] : $this->getPostHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Loggers\\Logger']) ? $this->services['Yoast\\WP\\SEO\\Loggers\\Logger'] : ($this->services['Yoast\\WP\\SEO\\Loggers\\Logger'] = new \Yoast\WP\SEO\Loggers\Logger())) && false ?: '_'});
4215
  }
4216
 
4217
  /**
4234
  return $this->services['Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_System_Page_Watcher'] = new \Yoast\WP\SEO\Integrations\Watchers\Indexable_System_Page_Watcher(${($_ = isset($this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository']) ? $this->services['Yoast\\WP\\SEO\\Repositories\\Indexable_Repository'] : $this->getIndexableRepositoryService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Builder']) ? $this->services['Yoast\\WP\\SEO\\Builders\\Indexable_Builder'] : $this->getIndexableBuilderService()) && false ?: '_'});
4235
  }
4236
 
4237
+ /**
4238
+ * Gets the public 'Yoast\WP\SEO\Integrations\Watchers\Indexable_Taxonomy_Change_Watcher' shared autowired service.
4239
+ *
4240
+ * @return \Yoast\WP\SEO\Integrations\Watchers\Indexable_Taxonomy_Change_Watcher
4241
+ */
4242
+ protected function getIndexableTaxonomyChangeWatcherService()
4243
+ {
4244
+ return $this->services['Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Taxonomy_Change_Watcher'] = new \Yoast\WP\SEO\Integrations\Watchers\Indexable_Taxonomy_Change_Watcher(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Indexing_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Indexing_Helper'] : $this->getIndexingHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper'] = new \Yoast\WP\SEO\Helpers\Options_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Taxonomy_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Taxonomy_Helper'] : $this->getTaxonomyHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast_Notification_Center']) ? $this->services['Yoast_Notification_Center'] : $this->getYoastNotificationCenterService()) && false ?: '_'});
4245
+ }
4246
+
4247
  /**
4248
  * Gets the public 'Yoast\WP\SEO\Integrations\Watchers\Indexable_Term_Watcher' shared autowired service.
4249
  *
4323
  {
4324
  $this->services['Yoast\\WP\\SEO\\Loader'] = $instance = new \Yoast\WP\SEO\Loader($this);
4325
 
4326
+ $instance->register_command('Yoast\\WP\\SEO\\Commands\\Cleanup_Command');
4327
  $instance->register_command('Yoast\\WP\\SEO\\Commands\\Index_Command');
4328
  $instance->register_migration('free', '20171228151840', 'Yoast\\WP\\SEO\\Config\\Migrations\\WpYoastIndexable');
4329
  $instance->register_migration('free', '20171228151841', 'Yoast\\WP\\SEO\\Config\\Migrations\\WpYoastPrimaryTerm');
4365
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Admin\\Health_Check_Integration');
4366
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Admin\\HelpScout_Beacon');
4367
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Admin\\Import_Integration');
4368
+ $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Exclude_Taxonomy_Integration');
4369
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Page_Integration');
4370
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Notification_Integration');
4371
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Tool_Integration');
4429
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Addon_Update_Watcher');
4430
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Auto_Update_Watcher');
4431
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Ancestor_Watcher');
4432
+ $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Archive_Watcher');
4433
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Watcher');
4434
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Category_Permalink_Watcher');
4435
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Date_Archive_Watcher');
4438
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Permalink_Watcher');
4439
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Meta_Watcher');
4440
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Archive_Watcher');
4441
+ $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Change_Watcher');
4442
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Watcher');
4443
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Static_Home_Page_Watcher');
4444
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_System_Page_Watcher');
4445
+ $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Taxonomy_Change_Watcher');
4446
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Term_Watcher');
4447
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Titles_Watcher');
4448
  $instance->register_integration('Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Wpseo_Watcher');
4514
  */
4515
  protected function getIndexableAuthorArchivePresentationService()
4516
  {
4517
+ $this->services['Yoast\\WP\\SEO\\Presentations\\Indexable_Author_Archive_Presentation'] = $instance = new \Yoast\WP\SEO\Presentations\Indexable_Author_Archive_Presentation(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Post_Type_Helper'] : $this->getPostTypeHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Author_Archive_Helper'] : $this->getAuthorArchiveHelperService()) && false ?: '_'});
4518
 
4519
  $instance->set_generators(${($_ = isset($this->services['Yoast\\WP\\SEO\\Generators\\Schema_Generator']) ? $this->services['Yoast\\WP\\SEO\\Generators\\Schema_Generator'] : $this->getSchemaGeneratorService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Generators\\Open_Graph_Locale_Generator']) ? $this->services['Yoast\\WP\\SEO\\Generators\\Open_Graph_Locale_Generator'] : ($this->services['Yoast\\WP\\SEO\\Generators\\Open_Graph_Locale_Generator'] = new \Yoast\WP\SEO\Generators\Open_Graph_Locale_Generator())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Generators\\Open_Graph_Image_Generator']) ? $this->services['Yoast\\WP\\SEO\\Generators\\Open_Graph_Image_Generator'] : $this->getOpenGraphImageGeneratorService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Generators\\Twitter_Image_Generator']) ? $this->services['Yoast\\WP\\SEO\\Generators\\Twitter_Image_Generator'] : $this->getTwitterImageGeneratorService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Generators\\Breadcrumbs_Generator']) ? $this->services['Yoast\\WP\\SEO\\Generators\\Breadcrumbs_Generator'] : $this->getBreadcrumbsGeneratorService()) && false ?: '_'});
4520
  $instance->set_helpers(${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Image_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Image_Helper'] : $this->getImageHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Options_Helper'] = new \Yoast\WP\SEO\Helpers\Options_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Current_Page_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Current_Page_Helper'] : $this->getCurrentPageHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Url_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Url_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Url_Helper'] = new \Yoast\WP\SEO\Helpers\Url_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\User_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\User_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\User_Helper'] = new \Yoast\WP\SEO\Helpers\User_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Indexable_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Indexable_Helper'] : $this->getIndexableHelperService()) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Permalink_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Permalink_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Permalink_Helper'] = new \Yoast\WP\SEO\Helpers\Permalink_Helper())) && false ?: '_'}, ${($_ = isset($this->services['Yoast\\WP\\SEO\\Helpers\\Open_Graph\\Values_Helper']) ? $this->services['Yoast\\WP\\SEO\\Helpers\\Open_Graph\\Values_Helper'] : ($this->services['Yoast\\WP\\SEO\\Helpers\\Open_Graph\\Values_Helper'] = new \Yoast\WP\SEO\Helpers\Open_Graph\Values_Helper())) && false ?: '_'});
src/generators/schema/breadcrumb.php CHANGED
@@ -15,6 +15,10 @@ class Breadcrumb extends Abstract_Schema_Piece {
15
  * @return bool
16
  */
17
  public function is_needed() {
 
 
 
 
18
  if ( $this->context->indexable->object_type === 'system-page' && $this->context->indexable->object_sub_type === '404' ) {
19
  return false;
20
  }
15
  * @return bool
16
  */
17
  public function is_needed() {
18
+ if ( $this->context->indexable->object_type === 'unknown' ) {
19
+ return false;
20
+ }
21
+
22
  if ( $this->context->indexable->object_type === 'system-page' && $this->context->indexable->object_sub_type === '404' ) {
23
  return false;
24
  }
src/generators/schema/webpage.php CHANGED
@@ -16,6 +16,9 @@ class WebPage extends Abstract_Schema_Piece {
16
  * @return bool
17
  */
18
  public function is_needed() {
 
 
 
19
  return ! ( $this->context->indexable->object_type === 'system-page' && $this->context->indexable->object_sub_type === '404' );
20
  }
21
 
16
  * @return bool
17
  */
18
  public function is_needed() {
19
+ if ( $this->context->indexable->object_type === 'unknown' ) {
20
+ return false;
21
+ }
22
  return ! ( $this->context->indexable->object_type === 'system-page' && $this->context->indexable->object_sub_type === '404' );
23
  }
24
 
src/helpers/author-archive-helper.php CHANGED
@@ -2,6 +2,7 @@
2
 
3
  namespace Yoast\WP\SEO\Helpers;
4
 
 
5
  use Yoast\WP\Lib\Model;
6
 
7
  /**
@@ -9,6 +10,34 @@ use Yoast\WP\Lib\Model;
9
  */
10
  class Author_Archive_Helper {
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  /**
13
  * Gets the array of post types that are shown on an author's archive.
14
  *
@@ -46,6 +75,43 @@ class Author_Archive_Helper {
46
  return false;
47
  }
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  /**
50
  * Returns whether the author has at least one public post.
51
  *
2
 
3
  namespace Yoast\WP\SEO\Helpers;
4
 
5
+ use WP_Query;
6
  use Yoast\WP\Lib\Model;
7
 
8
  /**
10
  */
11
  class Author_Archive_Helper {
12
 
13
+ /**
14
+ * The options helper.
15
+ *
16
+ * @var Options_Helper
17
+ */
18
+ private $options_helper;
19
+
20
+ /**
21
+ * The post type helper.
22
+ *
23
+ * @var Post_Type_Helper
24
+ */
25
+ private $post_type_helper;
26
+
27
+ /**
28
+ * Creates a new author archive helper.
29
+ *
30
+ * @param Options_Helper $options_helper The options helper.
31
+ * @param Post_Type_Helper $post_type_helper The post type helper.
32
+ */
33
+ public function __construct(
34
+ Options_Helper $options_helper,
35
+ Post_Type_Helper $post_type_helper
36
+ ) {
37
+ $this->options_helper = $options_helper;
38
+ $this->post_type_helper = $post_type_helper;
39
+ }
40
+
41
  /**
42
  * Gets the array of post types that are shown on an author's archive.
43
  *
75
  return false;
76
  }
77
 
78
+ /**
79
+ * Returns whether the author has at least one public post.
80
+ *
81
+ * **Note**: It uses WP_Query to determine the number of posts,
82
+ * not the indexables table.
83
+ *
84
+ * @param string $user_id The user ID.
85
+ *
86
+ * @return bool Whether the author has at least one public post.
87
+ */
88
+ public function author_has_public_posts_wp( $user_id ) {
89
+ $post_types = \array_intersect( $this->get_author_archive_post_types(), $this->post_type_helper->get_indexable_post_types() );
90
+ $public_post_stati = \array_values( \array_filter( \get_post_stati(), 'is_post_status_viewable' ) );
91
+
92
+ $args = [
93
+ 'post_type' => $post_types,
94
+ 'post_status' => $public_post_stati,
95
+ 'author' => $user_id,
96
+ ];
97
+ $query = new WP_Query( $args );
98
+
99
+ if ( ! empty( $query->posts ) ) {
100
+ return true;
101
+ }
102
+
103
+ return false;
104
+ }
105
+
106
+ /**
107
+ * Checks whether author archives are disabled.
108
+ *
109
+ * @return bool `true` if author archives are disabled, `false` if not.
110
+ */
111
+ public function are_disabled() {
112
+ return $this->options_helper->get( 'disable-author' );
113
+ }
114
+
115
  /**
116
  * Returns whether the author has at least one public post.
117
  *
src/helpers/post-helper.php CHANGED
@@ -17,6 +17,13 @@ class Post_Helper {
17
  */
18
  private $string;
19
 
 
 
 
 
 
 
 
20
  /**
21
  * Represents the indexables repository.
22
  *
@@ -29,10 +36,15 @@ class Post_Helper {
29
  *
30
  * @codeCoverageIgnore It only sets dependencies.
31
  *
32
- * @param String_Helper $string_helper The string helper.
 
33
  */
34
- public function __construct( String_Helper $string_helper ) {
35
- $this->string = $string_helper;
 
 
 
 
36
  }
37
 
38
  /**
@@ -164,6 +176,13 @@ class Post_Helper {
164
  * @return bool True if the post can be indexed.
165
  */
166
  public function is_post_indexable( $post_id ) {
 
 
 
 
 
 
 
167
  // Don't index excluded post statuses.
168
  if ( \in_array( \get_post_status( $post_id ), $this->get_excluded_post_statuses(), true ) ) {
169
  return false;
17
  */
18
  private $string;
19
 
20
+ /**
21
+ * Holds the Post_Type_Helper instance.
22
+ *
23
+ * @var Post_Type_Helper
24
+ */
25
+ private $post_type;
26
+
27
  /**
28
  * Represents the indexables repository.
29
  *
36
  *
37
  * @codeCoverageIgnore It only sets dependencies.
38
  *
39
+ * @param String_Helper $string_helper The string helper.
40
+ * @param Post_Type_Helper $post_type_helper The string helper.
41
  */
42
+ public function __construct(
43
+ String_Helper $string_helper,
44
+ Post_Type_Helper $post_type_helper
45
+ ) {
46
+ $this->string = $string_helper;
47
+ $this->post_type = $post_type_helper;
48
  }
49
 
50
  /**
176
  * @return bool True if the post can be indexed.
177
  */
178
  public function is_post_indexable( $post_id ) {
179
+ // Don't index posts which are not public (i.e. viewable).
180
+ $post_type = \get_post_type( $post_id );
181
+ $public_types = $this->post_type->get_indexable_post_types();
182
+ if ( ! \in_array( $post_type, $public_types, true ) ) {
183
+ return false;
184
+ }
185
+
186
  // Don't index excluded post statuses.
187
  if ( \in_array( \get_post_status( $post_id ), $this->get_excluded_post_statuses(), true ) ) {
188
  return false;
src/helpers/post-type-helper.php CHANGED
@@ -140,4 +140,17 @@ class Post_Type_Helper {
140
 
141
  return ( ! empty( $post_type->has_archive ) );
142
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  }
140
 
141
  return ( ! empty( $post_type->has_archive ) );
142
  }
143
+
144
+ /**
145
+ * Returns the post types that should be indexed.
146
+ *
147
+ * @return array The post types that should be indexed.
148
+ */
149
+ public function get_indexable_post_types() {
150
+ $public_post_types = $this->get_public_post_types();
151
+ $excluded_post_types = $this->get_excluded_post_types_for_indexables();
152
+
153
+ // `array_values`, to make sure that the keys are reset.
154
+ return \array_values( \array_diff( $public_post_types, $excluded_post_types ) );
155
+ }
156
  }
src/helpers/taxonomy-helper.php CHANGED
@@ -114,4 +114,51 @@ class Taxonomy_Helper {
114
  public function get_custom_taxonomies( $output = 'names' ) {
115
  return \get_taxonomies( [ '_builtin' => false ], $output );
116
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  }
114
  public function get_custom_taxonomies( $output = 'names' ) {
115
  return \get_taxonomies( [ '_builtin' => false ], $output );
116
  }
117
+
118
+ /**
119
+ * Returns an array of taxonomies that are excluded from being indexed for the
120
+ * indexables.
121
+ *
122
+ * @return array The excluded taxonomies.
123
+ */
124
+ public function get_excluded_taxonomies_for_indexables() {
125
+ /**
126
+ * Filter: 'wpseo_indexable_excluded_taxonomies' - Allow developers to prevent a certain taxonomy
127
+ * from being saved to the indexable table.
128
+ *
129
+ * @param array $excluded_taxonomies The currently excluded taxonomies.
130
+ */
131
+ $excluded_taxonomies = \apply_filters( 'wpseo_indexable_excluded_taxonomies', [] );
132
+
133
+ // Failsafe, to always make sure that `excluded_taxonomies` is an array.
134
+ if ( ! \is_array( $excluded_taxonomies ) ) {
135
+ return [];
136
+ }
137
+
138
+ return $excluded_taxonomies;
139
+ }
140
+
141
+ /**
142
+ * Checks if the taxonomy is excluded.
143
+ *
144
+ * @param string $taxonomy The taxonomy to check.
145
+ *
146
+ * @return bool If the taxonomy is excluded.
147
+ */
148
+ public function is_excluded( $taxonomy ) {
149
+ return \in_array( $taxonomy, $this->get_excluded_taxonomies_for_indexables(), true );
150
+ }
151
+
152
+ /**
153
+ * This builds a list of indexable taxonomies.
154
+ *
155
+ * @return array The indexable taxonomies.
156
+ */
157
+ public function get_indexable_taxonomies() {
158
+ $public_taxonomies = $this->get_public_taxonomies();
159
+ $excluded_taxonomies = $this->get_excluded_taxonomies_for_indexables();
160
+
161
+ // `array_values`, to make sure that the keys are reset.
162
+ return \array_values( \array_diff( $public_taxonomies, $excluded_taxonomies ) );
163
+ }
164
  }
src/integrations/admin/indexables-exclude-taxonomy-integration.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Yoast\WP\SEO\Integrations\Admin;
4
+
5
+ use Yoast\WP\SEO\Helpers\Options_Helper;
6
+ use Yoast\WP\SEO\Integrations\Integration_Interface;
7
+ use Yoast\WP\SEO\Conditionals\No_Conditionals;
8
+
9
+ /**
10
+ * Indexables_Exclude_Taxonomy_Integration class
11
+ */
12
+ class Indexables_Exclude_Taxonomy_Integration implements Integration_Interface {
13
+
14
+ use No_Conditionals;
15
+
16
+ /**
17
+ * The options helper.
18
+ *
19
+ * @var Options_Helper
20
+ */
21
+ private $options_helper;
22
+
23
+ /**
24
+ * Indexables_Exclude_Taxonomy_Integration constructor.
25
+ *
26
+ * @param Options_Helper $options_helper The options helper.
27
+ */
28
+ public function __construct( Options_Helper $options_helper ) {
29
+ $this->options_helper = $options_helper;
30
+ }
31
+
32
+ /**
33
+ * {@inheritDoc}
34
+ */
35
+ public function register_hooks() {
36
+ \add_filter( 'wpseo_indexable_excluded_taxonomies', [ $this, 'exclude_taxonomies_for_indexation' ] );
37
+ }
38
+
39
+ /**
40
+ * Exclude the taxonomy from the indexable table.
41
+ *
42
+ * @param array $excluded_taxonomies The excluded taxonomies.
43
+ *
44
+ * @return array The excluded post types, including the specific post type.
45
+ */
46
+ public function exclude_taxonomies_for_indexation( $excluded_taxonomies ) {
47
+ if ( $this->options_helper->get( 'disable-post_format', false ) ) {
48
+ return \array_merge( $excluded_taxonomies, [ 'post_format' ] );
49
+ }
50
+
51
+ return $excluded_taxonomies;
52
+ }
53
+ }
src/integrations/cleanup-integration.php CHANGED
@@ -4,6 +4,9 @@ namespace Yoast\WP\SEO\Integrations;
4
 
5
  use Closure;
6
  use Yoast\WP\Lib\Model;
 
 
 
7
 
8
  /**
9
  * Adds cleanup hooks.
@@ -25,6 +28,40 @@ class Cleanup_Integration implements Integration_Interface {
25
  */
26
  const START_HOOK = 'wpseo_start_cleanup_indexables';
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  /**
29
  * Initializes the integration.
30
  *
@@ -71,6 +108,7 @@ class Cleanup_Integration implements Integration_Interface {
71
 
72
  // There are more items to delete for the current cleanup job, start a cronjob at the specified job.
73
  $this->start_cron_job( $name );
 
74
  return;
75
  }
76
  }
@@ -80,7 +118,7 @@ class Cleanup_Integration implements Integration_Interface {
80
  *
81
  * @return Closure[] The cleanup tasks.
82
  */
83
- protected function get_cleanup_tasks() {
84
  return \array_merge(
85
  [
86
  'clean_indexables_with_object_type_and_object_sub_type_shop_order' => function( $limit ) {
@@ -89,6 +127,18 @@ class Cleanup_Integration implements Integration_Interface {
89
  'clean_indexables_by_post_status_auto-draft' => function( $limit ) {
90
  return $this->clean_indexables_with_post_status( 'auto-draft', $limit );
91
  },
 
 
 
 
 
 
 
 
 
 
 
 
92
  ],
93
  $this->get_additional_tasks(),
94
  [
@@ -192,6 +242,7 @@ class Cleanup_Integration implements Integration_Interface {
192
 
193
  if ( $current_task_name === false ) {
194
  $this->reset_cleanup();
 
195
  return;
196
  }
197
 
@@ -216,6 +267,7 @@ class Cleanup_Integration implements Integration_Interface {
216
 
217
  if ( $items_cleaned === false ) {
218
  $this->reset_cleanup();
 
219
  return;
220
  }
221
 
@@ -223,13 +275,16 @@ class Cleanup_Integration implements Integration_Interface {
223
  // Check if we are finished with all tasks.
224
  if ( \next( $tasks ) === false ) {
225
  $this->reset_cleanup();
 
226
  return;
227
  }
228
 
229
  // Continue with the next task next time the cron job is run.
230
  \update_option( self::CURRENT_TASK_OPTION, \key( $tasks ) );
 
231
  return;
232
  }
 
233
  // There were items deleted for the current task, continue with the same task next cron call.
234
  return;
235
  }
@@ -251,6 +306,7 @@ class Cleanup_Integration implements Integration_Interface {
251
 
252
  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: There is no unescaped user input.
253
  $sql = $wpdb->prepare( "DELETE FROM $indexable_table WHERE object_type = %s AND object_sub_type = %s ORDER BY id LIMIT %d", $object_type, $object_sub_type, $limit );
 
254
  // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: Already prepared.
255
  return $wpdb->query( $sql );
256
  }
@@ -270,10 +326,160 @@ class Cleanup_Integration implements Integration_Interface {
270
 
271
  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: There is no unescaped user input.
272
  $sql = $wpdb->prepare( "DELETE FROM $indexable_table WHERE object_type = 'post' AND post_status = %s ORDER BY id LIMIT %d", $post_status, $limit );
 
273
  // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: Already prepared.
274
  return $wpdb->query( $sql );
275
  }
276
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  /**
278
  * Cleans orphaned rows from a yoast table.
279
  *
4
 
5
  use Closure;
6
  use Yoast\WP\Lib\Model;
7
+ use Yoast\WP\SEO\Helpers\Author_Archive_Helper;
8
+ use Yoast\WP\SEO\Helpers\Post_Type_Helper;
9
+ use Yoast\WP\SEO\Helpers\Taxonomy_Helper;
10
 
11
  /**
12
  * Adds cleanup hooks.
28
  */
29
  const START_HOOK = 'wpseo_start_cleanup_indexables';
30
 
31
+ /**
32
+ * A helper for taxonomies.
33
+ *
34
+ * @var Taxonomy_Helper
35
+ */
36
+ private $taxonomy;
37
+
38
+ /**
39
+ * A helper for post types.
40
+ *
41
+ * @var Post_Type_Helper
42
+ */
43
+ private $post_type;
44
+
45
+ /**
46
+ * A helper for author archives.
47
+ *
48
+ * @var Author_Archive_Helper
49
+ */
50
+ private $author_archive;
51
+
52
+ /**
53
+ * The constructor.
54
+ *
55
+ * @param Taxonomy_Helper $taxonomy A helper for taxonomies.
56
+ * @param Post_Type_Helper $post_type A helper for post types.
57
+ * @param Author_Archive_Helper $author_archive A helper for author archives.
58
+ */
59
+ public function __construct( Taxonomy_Helper $taxonomy, Post_Type_Helper $post_type, Author_Archive_Helper $author_archive ) {
60
+ $this->taxonomy = $taxonomy;
61
+ $this->post_type = $post_type;
62
+ $this->author_archive = $author_archive;
63
+ }
64
+
65
  /**
66
  * Initializes the integration.
67
  *
108
 
109
  // There are more items to delete for the current cleanup job, start a cronjob at the specified job.
110
  $this->start_cron_job( $name );
111
+
112
  return;
113
  }
114
  }
118
  *
119
  * @return Closure[] The cleanup tasks.
120
  */
121
+ public function get_cleanup_tasks() {
122
  return \array_merge(
123
  [
124
  'clean_indexables_with_object_type_and_object_sub_type_shop_order' => function( $limit ) {
127
  'clean_indexables_by_post_status_auto-draft' => function( $limit ) {
128
  return $this->clean_indexables_with_post_status( 'auto-draft', $limit );
129
  },
130
+ 'clean_indexables_for_non_publicly_viewable_post' => function ( $limit ) {
131
+ return $this->clean_indexables_for_non_publicly_viewable_post( $limit );
132
+ },
133
+ 'clean_indexables_for_non_publicly_viewable_taxonomies' => function ( $limit ) {
134
+ return $this->clean_indexables_for_non_publicly_viewable_taxonomies( $limit );
135
+ },
136
+ 'clean_indexables_for_authors_archive_disabled' => function ( $limit ) {
137
+ return $this->clean_indexables_for_authors_archive_disabled( $limit );
138
+ },
139
+ 'clean_indexables_for_authors_without_archive' => function ( $limit ) {
140
+ return $this->clean_indexables_for_authors_without_archive( $limit );
141
+ },
142
  ],
143
  $this->get_additional_tasks(),
144
  [
242
 
243
  if ( $current_task_name === false ) {
244
  $this->reset_cleanup();
245
+
246
  return;
247
  }
248
 
267
 
268
  if ( $items_cleaned === false ) {
269
  $this->reset_cleanup();
270
+
271
  return;
272
  }
273
 
275
  // Check if we are finished with all tasks.
276
  if ( \next( $tasks ) === false ) {
277
  $this->reset_cleanup();
278
+
279
  return;
280
  }
281
 
282
  // Continue with the next task next time the cron job is run.
283
  \update_option( self::CURRENT_TASK_OPTION, \key( $tasks ) );
284
+
285
  return;
286
  }
287
+
288
  // There were items deleted for the current task, continue with the same task next cron call.
289
  return;
290
  }
306
 
307
  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: There is no unescaped user input.
308
  $sql = $wpdb->prepare( "DELETE FROM $indexable_table WHERE object_type = %s AND object_sub_type = %s ORDER BY id LIMIT %d", $object_type, $object_sub_type, $limit );
309
+
310
  // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: Already prepared.
311
  return $wpdb->query( $sql );
312
  }
326
 
327
  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: There is no unescaped user input.
328
  $sql = $wpdb->prepare( "DELETE FROM $indexable_table WHERE object_type = 'post' AND post_status = %s ORDER BY id LIMIT %d", $post_status, $limit );
329
+
330
  // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: Already prepared.
331
  return $wpdb->query( $sql );
332
  }
333
 
334
+ /**
335
+ * Cleans up any indexables that belong to post types that are not/no longer publicly viewable.
336
+ *
337
+ * @param int $limit The limit we'll apply to the queries.
338
+ *
339
+ * @return bool|int The number of deleted rows, false if the query fails.
340
+ */
341
+ protected function clean_indexables_for_non_publicly_viewable_post( $limit ) {
342
+ global $wpdb;
343
+ $indexable_table = Model::get_table_name( 'Indexable' );
344
+
345
+ $included_post_types = $this->post_type->get_indexable_post_types();
346
+
347
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: Too hard to fix.
348
+ if ( empty( $included_post_types ) ) {
349
+ $delete_query = $wpdb->prepare(
350
+ "DELETE FROM $indexable_table
351
+ WHERE object_type = 'post'
352
+ AND object_sub_type IS NOT NULL
353
+ LIMIT %d",
354
+ $limit
355
+ );
356
+ }
357
+ else {
358
+ // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber -- Reason: we're passing an array instead.
359
+ $delete_query = $wpdb->prepare(
360
+ "DELETE FROM $indexable_table
361
+ WHERE object_type = 'post'
362
+ AND object_sub_type IS NOT NULL
363
+ AND object_sub_type NOT IN ( " . \implode( ', ', \array_fill( 0, \count( $included_post_types ), '%s' ) ) . ' )
364
+ LIMIT %d',
365
+ \array_merge( $included_post_types, [ $limit ] )
366
+ );
367
+ }
368
+ // phpcs:enable
369
+
370
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
371
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: Most performant way.
372
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Reason: Is it prepared already.
373
+ return $wpdb->query( $delete_query );
374
+ // phpcs:enable
375
+ }
376
+
377
+ /**
378
+ * Cleans up any indexables that belong to taxonomies that are not/no longer publicly viewable.
379
+ *
380
+ * @param int $limit The limit we'll apply to the queries.
381
+ *
382
+ * @return bool|int The number of deleted rows, false if the query fails.
383
+ */
384
+ protected function clean_indexables_for_non_publicly_viewable_taxonomies( $limit ) {
385
+ global $wpdb;
386
+ $indexable_table = Model::get_table_name( 'Indexable' );
387
+
388
+ $included_taxonomies = $this->taxonomy->get_indexable_taxonomies();
389
+
390
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: Too hard to fix.
391
+ if ( empty( $included_taxonomies ) ) {
392
+ $delete_query = $wpdb->prepare(
393
+ "DELETE FROM $indexable_table
394
+ WHERE object_type = 'term'
395
+ AND object_sub_type IS NOT NULL
396
+ LIMIT %d",
397
+ $limit
398
+ );
399
+ }
400
+ else {
401
+ // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber -- Reason: we're passing an array instead.
402
+ $delete_query = $wpdb->prepare(
403
+ "DELETE FROM $indexable_table
404
+ WHERE object_type = 'term'
405
+ AND object_sub_type IS NOT NULL
406
+ AND object_sub_type NOT IN ( " . \implode( ', ', \array_fill( 0, \count( $included_taxonomies ), '%s' ) ) . ' )
407
+ LIMIT %d',
408
+ \array_merge( $included_taxonomies, [ $limit ] )
409
+ );
410
+ }
411
+ // phpcs:enable
412
+
413
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
414
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: Most performant way.
415
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Reason: Is it prepared already.
416
+ return $wpdb->query( $delete_query );
417
+ // phpcs:enable
418
+ }
419
+
420
+ /**
421
+ * Cleans up any user indexables when the author archives have been disabled.
422
+ *
423
+ * @param int $limit The limit we'll apply to the queries.
424
+ *
425
+ * @return bool|int The number of deleted rows, false if the query fails.
426
+ */
427
+ protected function clean_indexables_for_authors_archive_disabled( $limit ) {
428
+ global $wpdb;
429
+
430
+ if ( ! $this->author_archive->are_disabled() ) {
431
+ return 0;
432
+ }
433
+
434
+ $indexable_table = Model::get_table_name( 'Indexable' );
435
+
436
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: Too hard to fix.
437
+ $delete_query = $wpdb->prepare( "DELETE FROM $indexable_table WHERE object_type = 'user' LIMIT %d", $limit );
438
+ // phpcs:enable
439
+
440
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
441
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: Most performant way.
442
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Reason: Is it prepared already.
443
+ return $wpdb->query( $delete_query );
444
+ // phpcs:enable
445
+ }
446
+
447
+ /**
448
+ * Cleans up any indexables that belong to users that have their author archives disabled.
449
+ *
450
+ * @param int $limit The limit we'll apply to the queries.
451
+ *
452
+ * @return bool|int The number of deleted rows, false if the query fails.
453
+ */
454
+ protected function clean_indexables_for_authors_without_archive( $limit ) {
455
+ global $wpdb;
456
+
457
+ $indexable_table = Model::get_table_name( 'Indexable' );
458
+ $author_archive_post_types = $this->author_archive->get_author_archive_post_types();
459
+ $viewable_post_stati = \array_filter( \get_post_stati(), 'is_post_status_viewable' );
460
+
461
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: Too hard to fix.
462
+ // phpcs:disable WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber -- Reason: we're passing an array instead.
463
+ $delete_query = $wpdb->prepare(
464
+ "DELETE FROM $indexable_table
465
+ WHERE object_type = 'user'
466
+ AND object_id NOT IN (
467
+ SELECT DISTINCT post_author
468
+ FROM $wpdb->posts
469
+ WHERE post_type IN ( " . \implode( ', ', \array_fill( 0, \count( $author_archive_post_types ), '%s' ) ) . ' )
470
+ AND post_status IN ( ' . \implode( ', ', \array_fill( 0, \count( $viewable_post_stati ), '%s' ) ) . ' )
471
+ ) LIMIT %d',
472
+ \array_merge( $author_archive_post_types, $viewable_post_stati, [ $limit ] )
473
+ );
474
+ // phpcs:enable
475
+
476
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
477
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: Most performant way.
478
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Reason: Is it prepared already.
479
+ return $wpdb->query( $delete_query );
480
+ // phpcs:enable
481
+ }
482
+
483
  /**
484
  * Cleans orphaned rows from a yoast table.
485
  *
src/integrations/watchers/indexable-author-archive-watcher.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Yoast\WP\SEO\Integrations\Watchers;
4
+
5
+ use Yoast\WP\SEO\Conditionals\Migrations_Conditional;
6
+ use Yoast\WP\SEO\Integrations\Cleanup_Integration;
7
+ use Yoast\WP\SEO\Integrations\Integration_Interface;
8
+
9
+ /**
10
+ * Watches the `wpseo_titles` option for changes to the author archive settings.
11
+ */
12
+ class Indexable_Author_Archive_Watcher implements Integration_Interface {
13
+
14
+ /**
15
+ * Check if the author archives are disabled whenever the `wpseo_titles` option
16
+ * changes.
17
+ *
18
+ * @return void
19
+ */
20
+ public function register_hooks() {
21
+ \add_action(
22
+ 'update_option_wpseo_titles',
23
+ [ $this, 'reschedule_indexable_cleanup_when_author_archives_are_disabled' ],
24
+ 10,
25
+ 2
26
+ );
27
+ }
28
+
29
+ /**
30
+ * This watcher should only be run when the migrations have been run.
31
+ * (Otherwise there may not be an indexable table to clean).
32
+ *
33
+ * @return string[] The conditionals.
34
+ */
35
+ public static function get_conditionals() {
36
+ return [ Migrations_Conditional::class ];
37
+ }
38
+
39
+ /**
40
+ * Reschedule the indexable cleanup routine if the author archives are disabled.
41
+ * to make sure that all authors are removed from the indexables table.
42
+ *
43
+ * When author archives are disabled, they can never be indexed.
44
+ *
45
+ * @param array $old_value The old `wpseo_titles` option value.
46
+ * @param array $new_value The new `wpseo_titles` option value.
47
+ *
48
+ * @return void
49
+ */
50
+ public function reschedule_indexable_cleanup_when_author_archives_are_disabled( $old_value, $new_value ) {
51
+ if ( $old_value['disable-author'] !== true && $new_value['disable-author'] === true ) {
52
+ $cleanup_not_yet_scheduled = ! \wp_next_scheduled( Cleanup_Integration::START_HOOK );
53
+ if ( $cleanup_not_yet_scheduled ) {
54
+ \wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
55
+ }
56
+ }
57
+ }
58
+ }
src/integrations/watchers/indexable-post-type-change-watcher.php ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Yoast\WP\SEO\Integrations\Watchers;
4
+
5
+ use Yoast_Notification;
6
+ use Yoast_Notification_Center;
7
+ use Yoast\WP\SEO\Actions\Indexing\Indexable_Post_Indexation_Action;
8
+ use Yoast\WP\SEO\Conditionals\Migrations_Conditional;
9
+ use Yoast\WP\SEO\Conditionals\Admin_Conditional;
10
+ use Yoast\WP\SEO\Conditionals\Not_Admin_Ajax_Conditional;
11
+ use Yoast\WP\SEO\Config\Indexing_Reasons;
12
+ use Yoast\WP\SEO\Helpers\Indexing_Helper;
13
+ use Yoast\WP\SEO\Helpers\Options_Helper;
14
+ use Yoast\WP\SEO\Helpers\Post_Type_Helper;
15
+ use Yoast\WP\SEO\Integrations\Cleanup_Integration;
16
+ use Yoast\WP\SEO\Integrations\Integration_Interface;
17
+
18
+ /**
19
+ * Post type change watcher.
20
+ */
21
+ class Indexable_Post_Type_Change_Watcher implements Integration_Interface {
22
+
23
+ /**
24
+ * The indexing helper.
25
+ *
26
+ * @var Indexing_Helper
27
+ */
28
+ protected $indexing_helper;
29
+
30
+ /**
31
+ * Holds the Options_Helper instance.
32
+ *
33
+ * @var Options_Helper
34
+ */
35
+ private $options;
36
+
37
+ /**
38
+ * Holds the Post_Type_Helper instance.
39
+ *
40
+ * @var Post_Type_Helper
41
+ */
42
+ private $post_type_helper;
43
+
44
+ /**
45
+ * The notifications center.
46
+ *
47
+ * @var Yoast_Notification_Center
48
+ */
49
+ private $notification_center;
50
+
51
+ /**
52
+ * Returns the conditionals based on which this loadable should be active.
53
+ *
54
+ * @return array
55
+ */
56
+ public static function get_conditionals() {
57
+ return [ Not_Admin_Ajax_Conditional::class, Admin_Conditional::class, Migrations_Conditional::class ];
58
+ }
59
+
60
+ /**
61
+ * Indexable_Post_Type_Change_Watcher constructor.
62
+ *
63
+ * @param Options_Helper $options The options helper.
64
+ * @param Indexing_Helper $indexing_helper The indexing helper.
65
+ * @param Post_Type_Helper $post_type_helper The post_typehelper.
66
+ * @param Yoast_Notification_Center $notification_center The notification center.
67
+ */
68
+ public function __construct(
69
+ Options_Helper $options,
70
+ Indexing_Helper $indexing_helper,
71
+ Post_Type_Helper $post_type_helper,
72
+ Yoast_Notification_Center $notification_center
73
+ ) {
74
+ $this->options = $options;
75
+ $this->indexing_helper = $indexing_helper;
76
+ $this->post_type_helper = $post_type_helper;
77
+ $this->notification_center = $notification_center;
78
+ }
79
+
80
+ /**
81
+ * Initializes the integration.
82
+ *
83
+ * This is the place to register hooks and filters.
84
+ *
85
+ * @return void
86
+ */
87
+ public function register_hooks() {
88
+ \add_action( 'admin_init', [ $this, 'check_post_types_public_availability' ] );
89
+ }
90
+
91
+ /**
92
+ * Checks if one or more post types change visibility.
93
+ *
94
+ * @return void
95
+ */
96
+ public function check_post_types_public_availability() {
97
+
98
+ // We have to make sure this is just a plain http request, no ajax/REST.
99
+ if ( \wp_is_json_request() ) {
100
+ return;
101
+ }
102
+
103
+ $public_post_types = \array_keys( $this->post_type_helper->get_public_post_types() );
104
+ $last_known_public_post_types = $this->options->get( 'last_known_public_post_types', [] );
105
+
106
+ // Initializing the option on the first run.
107
+ if ( empty( $last_known_public_post_types ) ) {
108
+ $this->options->set( 'last_known_public_post_types', $public_post_types );
109
+ return;
110
+ }
111
+
112
+ // We look for new public post types.
113
+ $newly_made_public_post_types = \array_diff( $public_post_types, $last_known_public_post_types );
114
+ // We look for post types that from public have been made private.
115
+ $newly_made_non_public_post_types = \array_diff( $last_known_public_post_types, $public_post_types );
116
+
117
+ // Nothing to be done if no changes has been made to post types.
118
+ if ( empty( $newly_made_public_post_types ) && ( empty( $newly_made_non_public_post_types ) ) ) {
119
+ return;
120
+ }
121
+
122
+ // Update the list of last known public post types in the database.
123
+ $this->options->set( 'last_known_public_post_types', $public_post_types );
124
+
125
+ // There are new post types that have been made public.
126
+ if ( ! empty( $newly_made_public_post_types ) ) {
127
+
128
+ // Force a notification requesting to start the SEO data optimization.
129
+ \delete_transient( Indexable_Post_Indexation_Action::UNINDEXED_COUNT_TRANSIENT );
130
+ \delete_transient( Indexable_Post_Indexation_Action::UNINDEXED_LIMITED_COUNT_TRANSIENT );
131
+
132
+ $this->indexing_helper->set_reason( Indexing_Reasons::REASON_POST_TYPE_MADE_PUBLIC );
133
+
134
+ $this->maybe_add_notification();
135
+ }
136
+
137
+ // There are post types that have been made private.
138
+ if ( ! empty( $newly_made_non_public_post_types ) ) {
139
+ // Schedule a cron job to remove all the posts whose post type has been made private.
140
+ $cleanup_not_yet_scheduled = ! \wp_next_scheduled( Cleanup_Integration::START_HOOK );
141
+ if ( $cleanup_not_yet_scheduled ) {
142
+ \wp_schedule_single_event( ( \time() + ( \MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
143
+ }
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Decides if a notification should be added in the notification center.
149
+ *
150
+ * @return void
151
+ */
152
+ private function maybe_add_notification() {
153
+ $notification = $this->notification_center->get_notification_by_id( 'post-types-made-public' );
154
+ if ( is_null( $notification ) ) {
155
+ $this->add_notification();
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Adds a notification to be shown on the next page request since posts are updated in an ajax request.
161
+ *
162
+ * @return void
163
+ */
164
+ private function add_notification() {
165
+ $message = sprintf(
166
+ /* translators: 1: Opening tag of the link to the Search appearance settings page, 2: Link closing tag. */
167
+ \esc_html__( 'It looks like you\'ve added a new type of content to your website. We recommend that you review your %1$sSearch appearance settings%2$s.', 'wordpress-seo' ),
168
+ '<a href="' . \esc_url( \admin_url( 'admin.php?page=wpseo_titles#top#post-types' ) ) . '">',
169
+ '</a>'
170
+ );
171
+
172
+ $notification = new Yoast_Notification(
173
+ $message,
174
+ [
175
+ 'type' => Yoast_Notification::WARNING,
176
+ 'id' => 'post-types-made-public',
177
+ 'capabilities' => 'wpseo_manage_options',
178
+ 'priority' => 0.8,
179
+ ]
180
+ );
181
+
182
+ $this->notification_center->add_notification( $notification );
183
+ }
184
+ }
src/integrations/watchers/indexable-post-watcher.php CHANGED
@@ -9,6 +9,7 @@ use Yoast\WP\SEO\Builders\Indexable_Link_Builder;
9
  use Yoast\WP\SEO\Conditionals\Migrations_Conditional;
10
  use Yoast\WP\SEO\Helpers\Author_Archive_Helper;
11
  use Yoast\WP\SEO\Helpers\Post_Helper;
 
12
  use Yoast\WP\SEO\Integrations\Integration_Interface;
13
  use Yoast\WP\SEO\Loggers\Logger;
14
  use Yoast\WP\SEO\Models\Indexable;
@@ -168,7 +169,6 @@ class Indexable_Post_Watcher implements Integration_Interface {
168
  }
169
 
170
  $this->update_relations( $post );
171
- $this->update_has_public_posts( $indexable );
172
 
173
  $indexable->save();
174
  }
@@ -192,6 +192,15 @@ class Indexable_Post_Watcher implements Integration_Interface {
192
 
193
  $post = $this->post->get_post( $post_id );
194
 
 
 
 
 
 
 
 
 
 
195
  // Build links for this post.
196
  if ( $post && $indexable && \in_array( $post->post_status, $this->post->get_public_post_statuses(), true ) ) {
197
  $this->link_builder->build( $indexable, $post->post_content );
@@ -212,9 +221,13 @@ class Indexable_Post_Watcher implements Integration_Interface {
212
  protected function update_has_public_posts( $indexable ) {
213
  // Update the author indexable's has public posts value.
214
  try {
215
- $author_indexable = $this->repository->find_by_id_and_type( $indexable->author_id, 'user' );
216
- $author_indexable->has_public_posts = $this->author_archive->author_has_public_posts( $author_indexable->object_id );
217
- $author_indexable->save();
 
 
 
 
218
  } catch ( Exception $exception ) {
219
  $this->logger->log( LogLevel::ERROR, $exception->getMessage() );
220
  }
@@ -223,6 +236,24 @@ class Indexable_Post_Watcher implements Integration_Interface {
223
  $this->post->update_has_public_posts_on_attachments( $indexable->object_id, $indexable->is_public );
224
  }
225
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  /**
227
  * Updates the relations on post save or post status change.
228
  *
9
  use Yoast\WP\SEO\Conditionals\Migrations_Conditional;
10
  use Yoast\WP\SEO\Helpers\Author_Archive_Helper;
11
  use Yoast\WP\SEO\Helpers\Post_Helper;
12
+ use Yoast\WP\SEO\Integrations\Cleanup_Integration;
13
  use Yoast\WP\SEO\Integrations\Integration_Interface;
14
  use Yoast\WP\SEO\Loggers\Logger;
15
  use Yoast\WP\SEO\Models\Indexable;
169
  }
170
 
171
  $this->update_relations( $post );
 
172
 
173
  $indexable->save();
174
  }
192
 
193
  $post = $this->post->get_post( $post_id );
194
 
195
+ /*
196
+ * Update whether an author has public posts.
197
+ * For example this post could be set to Draft or Private,
198
+ * which can influence if its author has any public posts at all.
199
+ */
200
+ if ( $indexable ) {
201
+ $this->update_has_public_posts( $indexable );
202
+ }
203
+
204
  // Build links for this post.
205
  if ( $post && $indexable && \in_array( $post->post_status, $this->post->get_public_post_statuses(), true ) ) {
206
  $this->link_builder->build( $indexable, $post->post_content );
221
  protected function update_has_public_posts( $indexable ) {
222
  // Update the author indexable's has public posts value.
223
  try {
224
+ $author_indexable = $this->repository->find_by_id_and_type( $indexable->author_id, 'user' );
225
+ if ( $author_indexable ) {
226
+ $author_indexable->has_public_posts = $this->author_archive->author_has_public_posts( $author_indexable->object_id );
227
+ $author_indexable->save();
228
+
229
+ $this->reschedule_cleanup_if_author_has_no_posts( $author_indexable );
230
+ }
231
  } catch ( Exception $exception ) {
232
  $this->logger->log( LogLevel::ERROR, $exception->getMessage() );
233
  }
236
  $this->post->update_has_public_posts_on_attachments( $indexable->object_id, $indexable->is_public );
237
  }
238
 
239
+ /**
240
+ * Reschedule indexable cleanup if the author does not have any public posts.
241
+ * This should remove the author from the indexable table, since we do not
242
+ * want to store authors without public facing posts in the table.
243
+ *
244
+ * @param Indexable $author_indexable The author indexable.
245
+ *
246
+ * @return void
247
+ */
248
+ protected function reschedule_cleanup_if_author_has_no_posts( $author_indexable ) {
249
+ if ( $author_indexable->has_public_posts === false ) {
250
+ $cleanup_not_yet_scheduled = ! \wp_next_scheduled( Cleanup_Integration::START_HOOK );
251
+ if ( $cleanup_not_yet_scheduled ) {
252
+ \wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
253
+ }
254
+ }
255
+ }
256
+
257
  /**
258
  * Updates the relations on post save or post status change.
259
  *
src/integrations/watchers/indexable-taxonomy-change-watcher.php ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Yoast\WP\SEO\Integrations\Watchers;
4
+
5
+ use Yoast_Notification;
6
+ use Yoast_Notification_Center;
7
+ use Yoast\WP\SEO\Actions\Indexing\Indexable_Term_Indexation_Action;
8
+ use Yoast\WP\SEO\Conditionals\Migrations_Conditional;
9
+ use Yoast\WP\SEO\Conditionals\Admin_Conditional;
10
+ use Yoast\WP\SEO\Conditionals\Not_Admin_Ajax_Conditional;
11
+ use Yoast\WP\SEO\Config\Indexing_Reasons;
12
+ use Yoast\WP\SEO\Helpers\Indexing_Helper;
13
+ use Yoast\WP\SEO\Helpers\Options_Helper;
14
+ use Yoast\WP\SEO\Helpers\Taxonomy_Helper;
15
+ use Yoast\WP\SEO\Integrations\Cleanup_Integration;
16
+ use Yoast\WP\SEO\Integrations\Integration_Interface;
17
+
18
+ /**
19
+ * Taxonomy watcher.
20
+ *
21
+ * Responds to changes in taxonomies public availability.
22
+ */
23
+ class Indexable_Taxonomy_Change_Watcher implements Integration_Interface {
24
+
25
+ /**
26
+ * The indexing helper.
27
+ *
28
+ * @var Indexing_Helper
29
+ */
30
+ protected $indexing_helper;
31
+
32
+ /**
33
+ * Holds the Options_Helper instance.
34
+ *
35
+ * @var Options_Helper
36
+ */
37
+ private $options;
38
+
39
+ /**
40
+ * Holds the Taxonomy_Helper instance.
41
+ *
42
+ * @var Taxonomy_Helper
43
+ */
44
+ private $taxonomy_helper;
45
+
46
+ /**
47
+ * The notifications center.
48
+ *
49
+ * @var Yoast_Notification_Center
50
+ */
51
+ private $notification_center;
52
+
53
+ /**
54
+ * Returns the conditionals based on which this loadable should be active.
55
+ *
56
+ * @return array
57
+ */
58
+ public static function get_conditionals() {
59
+ return [ Not_Admin_Ajax_Conditional::class, Admin_Conditional::class, Migrations_Conditional::class ];
60
+ }
61
+
62
+ /**
63
+ * Indexable_Taxonomy_Change_Watcher constructor.
64
+ *
65
+ * @param Indexing_Helper $indexing_helper The indexing helper.
66
+ * @param Options_Helper $options The options helper.
67
+ * @param Taxonomy_Helper $taxonomy_helper The taxonomy helper.
68
+ * @param Yoast_Notification_Center $notification_center The notification center.
69
+ */
70
+ public function __construct(
71
+ Indexing_Helper $indexing_helper,
72
+ Options_Helper $options,
73
+ Taxonomy_Helper $taxonomy_helper,
74
+ Yoast_Notification_Center $notification_center
75
+ ) {
76
+ $this->indexing_helper = $indexing_helper;
77
+ $this->options = $options;
78
+ $this->taxonomy_helper = $taxonomy_helper;
79
+ $this->notification_center = $notification_center;
80
+ }
81
+
82
+ /**
83
+ * Initializes the integration.
84
+ *
85
+ * This is the place to register hooks and filters.
86
+ *
87
+ * @return void
88
+ */
89
+ public function register_hooks() {
90
+ \add_action( 'admin_init', [ $this, 'check_taxonomy_public_availability' ] );
91
+ }
92
+
93
+ /**
94
+ * Checks if one or more taxonomies change visibility.
95
+ *
96
+ * @return void
97
+ */
98
+ public function check_taxonomy_public_availability() {
99
+
100
+ // We have to make sure this is just a plain http request, no ajax/REST.
101
+ if ( \wp_is_json_request() ) {
102
+ return;
103
+ }
104
+
105
+ $public_taxonomies = \array_keys( $this->taxonomy_helper->get_public_taxonomies() );
106
+ $last_known_public_taxonomies = $this->options->get( 'last_known_public_taxonomies', [] );
107
+
108
+ // Initializing the option on the first run.
109
+ if ( empty( $last_known_public_taxonomies ) ) {
110
+ $this->options->set( 'last_known_public_taxonomies', $public_taxonomies );
111
+ return;
112
+ }
113
+
114
+ // We look for new public taxonomies.
115
+ $newly_made_public_taxonomies = \array_diff( $public_taxonomies, $last_known_public_taxonomies );
116
+ // We look fortaxonomies that from public have been made private.
117
+ $newly_made_non_public_taxonomies = \array_diff( $last_known_public_taxonomies, $public_taxonomies );
118
+
119
+ // Nothing to be done if no changes has been made to taxonomies.
120
+ if ( empty( $newly_made_public_taxonomies ) && ( empty( $newly_made_non_public_taxonomies ) ) ) {
121
+ return;
122
+ }
123
+
124
+ // Update the list of last known public taxonomies in the database.
125
+ $this->options->set( 'last_known_public_taxonomies', $public_taxonomies );
126
+
127
+ // There are new taxonomies that have been made public.
128
+ if ( ! empty( $newly_made_public_taxonomies ) ) {
129
+
130
+ // Force a notification requesting to start the SEO data optimization.
131
+ \delete_transient( Indexable_Term_Indexation_Action::UNINDEXED_COUNT_TRANSIENT );
132
+ \delete_transient( Indexable_Term_Indexation_Action::UNINDEXED_LIMITED_COUNT_TRANSIENT );
133
+
134
+ $this->indexing_helper->set_reason( Indexing_Reasons::REASON_TAXONOMY_MADE_PUBLIC );
135
+
136
+ $this->maybe_add_notification();
137
+ }
138
+
139
+ // There are taxonomies that have been made private.
140
+ if ( ! empty( $newly_made_non_public_taxonomies ) ) {
141
+ // Schedule a cron job to remove all the terms whose taxonomy has been made private.
142
+ $cleanup_not_yet_scheduled = ! \wp_next_scheduled( Cleanup_Integration::START_HOOK );
143
+ if ( $cleanup_not_yet_scheduled ) {
144
+ \wp_schedule_single_event( ( \time() + ( \MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
145
+ }
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Decides if a notification should be added in the notification center.
151
+ *
152
+ * @return void
153
+ */
154
+ private function maybe_add_notification() {
155
+ $notification = $this->notification_center->get_notification_by_id( 'taxonomies-made-public' );
156
+ if ( is_null( $notification ) ) {
157
+ $this->add_notification();
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Adds a notification to be shown on the next page request since posts are updated in an ajax request.
163
+ *
164
+ * @return void
165
+ */
166
+ private function add_notification() {
167
+ $message = sprintf(
168
+ /* translators: 1: Opening tag of the link to the Search appearance settings page, 2: Link closing tag. */
169
+ \esc_html__( 'It looks like you\'ve added a new taxonomy to your website. We recommend that you review your %1$sSearch appearance settings%2$s.', 'wordpress-seo' ),
170
+ '<a href="' . \esc_url( \admin_url( 'admin.php?page=wpseo_titles#top#taxonomies' ) ) . '">',
171
+ '</a>'
172
+ );
173
+
174
+ $notification = new Yoast_Notification(
175
+ $message,
176
+ [
177
+ 'type' => Yoast_Notification::WARNING,
178
+ 'id' => 'taxonomies-made-public',
179
+ 'capabilities' => 'wpseo_manage_options',
180
+ 'priority' => 0.8,
181
+ ]
182
+ );
183
+
184
+ $this->notification_center->add_notification( $notification );
185
+ }
186
+ }
src/presentations/indexable-term-archive-presentation.php CHANGED
@@ -100,7 +100,11 @@ class Indexable_Term_Archive_Presentation extends Indexable_Presentation {
100
  * @return array The source.
101
  */
102
  public function generate_source() {
103
- return \get_term( $this->model->object_id, $this->model->object_sub_type );
 
 
 
 
104
  }
105
 
106
  /**
100
  * @return array The source.
101
  */
102
  public function generate_source() {
103
+ if ( ! empty( $this->model->object_id ) ) {
104
+ return \get_term( $this->model->object_id, $this->model->object_sub_type );
105
+ }
106
+
107
+ return \get_term( \get_queried_object()->term_id, \get_queried_object()->taxonomy );
108
  }
109
 
110
  /**
src/presenters/admin/indexing-notification-presenter.php CHANGED
@@ -83,6 +83,12 @@ class Indexing_Notification_Presenter extends Abstract_Presenter {
83
  case Indexing_Reasons::REASON_TAG_BASE_PREFIX:
84
  $text = \esc_html__( 'Because of a change in your tag base setting, some of your SEO data needs to be reprocessed.', 'wordpress-seo' );
85
  break;
 
 
 
 
 
 
86
  default:
87
  $text = \esc_html__( 'You can speed up your site and get insight into your internal linking structure by letting us perform a few optimizations to the way SEO data is stored. ', 'wordpress-seo' );
88
  }
83
  case Indexing_Reasons::REASON_TAG_BASE_PREFIX:
84
  $text = \esc_html__( 'Because of a change in your tag base setting, some of your SEO data needs to be reprocessed.', 'wordpress-seo' );
85
  break;
86
+ case Indexing_Reasons::REASON_POST_TYPE_MADE_PUBLIC:
87
+ $text = \esc_html__( 'We need to re-analyze some of your SEO data because of a change in the visibility of your post types. Please help us do that by running the SEO data optimization. ', 'wordpress-seo' );
88
+ break;
89
+ case Indexing_Reasons::REASON_TAXONOMY_MADE_PUBLIC:
90
+ $text = \esc_html__( 'We need to re-analyze some of your SEO data because of a change in the visibility of your taxonomies. Please help us do that by running the SEO data optimization. ', 'wordpress-seo' );
91
+ break;
92
  default:
93
  $text = \esc_html__( 'You can speed up your site and get insight into your internal linking structure by letting us perform a few optimizations to the way SEO data is stored. ', 'wordpress-seo' );
94
  }
src/routes/indexing-route.php CHANGED
@@ -267,8 +267,6 @@ class Indexing_Route extends Abstract_Indexation_Route {
267
  $this->indexable_indexing_complete_action = $indexable_indexing_complete_action;
268
  $this->indexing_complete_action = $indexing_complete_action;
269
  $this->prepare_indexing_action = $prepare_indexing_action;
270
- $this->post_link_indexing_action = $post_link_indexing_action;
271
- $this->term_link_indexing_action = $term_link_indexing_action;
272
  $this->options_helper = $options_helper;
273
  $this->post_link_indexing_action = $post_link_indexing_action;
274
  $this->term_link_indexing_action = $term_link_indexing_action;
267
  $this->indexable_indexing_complete_action = $indexable_indexing_complete_action;
268
  $this->indexing_complete_action = $indexing_complete_action;
269
  $this->prepare_indexing_action = $prepare_indexing_action;
 
 
270
  $this->options_helper = $options_helper;
271
  $this->post_link_indexing_action = $post_link_indexing_action;
272
  $this->term_link_indexing_action = $term_link_indexing_action;
src/routes/yoast-head-rest-field.php CHANGED
@@ -93,13 +93,13 @@ class Yoast_Head_REST_Field implements Route_Interface {
93
  * @return void
94
  */
95
  public function register_routes() {
96
- $public_post_types = $this->post_type_helper->get_public_post_types();
97
 
98
  foreach ( $public_post_types as $post_type ) {
99
  $this->register_rest_fields( $post_type, 'for_post' );
100
  }
101
 
102
- $public_taxonomies = $this->taxonomy_helper->get_public_taxonomies();
103
 
104
  foreach ( $public_taxonomies as $taxonomy ) {
105
  if ( $taxonomy === 'post_tag' ) {
93
  * @return void
94
  */
95
  public function register_routes() {
96
+ $public_post_types = $this->post_type_helper->get_indexable_post_types();
97
 
98
  foreach ( $public_post_types as $post_type ) {
99
  $this->register_rest_fields( $post_type, 'for_post' );
100
  }
101
 
102
+ $public_taxonomies = $this->taxonomy_helper->get_indexable_taxonomies();
103
 
104
  foreach ( $public_taxonomies as $taxonomy ) {
105
  if ( $taxonomy === 'post_tag' ) {
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInita31131447b900c039503fcd6ea7f3a02::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit62b027a57a9c5e22cc60a7e0e5f9edfd::getLoader();
vendor/composer/autoload_classmap.php CHANGED
@@ -606,6 +606,7 @@ return array(
606
  'Yoast\\WP\\SEO\\Builders\\Indexable_System_Page_Builder' => $baseDir . '/src/builders/indexable-system-page-builder.php',
607
  'Yoast\\WP\\SEO\\Builders\\Indexable_Term_Builder' => $baseDir . '/src/builders/indexable-term-builder.php',
608
  'Yoast\\WP\\SEO\\Builders\\Primary_Term_Builder' => $baseDir . '/src/builders/primary-term-builder.php',
 
609
  'Yoast\\WP\\SEO\\Commands\\Command_Interface' => $baseDir . '/src/commands/command-interface.php',
610
  'Yoast\\WP\\SEO\\Commands\\Index_Command' => $baseDir . '/src/commands/index-command.php',
611
  'Yoast\\WP\\SEO\\Conditionals\\Addon_Installation_Conditional' => $baseDir . '/src/conditionals/addon-installation-conditional.php',
@@ -714,10 +715,14 @@ return array(
714
  'Yoast\\WP\\SEO\\Exceptions\\Addon_Installation\\User_Cannot_Activate_Plugins_Exception' => $baseDir . '/src/exceptions/addon-installation/user-cannot-activate-plugins-exception.php',
715
  'Yoast\\WP\\SEO\\Exceptions\\Addon_Installation\\User_Cannot_Install_Plugins_Exception' => $baseDir . '/src/exceptions/addon-installation/user-cannot-install-plugins-exception.php',
716
  'Yoast\\WP\\SEO\\Exceptions\\Importing\\Aioseo_Validation_Exception' => $baseDir . '/src/exceptions/importing/aioseo-validation-exception.php',
 
717
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Indexable_Exception' => $baseDir . '/src/exceptions/indexable/indexable-exception.php',
718
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Invalid_Term_Exception' => $baseDir . '/src/exceptions/indexable/invalid-term-exception.php',
 
 
719
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Post_Not_Found_Exception' => $baseDir . '/src/exceptions/indexable/post-not-found-exception.php',
720
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Source_Exception' => $baseDir . '/src/exceptions/indexable/source-exception.php',
 
721
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Term_Not_Found_Exception' => $baseDir . '/src/exceptions/indexable/term-not-found-exception.php',
722
  'Yoast\\WP\\SEO\\Exceptions\\Missing_Method' => $baseDir . '/src/exceptions/missing-method.php',
723
  'Yoast\\WP\\SEO\\Exceptions\\OAuth\\Authentication_Failed_Exception' => $baseDir . '/src/exceptions/oauth/authentication-failed-exception.php',
@@ -818,6 +823,7 @@ return array(
818
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Health_Check_Integration' => $baseDir . '/src/integrations/admin/health-check-integration.php',
819
  'Yoast\\WP\\SEO\\Integrations\\Admin\\HelpScout_Beacon' => $baseDir . '/src/integrations/admin/helpscout-beacon.php',
820
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Import_Integration' => $baseDir . '/src/integrations/admin/import-integration.php',
 
821
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Page_Integration' => $baseDir . '/src/integrations/admin/indexables-page-integration.php',
822
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexation_Integration' => $baseDir . '/src/deprecated/src/integrations/admin/indexation-integration.php',
823
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Notification_Integration' => $baseDir . '/src/integrations/admin/indexing-notification-integration.php',
@@ -890,6 +896,7 @@ return array(
890
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Addon_Update_Watcher' => $baseDir . '/src/integrations/watchers/addon-update-watcher.php',
891
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Auto_Update_Watcher' => $baseDir . '/src/integrations/watchers/auto-update-watcher.php',
892
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Ancestor_Watcher' => $baseDir . '/src/integrations/watchers/indexable-ancestor-watcher.php',
 
893
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Watcher' => $baseDir . '/src/integrations/watchers/indexable-author-watcher.php',
894
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Category_Permalink_Watcher' => $baseDir . '/src/integrations/watchers/indexable-category-permalink-watcher.php',
895
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Date_Archive_Watcher' => $baseDir . '/src/integrations/watchers/indexable-date-archive-watcher.php',
@@ -898,9 +905,11 @@ return array(
898
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Permalink_Watcher' => $baseDir . '/src/integrations/watchers/indexable-permalink-watcher.php',
899
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Meta_Watcher' => $baseDir . '/src/integrations/watchers/indexable-post-meta-watcher.php',
900
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Archive_Watcher' => $baseDir . '/src/integrations/watchers/indexable-post-type-archive-watcher.php',
 
901
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Watcher' => $baseDir . '/src/integrations/watchers/indexable-post-watcher.php',
902
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Static_Home_Page_Watcher' => $baseDir . '/src/integrations/watchers/indexable-static-home-page-watcher.php',
903
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_System_Page_Watcher' => $baseDir . '/src/integrations/watchers/indexable-system-page-watcher.php',
 
904
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Term_Watcher' => $baseDir . '/src/integrations/watchers/indexable-term-watcher.php',
905
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Titles_Watcher' => $baseDir . '/src/integrations/watchers/option-titles-watcher.php',
906
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Wpseo_Watcher' => $baseDir . '/src/integrations/watchers/option-wpseo-watcher.php',
606
  'Yoast\\WP\\SEO\\Builders\\Indexable_System_Page_Builder' => $baseDir . '/src/builders/indexable-system-page-builder.php',
607
  'Yoast\\WP\\SEO\\Builders\\Indexable_Term_Builder' => $baseDir . '/src/builders/indexable-term-builder.php',
608
  'Yoast\\WP\\SEO\\Builders\\Primary_Term_Builder' => $baseDir . '/src/builders/primary-term-builder.php',
609
+ 'Yoast\\WP\\SEO\\Commands\\Cleanup_Command' => $baseDir . '/src/commands/cleanup-command.php',
610
  'Yoast\\WP\\SEO\\Commands\\Command_Interface' => $baseDir . '/src/commands/command-interface.php',
611
  'Yoast\\WP\\SEO\\Commands\\Index_Command' => $baseDir . '/src/commands/index-command.php',
612
  'Yoast\\WP\\SEO\\Conditionals\\Addon_Installation_Conditional' => $baseDir . '/src/conditionals/addon-installation-conditional.php',
715
  'Yoast\\WP\\SEO\\Exceptions\\Addon_Installation\\User_Cannot_Activate_Plugins_Exception' => $baseDir . '/src/exceptions/addon-installation/user-cannot-activate-plugins-exception.php',
716
  'Yoast\\WP\\SEO\\Exceptions\\Addon_Installation\\User_Cannot_Install_Plugins_Exception' => $baseDir . '/src/exceptions/addon-installation/user-cannot-install-plugins-exception.php',
717
  'Yoast\\WP\\SEO\\Exceptions\\Importing\\Aioseo_Validation_Exception' => $baseDir . '/src/exceptions/importing/aioseo-validation-exception.php',
718
+ 'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Author_Not_Built_Exception' => $baseDir . '/src/exceptions/indexable/author-not-built-exception.php',
719
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Indexable_Exception' => $baseDir . '/src/exceptions/indexable/indexable-exception.php',
720
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Invalid_Term_Exception' => $baseDir . '/src/exceptions/indexable/invalid-term-exception.php',
721
+ 'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Not_Built_Exception' => $baseDir . '/src/exceptions/indexable/not-built-exception.php',
722
+ 'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Post_Not_Built_Exception' => $baseDir . '/src/exceptions/indexable/post-not-built-exception.php',
723
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Post_Not_Found_Exception' => $baseDir . '/src/exceptions/indexable/post-not-found-exception.php',
724
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Source_Exception' => $baseDir . '/src/exceptions/indexable/source-exception.php',
725
+ 'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Term_Not_Built_Exception' => $baseDir . '/src/exceptions/indexable/term-not-built-exception.php',
726
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Term_Not_Found_Exception' => $baseDir . '/src/exceptions/indexable/term-not-found-exception.php',
727
  'Yoast\\WP\\SEO\\Exceptions\\Missing_Method' => $baseDir . '/src/exceptions/missing-method.php',
728
  'Yoast\\WP\\SEO\\Exceptions\\OAuth\\Authentication_Failed_Exception' => $baseDir . '/src/exceptions/oauth/authentication-failed-exception.php',
823
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Health_Check_Integration' => $baseDir . '/src/integrations/admin/health-check-integration.php',
824
  'Yoast\\WP\\SEO\\Integrations\\Admin\\HelpScout_Beacon' => $baseDir . '/src/integrations/admin/helpscout-beacon.php',
825
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Import_Integration' => $baseDir . '/src/integrations/admin/import-integration.php',
826
+ 'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Exclude_Taxonomy_Integration' => $baseDir . '/src/integrations/admin/indexables-exclude-taxonomy-integration.php',
827
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Page_Integration' => $baseDir . '/src/integrations/admin/indexables-page-integration.php',
828
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexation_Integration' => $baseDir . '/src/deprecated/src/integrations/admin/indexation-integration.php',
829
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Notification_Integration' => $baseDir . '/src/integrations/admin/indexing-notification-integration.php',
896
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Addon_Update_Watcher' => $baseDir . '/src/integrations/watchers/addon-update-watcher.php',
897
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Auto_Update_Watcher' => $baseDir . '/src/integrations/watchers/auto-update-watcher.php',
898
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Ancestor_Watcher' => $baseDir . '/src/integrations/watchers/indexable-ancestor-watcher.php',
899
+ 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Archive_Watcher' => $baseDir . '/src/integrations/watchers/indexable-author-archive-watcher.php',
900
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Watcher' => $baseDir . '/src/integrations/watchers/indexable-author-watcher.php',
901
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Category_Permalink_Watcher' => $baseDir . '/src/integrations/watchers/indexable-category-permalink-watcher.php',
902
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Date_Archive_Watcher' => $baseDir . '/src/integrations/watchers/indexable-date-archive-watcher.php',
905
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Permalink_Watcher' => $baseDir . '/src/integrations/watchers/indexable-permalink-watcher.php',
906
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Meta_Watcher' => $baseDir . '/src/integrations/watchers/indexable-post-meta-watcher.php',
907
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Archive_Watcher' => $baseDir . '/src/integrations/watchers/indexable-post-type-archive-watcher.php',
908
+ 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Change_Watcher' => $baseDir . '/src/integrations/watchers/indexable-post-type-change-watcher.php',
909
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Watcher' => $baseDir . '/src/integrations/watchers/indexable-post-watcher.php',
910
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Static_Home_Page_Watcher' => $baseDir . '/src/integrations/watchers/indexable-static-home-page-watcher.php',
911
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_System_Page_Watcher' => $baseDir . '/src/integrations/watchers/indexable-system-page-watcher.php',
912
+ 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Taxonomy_Change_Watcher' => $baseDir . '/src/integrations/watchers/indexable-taxonomy-change-watcher.php',
913
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Term_Watcher' => $baseDir . '/src/integrations/watchers/indexable-term-watcher.php',
914
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Titles_Watcher' => $baseDir . '/src/integrations/watchers/option-titles-watcher.php',
915
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Wpseo_Watcher' => $baseDir . '/src/integrations/watchers/option-wpseo-watcher.php',
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInita31131447b900c039503fcd6ea7f3a02
6
  {
7
  private static $loader;
8
 
@@ -24,15 +24,15 @@ class ComposerAutoloaderInita31131447b900c039503fcd6ea7f3a02
24
 
25
  require __DIR__ . '/platform_check.php';
26
 
27
- spl_autoload_register(array('ComposerAutoloaderInita31131447b900c039503fcd6ea7f3a02', 'loadClassLoader'), true, true);
28
  self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
29
- spl_autoload_unregister(array('ComposerAutoloaderInita31131447b900c039503fcd6ea7f3a02', 'loadClassLoader'));
30
 
31
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
32
  if ($useStaticLoader) {
33
  require __DIR__ . '/autoload_static.php';
34
 
35
- call_user_func(\Composer\Autoload\ComposerStaticInita31131447b900c039503fcd6ea7f3a02::getInitializer($loader));
36
  } else {
37
  $map = require __DIR__ . '/autoload_namespaces.php';
38
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit62b027a57a9c5e22cc60a7e0e5f9edfd
6
  {
7
  private static $loader;
8
 
24
 
25
  require __DIR__ . '/platform_check.php';
26
 
27
+ spl_autoload_register(array('ComposerAutoloaderInit62b027a57a9c5e22cc60a7e0e5f9edfd', 'loadClassLoader'), true, true);
28
  self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
29
+ spl_autoload_unregister(array('ComposerAutoloaderInit62b027a57a9c5e22cc60a7e0e5f9edfd', 'loadClassLoader'));
30
 
31
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
32
  if ($useStaticLoader) {
33
  require __DIR__ . '/autoload_static.php';
34
 
35
+ call_user_func(\Composer\Autoload\ComposerStaticInit62b027a57a9c5e22cc60a7e0e5f9edfd::getInitializer($loader));
36
  } else {
37
  $map = require __DIR__ . '/autoload_namespaces.php';
38
  foreach ($map as $namespace => $path) {
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInita31131447b900c039503fcd6ea7f3a02
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'C' =>
@@ -621,6 +621,7 @@ class ComposerStaticInita31131447b900c039503fcd6ea7f3a02
621
  'Yoast\\WP\\SEO\\Builders\\Indexable_System_Page_Builder' => __DIR__ . '/../..' . '/src/builders/indexable-system-page-builder.php',
622
  'Yoast\\WP\\SEO\\Builders\\Indexable_Term_Builder' => __DIR__ . '/../..' . '/src/builders/indexable-term-builder.php',
623
  'Yoast\\WP\\SEO\\Builders\\Primary_Term_Builder' => __DIR__ . '/../..' . '/src/builders/primary-term-builder.php',
 
624
  'Yoast\\WP\\SEO\\Commands\\Command_Interface' => __DIR__ . '/../..' . '/src/commands/command-interface.php',
625
  'Yoast\\WP\\SEO\\Commands\\Index_Command' => __DIR__ . '/../..' . '/src/commands/index-command.php',
626
  'Yoast\\WP\\SEO\\Conditionals\\Addon_Installation_Conditional' => __DIR__ . '/../..' . '/src/conditionals/addon-installation-conditional.php',
@@ -729,10 +730,14 @@ class ComposerStaticInita31131447b900c039503fcd6ea7f3a02
729
  'Yoast\\WP\\SEO\\Exceptions\\Addon_Installation\\User_Cannot_Activate_Plugins_Exception' => __DIR__ . '/../..' . '/src/exceptions/addon-installation/user-cannot-activate-plugins-exception.php',
730
  'Yoast\\WP\\SEO\\Exceptions\\Addon_Installation\\User_Cannot_Install_Plugins_Exception' => __DIR__ . '/../..' . '/src/exceptions/addon-installation/user-cannot-install-plugins-exception.php',
731
  'Yoast\\WP\\SEO\\Exceptions\\Importing\\Aioseo_Validation_Exception' => __DIR__ . '/../..' . '/src/exceptions/importing/aioseo-validation-exception.php',
 
732
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Indexable_Exception' => __DIR__ . '/../..' . '/src/exceptions/indexable/indexable-exception.php',
733
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Invalid_Term_Exception' => __DIR__ . '/../..' . '/src/exceptions/indexable/invalid-term-exception.php',
 
 
734
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Post_Not_Found_Exception' => __DIR__ . '/../..' . '/src/exceptions/indexable/post-not-found-exception.php',
735
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Source_Exception' => __DIR__ . '/../..' . '/src/exceptions/indexable/source-exception.php',
 
736
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Term_Not_Found_Exception' => __DIR__ . '/../..' . '/src/exceptions/indexable/term-not-found-exception.php',
737
  'Yoast\\WP\\SEO\\Exceptions\\Missing_Method' => __DIR__ . '/../..' . '/src/exceptions/missing-method.php',
738
  'Yoast\\WP\\SEO\\Exceptions\\OAuth\\Authentication_Failed_Exception' => __DIR__ . '/../..' . '/src/exceptions/oauth/authentication-failed-exception.php',
@@ -833,6 +838,7 @@ class ComposerStaticInita31131447b900c039503fcd6ea7f3a02
833
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Health_Check_Integration' => __DIR__ . '/../..' . '/src/integrations/admin/health-check-integration.php',
834
  'Yoast\\WP\\SEO\\Integrations\\Admin\\HelpScout_Beacon' => __DIR__ . '/../..' . '/src/integrations/admin/helpscout-beacon.php',
835
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Import_Integration' => __DIR__ . '/../..' . '/src/integrations/admin/import-integration.php',
 
836
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Page_Integration' => __DIR__ . '/../..' . '/src/integrations/admin/indexables-page-integration.php',
837
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexation_Integration' => __DIR__ . '/../..' . '/src/deprecated/src/integrations/admin/indexation-integration.php',
838
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Notification_Integration' => __DIR__ . '/../..' . '/src/integrations/admin/indexing-notification-integration.php',
@@ -905,6 +911,7 @@ class ComposerStaticInita31131447b900c039503fcd6ea7f3a02
905
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Addon_Update_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/addon-update-watcher.php',
906
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Auto_Update_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/auto-update-watcher.php',
907
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Ancestor_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-ancestor-watcher.php',
 
908
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-author-watcher.php',
909
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Category_Permalink_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-category-permalink-watcher.php',
910
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Date_Archive_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-date-archive-watcher.php',
@@ -913,9 +920,11 @@ class ComposerStaticInita31131447b900c039503fcd6ea7f3a02
913
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Permalink_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-permalink-watcher.php',
914
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Meta_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-post-meta-watcher.php',
915
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Archive_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-post-type-archive-watcher.php',
 
916
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-post-watcher.php',
917
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Static_Home_Page_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-static-home-page-watcher.php',
918
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_System_Page_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-system-page-watcher.php',
 
919
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Term_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-term-watcher.php',
920
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Titles_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/option-titles-watcher.php',
921
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Wpseo_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/option-wpseo-watcher.php',
@@ -1110,9 +1119,9 @@ class ComposerStaticInita31131447b900c039503fcd6ea7f3a02
1110
  public static function getInitializer(ClassLoader $loader)
1111
  {
1112
  return \Closure::bind(function () use ($loader) {
1113
- $loader->prefixLengthsPsr4 = ComposerStaticInita31131447b900c039503fcd6ea7f3a02::$prefixLengthsPsr4;
1114
- $loader->prefixDirsPsr4 = ComposerStaticInita31131447b900c039503fcd6ea7f3a02::$prefixDirsPsr4;
1115
- $loader->classMap = ComposerStaticInita31131447b900c039503fcd6ea7f3a02::$classMap;
1116
 
1117
  }, null, ClassLoader::class);
1118
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit62b027a57a9c5e22cc60a7e0e5f9edfd
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'C' =>
621
  'Yoast\\WP\\SEO\\Builders\\Indexable_System_Page_Builder' => __DIR__ . '/../..' . '/src/builders/indexable-system-page-builder.php',
622
  'Yoast\\WP\\SEO\\Builders\\Indexable_Term_Builder' => __DIR__ . '/../..' . '/src/builders/indexable-term-builder.php',
623
  'Yoast\\WP\\SEO\\Builders\\Primary_Term_Builder' => __DIR__ . '/../..' . '/src/builders/primary-term-builder.php',
624
+ 'Yoast\\WP\\SEO\\Commands\\Cleanup_Command' => __DIR__ . '/../..' . '/src/commands/cleanup-command.php',
625
  'Yoast\\WP\\SEO\\Commands\\Command_Interface' => __DIR__ . '/../..' . '/src/commands/command-interface.php',
626
  'Yoast\\WP\\SEO\\Commands\\Index_Command' => __DIR__ . '/../..' . '/src/commands/index-command.php',
627
  'Yoast\\WP\\SEO\\Conditionals\\Addon_Installation_Conditional' => __DIR__ . '/../..' . '/src/conditionals/addon-installation-conditional.php',
730
  'Yoast\\WP\\SEO\\Exceptions\\Addon_Installation\\User_Cannot_Activate_Plugins_Exception' => __DIR__ . '/../..' . '/src/exceptions/addon-installation/user-cannot-activate-plugins-exception.php',
731
  'Yoast\\WP\\SEO\\Exceptions\\Addon_Installation\\User_Cannot_Install_Plugins_Exception' => __DIR__ . '/../..' . '/src/exceptions/addon-installation/user-cannot-install-plugins-exception.php',
732
  'Yoast\\WP\\SEO\\Exceptions\\Importing\\Aioseo_Validation_Exception' => __DIR__ . '/../..' . '/src/exceptions/importing/aioseo-validation-exception.php',
733
+ 'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Author_Not_Built_Exception' => __DIR__ . '/../..' . '/src/exceptions/indexable/author-not-built-exception.php',
734
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Indexable_Exception' => __DIR__ . '/../..' . '/src/exceptions/indexable/indexable-exception.php',
735
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Invalid_Term_Exception' => __DIR__ . '/../..' . '/src/exceptions/indexable/invalid-term-exception.php',
736
+ 'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Not_Built_Exception' => __DIR__ . '/../..' . '/src/exceptions/indexable/not-built-exception.php',
737
+ 'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Post_Not_Built_Exception' => __DIR__ . '/../..' . '/src/exceptions/indexable/post-not-built-exception.php',
738
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Post_Not_Found_Exception' => __DIR__ . '/../..' . '/src/exceptions/indexable/post-not-found-exception.php',
739
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Source_Exception' => __DIR__ . '/../..' . '/src/exceptions/indexable/source-exception.php',
740
+ 'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Term_Not_Built_Exception' => __DIR__ . '/../..' . '/src/exceptions/indexable/term-not-built-exception.php',
741
  'Yoast\\WP\\SEO\\Exceptions\\Indexable\\Term_Not_Found_Exception' => __DIR__ . '/../..' . '/src/exceptions/indexable/term-not-found-exception.php',
742
  'Yoast\\WP\\SEO\\Exceptions\\Missing_Method' => __DIR__ . '/../..' . '/src/exceptions/missing-method.php',
743
  'Yoast\\WP\\SEO\\Exceptions\\OAuth\\Authentication_Failed_Exception' => __DIR__ . '/../..' . '/src/exceptions/oauth/authentication-failed-exception.php',
838
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Health_Check_Integration' => __DIR__ . '/../..' . '/src/integrations/admin/health-check-integration.php',
839
  'Yoast\\WP\\SEO\\Integrations\\Admin\\HelpScout_Beacon' => __DIR__ . '/../..' . '/src/integrations/admin/helpscout-beacon.php',
840
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Import_Integration' => __DIR__ . '/../..' . '/src/integrations/admin/import-integration.php',
841
+ 'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Exclude_Taxonomy_Integration' => __DIR__ . '/../..' . '/src/integrations/admin/indexables-exclude-taxonomy-integration.php',
842
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexables_Page_Integration' => __DIR__ . '/../..' . '/src/integrations/admin/indexables-page-integration.php',
843
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexation_Integration' => __DIR__ . '/../..' . '/src/deprecated/src/integrations/admin/indexation-integration.php',
844
  'Yoast\\WP\\SEO\\Integrations\\Admin\\Indexing_Notification_Integration' => __DIR__ . '/../..' . '/src/integrations/admin/indexing-notification-integration.php',
911
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Addon_Update_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/addon-update-watcher.php',
912
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Auto_Update_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/auto-update-watcher.php',
913
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Ancestor_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-ancestor-watcher.php',
914
+ 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Archive_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-author-archive-watcher.php',
915
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Author_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-author-watcher.php',
916
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Category_Permalink_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-category-permalink-watcher.php',
917
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Date_Archive_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-date-archive-watcher.php',
920
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Permalink_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-permalink-watcher.php',
921
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Meta_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-post-meta-watcher.php',
922
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Archive_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-post-type-archive-watcher.php',
923
+ 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Type_Change_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-post-type-change-watcher.php',
924
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Post_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-post-watcher.php',
925
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Static_Home_Page_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-static-home-page-watcher.php',
926
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_System_Page_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-system-page-watcher.php',
927
+ 'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Taxonomy_Change_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-taxonomy-change-watcher.php',
928
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Indexable_Term_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/indexable-term-watcher.php',
929
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Titles_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/option-titles-watcher.php',
930
  'Yoast\\WP\\SEO\\Integrations\\Watchers\\Option_Wpseo_Watcher' => __DIR__ . '/../..' . '/src/integrations/watchers/option-wpseo-watcher.php',
1119
  public static function getInitializer(ClassLoader $loader)
1120
  {
1121
  return \Closure::bind(function () use ($loader) {
1122
+ $loader->prefixLengthsPsr4 = ComposerStaticInit62b027a57a9c5e22cc60a7e0e5f9edfd::$prefixLengthsPsr4;
1123
+ $loader->prefixDirsPsr4 = ComposerStaticInit62b027a57a9c5e22cc60a7e0e5f9edfd::$prefixDirsPsr4;
1124
+ $loader->classMap = ComposerStaticInit62b027a57a9c5e22cc60a7e0e5f9edfd::$classMap;
1125
 
1126
  }, null, ClassLoader::class);
1127
  }
vendor/composer/installed.php CHANGED
@@ -5,7 +5,7 @@
5
  'type' => 'wordpress-plugin',
6
  'install_path' => __DIR__ . '/../../',
7
  'aliases' => array(),
8
- 'reference' => 'f512174439c64534a048012f8810a5727f1cd44e',
9
  'name' => 'yoast/wordpress-seo',
10
  'dev' => false,
11
  ),
@@ -46,7 +46,7 @@
46
  'type' => 'wordpress-plugin',
47
  'install_path' => __DIR__ . '/../../',
48
  'aliases' => array(),
49
- 'reference' => 'f512174439c64534a048012f8810a5727f1cd44e',
50
  'dev_requirement' => false,
51
  ),
52
  ),
5
  'type' => 'wordpress-plugin',
6
  'install_path' => __DIR__ . '/../../',
7
  'aliases' => array(),
8
+ 'reference' => '6a3178ca2fedf326ba298aa3cccb7a9fa4df95b3',
9
  'name' => 'yoast/wordpress-seo',
10
  'dev' => false,
11
  ),
46
  'type' => 'wordpress-plugin',
47
  'install_path' => __DIR__ . '/../../',
48
  'aliases' => array(),
49
+ 'reference' => '6a3178ca2fedf326ba298aa3cccb7a9fa4df95b3',
50
  'dev_requirement' => false,
51
  ),
52
  ),
wp-seo-main.php CHANGED
@@ -15,7 +15,7 @@ if ( ! function_exists( 'add_filter' ) ) {
15
  * {@internal Nobody should be able to overrule the real version number as this can cause
16
  * serious issues with the options, so no if ( ! defined() ).}}
17
  */
18
- define( 'WPSEO_VERSION', '19.10' );
19
 
20
 
21
  if ( ! defined( 'WPSEO_PATH' ) ) {
@@ -35,7 +35,7 @@ define( 'YOAST_VENDOR_DEFINE_PREFIX', 'YOASTSEO_VENDOR__' );
35
  define( 'YOAST_VENDOR_PREFIX_DIRECTORY', 'vendor_prefixed' );
36
 
37
  define( 'YOAST_SEO_PHP_REQUIRED', '5.6' );
38
- define( 'YOAST_SEO_WP_TESTED', '6.1' );
39
  define( 'YOAST_SEO_WP_REQUIRED', '5.9' );
40
 
41
  if ( ! defined( 'WPSEO_NAMESPACES' ) ) {
15
  * {@internal Nobody should be able to overrule the real version number as this can cause
16
  * serious issues with the options, so no if ( ! defined() ).}}
17
  */
18
+ define( 'WPSEO_VERSION', '19.11' );
19
 
20
 
21
  if ( ! defined( 'WPSEO_PATH' ) ) {
35
  define( 'YOAST_VENDOR_PREFIX_DIRECTORY', 'vendor_prefixed' );
36
 
37
  define( 'YOAST_SEO_PHP_REQUIRED', '5.6' );
38
+ define( 'YOAST_SEO_WP_TESTED', '6.1.1' );
39
  define( 'YOAST_SEO_WP_REQUIRED', '5.9' );
40
 
41
  if ( ! defined( 'WPSEO_NAMESPACES' ) ) {
wp-seo.php CHANGED
@@ -8,7 +8,7 @@
8
  *
9
  * @wordpress-plugin
10
  * Plugin Name: Yoast SEO
11
- * Version: 19.10
12
  * Plugin URI: https://yoa.st/1uj
13
  * Description: The first true all-in-one SEO solution for WordPress, including on-page content analysis, XML sitemaps and much more.
14
  * Author: Team Yoast
8
  *
9
  * @wordpress-plugin
10
  * Plugin Name: Yoast SEO
11
+ * Version: 19.11
12
  * Plugin URI: https://yoa.st/1uj
13
  * Description: The first true all-in-one SEO solution for WordPress, including on-page content analysis, XML sitemaps and much more.
14
  * Author: Team Yoast