← All changes
|
src/integrations/watchers/indexable-post-watcher.php
+66
-14
18.1
→
trunk
View file →
| @@ -7,9 +7,11 @@ | ||
| 7 | 7 | use Yoast\WP\SEO\Builders\Indexable_Builder; |
| 8 | 8 | use Yoast\WP\SEO\Builders\Indexable_Link_Builder; |
| 9 | 9 | use Yoast\WP\SEO\Conditionals\Migrations_Conditional; |
| 10 | 10 | use Yoast\WP\SEO\Helpers\Author_Archive_Helper; |
| 11 | +use Yoast\WP\SEO\Helpers\Indexable_Helper; | |
| 11 | 12 | use Yoast\WP\SEO\Helpers\Post_Helper; |
| 13 | +use Yoast\WP\SEO\Integrations\Cleanup_Integration; | |
| 12 | 14 | use Yoast\WP\SEO\Integrations\Integration_Interface; |
| 13 | 15 | use Yoast\WP\SEO\Loggers\Logger; |
| 14 | 16 | use Yoast\WP\SEO\Models\Indexable; |
| 15 | 17 | use Yoast\WP\SEO\Repositories\Indexable_Hierarchy_Repository; |
| @@ -58,8 +60,15 @@ | ||
| 58 | 60 | */ |
| 59 | 61 | private $author_archive; |
| 60 | 62 | |
| 61 | 63 | /** |
| 64 | + * The indexable helper. | |
| 65 | + * | |
| 66 | + * @var Indexable_Helper | |
| 67 | + */ | |
| 68 | + private $indexable_helper; | |
| 69 | + | |
| 70 | + /** | |
| 62 | 71 | * Holds the Post_Helper instance. |
| 63 | 72 | * |
| 64 | 73 | * @var Post_Helper |
| 65 | 74 | */ |
| @@ -74,9 +83,9 @@ | ||
| 74 | 83 | |
| 75 | 84 | /** |
| 76 | 85 | * Returns the conditionals based on which this loadable should be active. |
| 77 | 86 | * |
| 78 | - * @return array | |
| 87 | + * @return array<string> The conditionals. | |
| 79 | 88 | */ |
| 80 | 89 | public static function get_conditionals() { |
| 81 | 90 | return [ Migrations_Conditional::class ]; |
| 82 | 91 | } |
| @@ -88,8 +97,9 @@ | ||
| 88 | 97 | * @param Indexable_Builder $builder The post builder to use. |
| 89 | 98 | * @param Indexable_Hierarchy_Repository $hierarchy_repository The hierarchy repository to use. |
| 90 | 99 | * @param Indexable_Link_Builder $link_builder The link builder. |
| 91 | 100 | * @param Author_Archive_Helper $author_archive The author archive helper. |
| 101 | + * @param Indexable_Helper $indexable_helper The indexable helper. | |
| 92 | 102 | * @param Post_Helper $post The post helper. |
| 93 | 103 | * @param Logger $logger The logger. |
| 94 | 104 | */ |
| 95 | 105 | public function __construct( |
| @@ -97,8 +107,9 @@ | ||
| 97 | 107 | Indexable_Builder $builder, |
| 98 | 108 | Indexable_Hierarchy_Repository $hierarchy_repository, |
| 99 | 109 | Indexable_Link_Builder $link_builder, |
| 100 | 110 | Author_Archive_Helper $author_archive, |
| 111 | + Indexable_Helper $indexable_helper, | |
| 101 | 112 | Post_Helper $post, |
| 102 | 113 | Logger $logger |
| 103 | 114 | ) { |
| 104 | 115 | $this->repository = $repository; |
| @@ -105,8 +116,9 @@ | ||
| 105 | 116 | $this->builder = $builder; |
| 106 | 117 | $this->hierarchy_repository = $hierarchy_repository; |
| 107 | 118 | $this->link_builder = $link_builder; |
| 108 | 119 | $this->author_archive = $author_archive; |
| 120 | + $this->indexable_helper = $indexable_helper; | |
| 109 | 121 | $this->post = $post; |
| 110 | 122 | $this->logger = $logger; |
| 111 | 123 | } |
| 112 | 124 | |
| @@ -147,8 +159,9 @@ | ||
| 147 | 159 | |
| 148 | 160 | $this->hierarchy_repository->clear_ancestors( $indexable->id ); |
| 149 | 161 | $this->link_builder->delete( $indexable ); |
| 150 | 162 | $indexable->delete(); |
| 163 | + \do_action( 'wpseo_indexable_deleted', $indexable ); | |
| 151 | 164 | } |
| 152 | 165 | |
| 153 | 166 | /** |
| 154 | 167 | * Updates the relations when the post indexable is built. |
| @@ -154,8 +167,10 @@ | ||
| 154 | 167 | * Updates the relations when the post indexable is built. |
| 155 | 168 | * |
| 156 | 169 | * @param Indexable $indexable The indexable. |
| 157 | 170 | * @param WP_Post $post The post. |
| 171 | + * | |
| 172 | + * @return void | |
| 158 | 173 | */ |
| 159 | 174 | public function updated_indexable( $indexable, $post ) { |
| 160 | 175 | // Only interested in post indexables. |
| 161 | 176 | if ( $indexable->object_type !== 'post' ) { |
| @@ -161,17 +176,14 @@ | ||
| 161 | 176 | if ( $indexable->object_type !== 'post' ) { |
| 162 | 177 | return; |
| 163 | 178 | } |
| 164 | 179 | |
| 165 | - if ( is_a( $post, Indexable::class ) ) { | |
| 166 | - _deprecated_argument( __FUNCTION__, '17.7', 'The $old_indexable argument has been deprecated.' ); | |
| 180 | + if ( \is_a( $post, Indexable::class ) ) { | |
| 181 | + \_deprecated_argument( __FUNCTION__, '17.7', 'The $old_indexable argument has been deprecated.' ); | |
| 167 | 182 | $post = $this->post->get_post( $indexable->object_id ); |
| 168 | 183 | } |
| 169 | 184 | |
| 170 | 185 | $this->update_relations( $post ); |
| 171 | - $this->update_has_public_posts( $indexable ); | |
| 172 | - | |
| 173 | - $indexable->save(); | |
| 174 | 186 | } |
| 175 | 187 | |
| 176 | 188 | /** |
| 177 | 189 | * Saves post meta. |
| @@ -191,13 +203,22 @@ | ||
| 191 | 203 | $indexable = $this->builder->build_for_id_and_type( $post_id, 'post', $indexable ); |
| 192 | 204 | |
| 193 | 205 | $post = $this->post->get_post( $post_id ); |
| 194 | 206 | |
| 207 | + /* | |
| 208 | + * Update whether an author has public posts. | |
| 209 | + * For example this post could be set to Draft or Private, | |
| 210 | + * which can influence if its author has any public posts at all. | |
| 211 | + */ | |
| 212 | + if ( $indexable ) { | |
| 213 | + $this->update_has_public_posts( $indexable ); | |
| 214 | + } | |
| 215 | + | |
| 195 | 216 | // Build links for this post. |
| 196 | 217 | if ( $post && $indexable && \in_array( $post->post_status, $this->post->get_public_post_statuses(), true ) ) { |
| 197 | 218 | $this->link_builder->build( $indexable, $post->post_content ); |
| 198 | 219 | // Save indexable to persist the updated link count. |
| 199 | - $indexable->save(); | |
| 220 | + $this->indexable_helper->save_indexable( $indexable ); | |
| 200 | 221 | $this->updated_indexable( $indexable, $post ); |
| 201 | 222 | } |
| 202 | 223 | } catch ( Exception $exception ) { |
| 203 | 224 | $this->logger->log( LogLevel::ERROR, $exception->getMessage() ); |
| @@ -207,15 +228,23 @@ | ||
| 207 | 228 | /** |
| 208 | 229 | * Updates the has_public_posts when the post indexable is built. |
| 209 | 230 | * |
| 210 | 231 | * @param Indexable $indexable The indexable to check. |
| 232 | + * | |
| 233 | + * @return void | |
| 211 | 234 | */ |
| 212 | 235 | protected function update_has_public_posts( $indexable ) { |
| 213 | 236 | // Update the author indexable's has public posts value. |
| 214 | 237 | 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(); | |
| 238 | + $author_indexable = $this->repository->find_by_id_and_type( $indexable->author_id, 'user' ); | |
| 239 | + if ( $author_indexable ) { | |
| 240 | + $author_indexable->has_public_posts = $this->author_archive->author_has_public_posts( $author_indexable->object_id ); | |
| 241 | + $this->indexable_helper->save_indexable( $author_indexable ); | |
| 242 | + | |
| 243 | + if ( $this->indexable_helper->should_index_indexable( $author_indexable ) ) { | |
| 244 | + $this->reschedule_cleanup_if_author_has_no_posts( $author_indexable ); | |
| 245 | + } | |
| 246 | + } | |
| 218 | 247 | } catch ( Exception $exception ) { |
| 219 | 248 | $this->logger->log( LogLevel::ERROR, $exception->getMessage() ); |
| 220 | 249 | } |
| 221 | 250 | |
| @@ -223,18 +252,41 @@ | ||
| 223 | 252 | $this->post->update_has_public_posts_on_attachments( $indexable->object_id, $indexable->is_public ); |
| 224 | 253 | } |
| 225 | 254 | |
| 226 | 255 | /** |
| 256 | + * Reschedule indexable cleanup if the author does not have any public posts. | |
| 257 | + * This should remove the author from the indexable table, since we do not | |
| 258 | + * want to store authors without public facing posts in the table. | |
| 259 | + * | |
| 260 | + * @param Indexable $author_indexable The author indexable. | |
| 261 | + * | |
| 262 | + * @return void | |
| 263 | + */ | |
| 264 | + protected function reschedule_cleanup_if_author_has_no_posts( $author_indexable ) { | |
| 265 | + if ( $author_indexable->has_public_posts === false ) { | |
| 266 | + $cleanup_not_yet_scheduled = ! \wp_next_scheduled( Cleanup_Integration::START_HOOK ); | |
| 267 | + if ( $cleanup_not_yet_scheduled ) { | |
| 268 | + \wp_schedule_single_event( ( \time() + ( \MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK ); | |
| 269 | + } | |
| 270 | + } | |
| 271 | + } | |
| 272 | + | |
| 273 | + /** | |
| 227 | 274 | * Updates the relations on post save or post status change. |
| 228 | 275 | * |
| 229 | 276 | * @param WP_Post $post The post that has been updated. |
| 277 | + * | |
| 278 | + * @return void | |
| 230 | 279 | */ |
| 231 | 280 | protected function update_relations( $post ) { |
| 232 | 281 | $related_indexables = $this->get_related_indexables( $post ); |
| 233 | 282 | |
| 234 | 283 | foreach ( $related_indexables as $indexable ) { |
| 235 | - $indexable->object_last_modified = max( $indexable->object_last_modified, $post->post_modified_gmt ); | |
| 236 | - $indexable->save(); | |
| 284 | + // Ignore everything that is not an actual indexable. | |
| 285 | + if ( \is_a( $indexable, Indexable::class ) ) { | |
| 286 | + $indexable->object_last_modified = \max( $indexable->object_last_modified, $post->post_modified_gmt ); | |
| 287 | + $this->indexable_helper->save_indexable( $indexable ); | |
| 288 | + } | |
| 237 | 289 | } |
| 238 | 290 | } |
| 239 | 291 | |
| 240 | 292 | /** |
| @@ -247,9 +299,9 @@ | ||
| 247 | 299 | protected function get_related_indexables( $post ) { |
| 248 | 300 | /** |
| 249 | 301 | * The related indexables. |
| 250 | 302 | * |
| 251 | - * @var Indexable[] $related_indexables . | |
| 303 | + * @var Indexable[] $related_indexables | |
| 252 | 304 | */ |
| 253 | 305 | $related_indexables = []; |
| 254 | 306 | $related_indexables[] = $this->repository->find_by_id_and_type( $post->post_author, 'user', false ); |
| 255 | 307 | $related_indexables[] = $this->repository->find_for_post_type_archive( $post->post_type, false ); |
| @@ -268,9 +320,9 @@ | ||
| 268 | 320 | $term_ids = \array_merge( $term_ids, \wp_list_pluck( $terms, 'term_id' ) ); |
| 269 | 321 | } |
| 270 | 322 | $related_indexables = \array_merge( |
| 271 | 323 | $related_indexables, |
| 272 | - $this->repository->find_by_multiple_ids_and_type( $term_ids, 'term', false ) | |
| 324 | + $this->repository->find_by_multiple_ids_and_type( $term_ids, 'term', false ), | |
| 273 | 325 | ); |
| 274 | 326 | |
| 275 | 327 | return \array_filter( $related_indexables ); |
| 276 | 328 | } |