PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 28.2
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v28.2
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
wordpress-seo / src / helpers / indexing-helper.php

indexing-helper.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 28.2, at src/helpers/indexing-helper.php

396 lines 12.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Yoast\WP\SEO\Helpers;
4
5 use Yoast\WP\SEO\Actions\Indexing\Indexable_General_Indexation_Action;
6 use Yoast\WP\SEO\Actions\Indexing\Indexable_Post_Indexation_Action;
7 use Yoast\WP\SEO\Actions\Indexing\Indexable_Post_Type_Archive_Indexation_Action;
8 use Yoast\WP\SEO\Actions\Indexing\Indexable_Term_Indexation_Action;
9 use Yoast\WP\SEO\Actions\Indexing\Indexation_Action_Interface;
10 use Yoast\WP\SEO\Actions\Indexing\Limited_Indexing_Action_Interface;
11 use Yoast\WP\SEO\Actions\Indexing\Post_Link_Indexing_Action;
12 use Yoast\WP\SEO\Actions\Indexing\Term_Link_Indexing_Action;
13 use Yoast\WP\SEO\Config\Indexing_Reasons;
14 use Yoast\WP\SEO\Integrations\Admin\Indexing_Notification_Integration;
15 use Yoast\WP\SEO\Repositories\Indexable_Repository;
16 use Yoast_Notification_Center;
17
18 /**
19 * A helper object for indexing.
20 */
21 class Indexing_Helper {
22
23 /**
24 * The options helper.
25 *
26 * @var Options_Helper
27 */
28 protected $options_helper;
29
30 /**
31 * The date helper.
32 *
33 * @var Date_Helper
34 */
35 protected $date_helper;
36
37 /**
38 * The notification center.
39 *
40 * @var Yoast_Notification_Center
41 */
42 protected $notification_center;
43
44 /**
45 * The indexation actions.
46 *
47 * @var Indexation_Action_Interface[]|Limited_Indexing_Action_Interface[]
48 */
49 protected $indexing_actions;
50
51 /**
52 * The indexation actions that can be done in the background.
53 *
54 * @var Indexation_Action_Interface[]|Limited_Indexing_Action_Interface[]
55 */
56 protected $background_indexing_actions;
57
58 /**
59 * The indexable repository.
60 *
61 * @var Indexable_Repository
62 */
63 protected $indexable_repository;
64
65 /**
66 * Indexing_Helper constructor.
67 *
68 * @param Options_Helper $options_helper The options helper.
69 * @param Date_Helper $date_helper The date helper.
70 * @param Yoast_Notification_Center $notification_center The notification center.
71 */
72 public function __construct(
73 Options_Helper $options_helper,
74 Date_Helper $date_helper,
75 Yoast_Notification_Center $notification_center
76 ) {
77 $this->options_helper = $options_helper;
78 $this->date_helper = $date_helper;
79 $this->notification_center = $notification_center;
80 }
81
82 /**
83 * Sets the actions.
84 *
85 * @required
86 *
87 * @param Indexable_Post_Indexation_Action $post_indexation The post indexing action.
88 * @param Indexable_Term_Indexation_Action $term_indexation The term indexing action.
89 * @param Indexable_Post_Type_Archive_Indexation_Action $post_type_archive_indexation The posttype indexing action.
90 * @param Indexable_General_Indexation_Action $general_indexation The general indexing (homepage etc) action.
91 * @param Post_Link_Indexing_Action $post_link_indexing_action The post crosslink indexing action.
92 * @param Term_Link_Indexing_Action $term_link_indexing_action The term crossling indexing action.
93 *
94 * @return void
95 */
96 public function set_indexing_actions(
97 Indexable_Post_Indexation_Action $post_indexation,
98 Indexable_Term_Indexation_Action $term_indexation,
99 Indexable_Post_Type_Archive_Indexation_Action $post_type_archive_indexation,
100 Indexable_General_Indexation_Action $general_indexation,
101 Post_Link_Indexing_Action $post_link_indexing_action,
102 Term_Link_Indexing_Action $term_link_indexing_action
103 ) {
104 $this->indexing_actions = [
105 $post_indexation,
106 $term_indexation,
107 $post_type_archive_indexation,
108 $general_indexation,
109 $post_link_indexing_action,
110 $term_link_indexing_action,
111 ];
112
113 // Coincidentally, the background indexing actions are the same with the Free indexing actions for now.
114 $this->background_indexing_actions = $this->indexing_actions;
115 }
116
117 /**
118 * Sets the indexable repository for the indexing helper class.
119 *
120 * @required
121 *
122 * @param Indexable_Repository $indexable_repository The indexable repository.
123 *
124 * @return void
125 */
126 public function set_indexable_repository( Indexable_Repository $indexable_repository ) {
127 $this->indexable_repository = $indexable_repository;
128 }
129
130 /**
131 * Prepares the indexing process by setting several database options and removing the indexing notification.
132 *
133 * @return void
134 */
135 public function prepare() {
136 $this->set_first_time( false );
137 $this->set_started( $this->date_helper->current_time() );
138 $this->remove_indexing_notification();
139 // Do not set_reason here; if the process is cancelled, the reason to start indexing is still valid.
140 }
141
142 /**
143 * Sets several database options when the indexing process is finished.
144 *
145 * @return void
146 */
147 public function complete() {
148 $this->set_reason( '' );
149 $this->set_started( null );
150 }
151
152 /**
153 * Sets appropriate flags when the indexing process fails.
154 *
155 * @return void
156 */
157 public function indexing_failed() {
158 $this->set_reason( Indexing_Reasons::REASON_INDEXING_FAILED );
159 $this->set_started( null );
160 }
161
162 /**
163 * Sets the indexing reason.
164 *
165 * @param string $reason The indexing reason.
166 *
167 * @return void
168 */
169 public function set_reason( $reason ) {
170 $this->options_helper->set( 'indexing_reason', $reason );
171 $this->remove_indexing_notification();
172 }
173
174 /**
175 * Removes any pre-existing notification, so that a new notification (with a possible new reason) can be added.
176 *
177 * @return void
178 */
179 protected function remove_indexing_notification() {
180 $this->notification_center->remove_notification_by_id(
181 Indexing_Notification_Integration::NOTIFICATION_ID,
182 );
183 }
184
185 /**
186 * Determines whether an indexing reason has been set in the options.
187 *
188 * @return bool Whether an indexing reason has been set in the options.
189 */
190 public function has_reason() {
191 $reason = $this->get_reason();
192
193 return ! empty( $reason );
194 }
195
196 /**
197 * Returns the indexing reason. The reason why the site-wide indexing process should be run.
198 *
199 * @return string The indexing reason, defaults to the empty string if no reason has been set.
200 */
201 public function get_reason() {
202 return $this->options_helper->get( 'indexing_reason', '' );
203 }
204
205 /**
206 * Sets the start time when the indexing process has started but not completed.
207 *
208 * @param int|bool $timestamp The start time when the indexing process has started but not completed, false otherwise.
209 *
210 * @return void
211 */
212 public function set_started( $timestamp ) {
213 $this->options_helper->set( 'indexing_started', $timestamp );
214 }
215
216 /**
217 * Gets the start time when the indexing process has started but not completed.
218 *
219 * @return int|bool The start time when the indexing process has started but not completed, false otherwise.
220 */
221 public function get_started() {
222 return $this->options_helper->get( 'indexing_started' );
223 }
224
225 /**
226 * Sets a boolean that indicates whether or not a site still has to be indexed for the first time.
227 *
228 * @param bool $is_first_time_indexing Whether or not a site still has to be indexed for the first time.
229 *
230 * @return void
231 */
232 public function set_first_time( $is_first_time_indexing ) {
233 $this->options_helper->set( 'indexing_first_time', $is_first_time_indexing );
234 }
235
236 /**
237 * Gets a boolean that indicates whether or not the site still has to be indexed for the first time.
238 *
239 * @return bool Whether the site still has to be indexed for the first time.
240 */
241 public function is_initial_indexing() {
242 return $this->options_helper->get( 'indexing_first_time', true );
243 }
244
245 /**
246 * Gets a boolean that indicates whether or not the indexing of the indexables has completed.
247 *
248 * @return bool Whether the indexing of the indexables has completed.
249 */
250 public function is_finished_indexables_indexing() {
251 return $this->options_helper->get( 'indexables_indexing_completed', false );
252 }
253
254 /**
255 * Returns the total number of unindexed objects.
256 *
257 * @return int The total number of unindexed objects.
258 */
259 public function get_unindexed_count() {
260 $unindexed_count = 0;
261
262 foreach ( $this->indexing_actions as $indexing_action ) {
263 $unindexed_count += $indexing_action->get_total_unindexed();
264 }
265
266 return $unindexed_count;
267 }
268
269 /**
270 * Returns the amount of un-indexed posts expressed in percentage, which will be needed to set a threshold.
271 *
272 * @param int $unindexed_count The number of unindexed objects.
273 *
274 * @return int The amount of unindexed posts expressed in percentage.
275 */
276 public function get_unindexed_percentage( $unindexed_count ) {
277 // Gets the amount of indexed objects in the site.
278 $indexed_count = $this->indexable_repository->get_total_number_of_indexables();
279 // The total amount of objects in the site.
280 $total_objects_count = ( $indexed_count + $unindexed_count );
281
282 return ( ( $unindexed_count / $total_objects_count ) * 100 );
283 }
284
285 /**
286 * Returns whether the SEO optimization button should show.
287 *
288 * @return bool Whether the SEO optimization button should show.
289 */
290 public function should_show_optimization_button() {
291 // Gets the amount of unindexed objects in the site.
292 $unindexed_count = $this->get_filtered_unindexed_count();
293
294 // If the amount of unidexed posts is <10 don't show configuration button.
295 if ( $unindexed_count <= 10 ) {
296 return false;
297 }
298 // If the amount of unidexed posts is >10, but the total amount of unidexed posts is ≤4% of the total amount of objects in the site, don't show configuration button.
299 if ( $this->get_unindexed_percentage( $unindexed_count ) <= 4 ) {
300 return false;
301 }
302 return true;
303 }
304
305 /**
306 * Returns the total number of unindexed objects and applies a filter for third party integrations.
307 *
308 * @return int The total number of unindexed objects.
309 */
310 public function get_filtered_unindexed_count() {
311 $unindexed_count = $this->get_unindexed_count();
312
313 /**
314 * Filter: 'wpseo_indexing_get_unindexed_count' - Allow changing the amount of unindexed objects.
315 *
316 * @param int $unindexed_count The amount of unindexed objects.
317 */
318 return \apply_filters( 'wpseo_indexing_get_unindexed_count', $unindexed_count );
319 }
320
321 /**
322 * Returns a limited number of unindexed objects.
323 *
324 * @param int $limit Limit the number of unindexed objects that are counted.
325 * @param Indexation_Action_Interface[]|Limited_Indexing_Action_Interface[] $actions The actions whose counts will be calculated.
326 *
327 * @return int The total number of unindexed objects.
328 */
329 public function get_limited_unindexed_count( $limit, $actions = [] ) {
330 $unindexed_count = 0;
331
332 if ( empty( $actions ) ) {
333 $actions = $this->indexing_actions;
334 }
335
336 foreach ( $actions as $action ) {
337 $unindexed_count += $action->get_limited_unindexed_count( $limit - $unindexed_count + 1 );
338 if ( $unindexed_count > $limit ) {
339 return $unindexed_count;
340 }
341 }
342
343 return $unindexed_count;
344 }
345
346 /**
347 * Returns the total number of unindexed objects and applies a filter for third party integrations.
348 *
349 * @param int $limit Limit the number of unindexed objects that are counted.
350 *
351 * @return int The total number of unindexed objects.
352 */
353 public function get_limited_filtered_unindexed_count( $limit ) {
354 $unindexed_count = $this->get_limited_unindexed_count( $limit, $this->indexing_actions );
355
356 if ( $unindexed_count > $limit ) {
357 return $unindexed_count;
358 }
359
360 /**
361 * Filter: 'wpseo_indexing_get_limited_unindexed_count' - Allow changing the amount of unindexed objects,
362 * and allow for a maximum number of items counted to improve performance.
363 *
364 * @param int $unindexed_count The amount of unindexed objects.
365 * @param int|false $limit Limit the number of unindexed objects that need to be counted.
366 * False if it doesn't need to be limited.
367 */
368 return \apply_filters( 'wpseo_indexing_get_limited_unindexed_count', $unindexed_count, $limit );
369 }
370
371 /**
372 * Returns the total number of unindexed objects that can be indexed in the background and applies a filter for third party integrations.
373 *
374 * @param int $limit Limit the number of unindexed objects that are counted.
375 *
376 * @return int The total number of unindexed objects that can be indexed in the background.
377 */
378 public function get_limited_filtered_unindexed_count_background( $limit ) {
379 $unindexed_count = $this->get_limited_unindexed_count( $limit, $this->background_indexing_actions );
380
381 if ( $unindexed_count > $limit ) {
382 return $unindexed_count;
383 }
384
385 /**
386 * Filter: 'wpseo_indexing_get_limited_unindexed_count_background' - Allow changing the amount of unindexed objects that can be indexed in the background,
387 * and allow for a maximum number of items counted to improve performance.
388 *
389 * @param int $unindexed_count The amount of unindexed objects.
390 * @param int|false $limit Limit the number of unindexed objects that need to be counted.
391 * False if it doesn't need to be limited.
392 */
393 return \apply_filters( 'wpseo_indexing_get_limited_unindexed_count_background', $unindexed_count, $limit );
394 }
395 }
396