PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / trunk
Yoast SEO – Advanced SEO with real-time guidance and built-in AI vtrunk
28.6 28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 All 130 releases
← All changes | src/integrations/watchers/indexable-post-watcher.php +64 -17 18.5 → 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,9 @@
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.' );
167 - $post = $this->post->get_post( $indexable->object_id );
168 - }
169 -
170 180 $this->update_relations( $post );
171 - $this->update_has_public_posts( $indexable );
172 -
173 - $indexable->save();
174 181 }
175 182
176 183 /**
177 184 * Saves post meta.
@@ -191,13 +198,22 @@
191 198 $indexable = $this->builder->build_for_id_and_type( $post_id, 'post', $indexable );
192 199
193 200 $post = $this->post->get_post( $post_id );
194 201
202 + /*
203 + * Update whether an author has public posts.
204 + * For example this post could be set to Draft or Private,
205 + * which can influence if its author has any public posts at all.
206 + */
207 + if ( $indexable ) {
208 + $this->update_has_public_posts( $indexable );
209 + }
210 +
195 211 // Build links for this post.
196 212 if ( $post && $indexable && \in_array( $post->post_status, $this->post->get_public_post_statuses(), true ) ) {
197 213 $this->link_builder->build( $indexable, $post->post_content );
198 214 // Save indexable to persist the updated link count.
199 - $indexable->save();
215 + $this->indexable_helper->save_indexable( $indexable );
200 216 $this->updated_indexable( $indexable, $post );
201 217 }
202 218 } catch ( Exception $exception ) {
203 219 $this->logger->log( LogLevel::ERROR, $exception->getMessage() );
@@ -207,15 +223,23 @@
207 223 /**
208 224 * Updates the has_public_posts when the post indexable is built.
209 225 *
210 226 * @param Indexable $indexable The indexable to check.
227 + *
228 + * @return void
211 229 */
212 230 protected function update_has_public_posts( $indexable ) {
213 231 // Update the author indexable's has public posts value.
214 232 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();
233 + $author_indexable = $this->repository->find_by_id_and_type( $indexable->author_id, 'user' );
234 + if ( $author_indexable ) {
235 + $author_indexable->has_public_posts = $this->author_archive->author_has_public_posts( $author_indexable->object_id );
236 + $this->indexable_helper->save_indexable( $author_indexable );
237 +
238 + if ( $this->indexable_helper->should_index_indexable( $author_indexable ) ) {
239 + $this->reschedule_cleanup_if_author_has_no_posts( $author_indexable );
240 + }
241 + }
218 242 } catch ( Exception $exception ) {
219 243 $this->logger->log( LogLevel::ERROR, $exception->getMessage() );
220 244 }
221 245
@@ -223,18 +247,41 @@
223 247 $this->post->update_has_public_posts_on_attachments( $indexable->object_id, $indexable->is_public );
224 248 }
225 249
226 250 /**
251 + * Reschedule indexable cleanup if the author does not have any public posts.
252 + * This should remove the author from the indexable table, since we do not
253 + * want to store authors without public facing posts in the table.
254 + *
255 + * @param Indexable $author_indexable The author indexable.
256 + *
257 + * @return void
258 + */
259 + protected function reschedule_cleanup_if_author_has_no_posts( $author_indexable ) {
260 + if ( $author_indexable->has_public_posts === false ) {
261 + $cleanup_not_yet_scheduled = ! \wp_next_scheduled( Cleanup_Integration::START_HOOK );
262 + if ( $cleanup_not_yet_scheduled ) {
263 + \wp_schedule_single_event( ( \time() + ( \MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
264 + }
265 + }
266 + }
267 +
268 + /**
227 269 * Updates the relations on post save or post status change.
228 270 *
229 271 * @param WP_Post $post The post that has been updated.
272 + *
273 + * @return void
230 274 */
231 275 protected function update_relations( $post ) {
232 276 $related_indexables = $this->get_related_indexables( $post );
233 277
234 278 foreach ( $related_indexables as $indexable ) {
235 - $indexable->object_last_modified = \max( $indexable->object_last_modified, $post->post_modified_gmt );
236 - $indexable->save();
279 + // Ignore everything that is not an actual indexable.
280 + if ( \is_a( $indexable, Indexable::class ) ) {
281 + $indexable->object_last_modified = \max( $indexable->object_last_modified, $post->post_modified_gmt );
282 + $this->indexable_helper->save_indexable( $indexable );
283 + }
237 284 }
238 285 }
239 286
240 287 /**
@@ -247,9 +294,9 @@
247 294 protected function get_related_indexables( $post ) {
248 295 /**
249 296 * The related indexables.
250 297 *
251 - * @var Indexable[] $related_indexables .
298 + * @var Indexable[] $related_indexables
252 299 */
253 300 $related_indexables = [];
254 301 $related_indexables[] = $this->repository->find_by_id_and_type( $post->post_author, 'user', false );
255 302 $related_indexables[] = $this->repository->find_for_post_type_archive( $post->post_type, false );
@@ -268,9 +315,9 @@
268 315 $term_ids = \array_merge( $term_ids, \wp_list_pluck( $terms, 'term_id' ) );
269 316 }
270 317 $related_indexables = \array_merge(
271 318 $related_indexables,
272 - $this->repository->find_by_multiple_ids_and_type( $term_ids, 'term', false )
319 + $this->repository->find_by_multiple_ids_and_type( $term_ids, 'term', false ),
273 320 );
274 321
275 322 return \array_filter( $related_indexables );
276 323 }