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.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 19.0 All 129 releases
← 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 }