• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / wordpress-seo / b78c91bd80d89b034df841d284a428c954224385

03 Sep 2024 07:50AM UTC coverage: 54.503% (+0.4%) from 54.072%
b78c91bd80d89b034df841d284a428c954224385

push

github

YoastBot
Bump version to 23.4 on free

7504 of 13559 branches covered (55.34%)

Branch coverage included in aggregate %.

29831 of 54942 relevant lines covered (54.3%)

41571.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.78
/src/integrations/admin/background-indexing-integration.php
1
<?php
2

3
namespace Yoast\WP\SEO\Integrations\Admin;
4

5
use Yoast\WP\SEO\Actions\Indexing\Indexable_Indexing_Complete_Action;
6
use Yoast\WP\SEO\Actions\Indexing\Indexation_Action_Interface;
7
use Yoast\WP\SEO\Conditionals\Get_Request_Conditional;
8
use Yoast\WP\SEO\Conditionals\Migrations_Conditional;
9
use Yoast\WP\SEO\Conditionals\WP_CRON_Enabled_Conditional;
10
use Yoast\WP\SEO\Conditionals\Yoast_Admin_And_Dashboard_Conditional;
11
use Yoast\WP\SEO\Helpers\Indexable_Helper;
12
use Yoast\WP\SEO\Helpers\Indexing_Helper;
13
use Yoast\WP\SEO\Integrations\Integration_Interface;
14

15
/**
16
 * Class Background_Indexing_Integration.
17
 *
18
 * @package Yoast\WP\SEO\Integrations\Admin
19
 */
20
class Background_Indexing_Integration implements Integration_Interface {
21

22
        /**
23
         * Represents the indexing completed action.
24
         *
25
         * @var Indexable_Indexing_Complete_Action
26
         */
27
        protected $complete_indexation_action;
28

29
        /**
30
         * Represents the indexing helper.
31
         *
32
         * @var Indexing_Helper
33
         */
34
        protected $indexing_helper;
35

36
        /**
37
         * An object that checks if we are on the Yoast admin or on the dashboard page.
38
         *
39
         * @var Yoast_Admin_And_Dashboard_Conditional
40
         */
41
        protected $yoast_admin_and_dashboard_conditional;
42

43
        /**
44
         * All available indexing actions.
45
         *
46
         * @var Indexation_Action_Interface[]
47
         */
48
        protected $indexing_actions;
49

50
        /**
51
         * An object that checks if we are handling a GET request.
52
         *
53
         * @var Get_Request_Conditional
54
         */
55
        private $get_request_conditional;
56

57
        /**
58
         * An object that checks if WP_CRON is enabled.
59
         *
60
         * @var WP_CRON_Enabled_Conditional
61
         */
62
        private $wp_cron_enabled_conditional;
63

64
        /**
65
         * The indexable helper
66
         *
67
         * @var Indexable_Helper
68
         */
69
        private $indexable_helper;
70

71
        /**
72
         * Shutdown_Indexing_Integration constructor.
73
         *
74
         * @param Indexable_Indexing_Complete_Action    $complete_indexation_action            The complete indexing action.
75
         * @param Indexing_Helper                       $indexing_helper                       The indexing helper.
76
         * @param Indexable_Helper                      $indexable_helper                      The indexable helper.
77
         * @param Yoast_Admin_And_Dashboard_Conditional $yoast_admin_and_dashboard_conditional An object that checks if we are on the Yoast admin or on the dashboard page.
78
         * @param Get_Request_Conditional               $get_request_conditional               An object that checks if we are handling a GET request.
79
         * @param WP_CRON_Enabled_Conditional           $wp_cron_enabled_conditional           An object that checks if WP_CRON is enabled.
80
         * @param Indexation_Action_Interface           ...$indexing_actions                   A list of all available indexing actions.
81
         */
82
        public function __construct(
2✔
83
                Indexable_Indexing_Complete_Action $complete_indexation_action,
84
                Indexing_Helper $indexing_helper,
85
                Indexable_Helper $indexable_helper,
86
                Yoast_Admin_And_Dashboard_Conditional $yoast_admin_and_dashboard_conditional,
87
                Get_Request_Conditional $get_request_conditional,
88
                WP_CRON_Enabled_Conditional $wp_cron_enabled_conditional,
89
                Indexation_Action_Interface ...$indexing_actions
90
        ) {
1✔
91
                $this->indexing_actions                      = $indexing_actions;
2✔
92
                $this->complete_indexation_action            = $complete_indexation_action;
2✔
93
                $this->indexing_helper                       = $indexing_helper;
2✔
94
                $this->indexable_helper                      = $indexable_helper;
2✔
95
                $this->yoast_admin_and_dashboard_conditional = $yoast_admin_and_dashboard_conditional;
2✔
96
                $this->get_request_conditional               = $get_request_conditional;
2✔
97
                $this->wp_cron_enabled_conditional           = $wp_cron_enabled_conditional;
2✔
98
        }
1✔
99

100
        /**
101
         * Returns the conditionals based on which this integration should be active.
102
         *
103
         * @return array The array of conditionals.
104
         */
105
        public static function get_conditionals() {
2✔
106
                return [
1✔
107
                        Migrations_Conditional::class,
2✔
108
                ];
1✔
109
        }
110

111
        /**
112
         * Register hooks.
113
         *
114
         * @return void
115
         */
116
        public function register_hooks() {
2✔
117
                \add_action( 'admin_init', [ $this, 'register_shutdown_indexing' ] );
2✔
118
                \add_action( 'wpseo_indexable_index_batch', [ $this, 'index' ] );
2✔
119
                // phpcs:ignore WordPress.WP.CronInterval -- The sniff doesn't understand values with parentheses. https://github.com/WordPress/WordPress-Coding-Standards/issues/2025
120
                \add_filter( 'cron_schedules', [ $this, 'add_cron_schedule' ] );
2✔
121
                \add_action( 'admin_init', [ $this, 'schedule_cron_indexing' ], 11 );
2✔
122

123
                $this->add_limit_filters();
2✔
124
        }
1✔
125

126
        /**
127
         * Adds the filters that change the indexing limits.
128
         *
129
         * @return void.
130
         */
131
        public function add_limit_filters() {
2✔
132
                \add_filter( 'wpseo_post_indexation_limit', [ $this, 'throttle_cron_indexing' ] );
2✔
133
                \add_filter( 'wpseo_post_type_archive_indexation_limit', [ $this, 'throttle_cron_indexing' ] );
2✔
134
                \add_filter( 'wpseo_term_indexation_limit', [ $this, 'throttle_cron_indexing' ] );
2✔
135
                \add_filter( 'wpseo_prominent_words_indexation_limit', [ $this, 'throttle_cron_indexing' ] );
2✔
136
                \add_filter( 'wpseo_link_indexing_limit', [ $this, 'throttle_cron_link_indexing' ] );
2✔
137
        }
1✔
138

139
        /**
140
         * Enqueues the required scripts.
141
         *
142
         * @return void
143
         */
144
        public function register_shutdown_indexing() {
12✔
145
                if ( $this->should_index_on_shutdown( $this->get_shutdown_limit() ) ) {
12✔
146
                        $this->register_shutdown_function( 'index' );
2✔
147
                }
148
        }
6✔
149

150
        /**
151
         * Run a single indexing pass of each indexing action. Intended for use as a shutdown function.
152
         *
153
         * @return void
154
         */
155
        public function index() {
12✔
156
                if ( \wp_doing_cron() && ! $this->should_index_on_cron() ) {
12✔
157
                        $this->unschedule_cron_indexing();
8✔
158

159
                        return;
8✔
160
                }
161

162
                foreach ( $this->indexing_actions as $indexation_action ) {
4✔
163
                        $indexation_action->index();
4✔
164
                }
165

166
                if ( $this->indexing_helper->get_limited_filtered_unindexed_count_background( 1 ) === 0 ) {
4✔
167
                        // We set this as complete, even though prominent words might not be complete. But that's the way we always treated that.
168
                        $this->complete_indexation_action->complete();
4✔
169
                }
170
        }
2✔
171

172
        /**
173
         * Adds the 'Every fifteen minutes' cron schedule to WP-Cron.
174
         *
175
         * @param array $schedules The existing schedules.
176
         *
177
         * @return array The schedules containing the fifteen_minutes schedule.
178
         */
179
        public function add_cron_schedule( $schedules ) {
4✔
180
                if ( ! \is_array( $schedules ) ) {
4✔
181
                        return $schedules;
2✔
182
                }
183

184
                $schedules['fifteen_minutes'] = [
2✔
185
                        'interval' => ( 15 * \MINUTE_IN_SECONDS ),
2✔
186
                        'display'  => \esc_html__( 'Every fifteen minutes', 'wordpress-seo' ),
2✔
187
                ];
1✔
188

189
                return $schedules;
2✔
190
        }
191

192
        /**
193
         * Schedule background indexing every 15 minutes if the index isn't already up to date.
194
         *
195
         * @return void
196
         */
197
        public function schedule_cron_indexing() {
20✔
198
                /**
199
                 * Filter: 'wpseo_unindexed_count_queries_ran' - Informs whether the expensive unindexed count queries have been ran already.
200
                 *
201
                 * @internal
202
                 *
203
                 * @param bool $have_queries_ran
204
                 */
205
                $have_queries_ran = \apply_filters( 'wpseo_unindexed_count_queries_ran', false );
20✔
206

207
                if ( ( ! $this->yoast_admin_and_dashboard_conditional->is_met() || ! $this->get_request_conditional->is_met() ) && ! $have_queries_ran ) {
20✔
208
                        return;
4✔
209
                }
210

211
                if ( ! \wp_next_scheduled( 'wpseo_indexable_index_batch' ) && $this->should_index_on_cron() ) {
16✔
212
                        \wp_schedule_event( ( \time() + \HOUR_IN_SECONDS ), 'fifteen_minutes', 'wpseo_indexable_index_batch' );
6✔
213
                }
214
        }
8✔
215

216
        /**
217
         * Limit cron indexing to 15 indexables per batch instead of 25.
218
         *
219
         * @param int $indexation_limit The current limit (filter input).
220
         *
221
         * @return int The new batch limit.
222
         */
223
        public function throttle_cron_indexing( $indexation_limit ) {
4✔
224
                if ( \wp_doing_cron() ) {
4✔
225
                        /**
226
                         * Filter: 'wpseo_cron_indexing_limit_size' - Adds the possibility to limit the number of items that are indexed when in cron action.
227
                         *
228
                         * @param int $limit Maximum number of indexables to be indexed per indexing action.
229
                         */
230
                        return \apply_filters( 'wpseo_cron_indexing_limit_size', 15 );
2✔
231
                }
232

233
                return $indexation_limit;
2✔
234
        }
235

236
        /**
237
         * Limit cron indexing to 3 links per batch instead of 5.
238
         *
239
         * @param int $link_indexation_limit The current limit (filter input).
240
         *
241
         * @return int The new batch limit.
242
         */
243
        public function throttle_cron_link_indexing( $link_indexation_limit ) {
4✔
244
                if ( \wp_doing_cron() ) {
4✔
245
                        /**
246
                         * Filter: 'wpseo_cron_link_indexing_limit_size' - Adds the possibility to limit the number of links that are indexed when in cron action.
247
                         *
248
                         * @param int $limit Maximum number of link indexables to be indexed per link indexing action.
249
                         */
250
                        return \apply_filters( 'wpseo_cron_link_indexing_limit_size', 3 );
2✔
251
                }
252

253
                return $link_indexation_limit;
2✔
254
        }
255

256
        /**
257
         * Determine whether cron indexation should be performed.
258
         *
259
         * @return bool Should cron indexation be performed.
260
         */
261
        protected function should_index_on_cron() {
24✔
262
                if ( ! $this->indexable_helper->should_index_indexables() ) {
24✔
263
                        return false;
6✔
264
                }
265

266
                // The filter supersedes everything when preventing cron indexation.
267
                if ( \apply_filters( 'Yoast\WP\SEO\enable_cron_indexing', true ) !== true ) {
18✔
268
                        return false;
4✔
269
                }
270

271
                return $this->indexing_helper->get_limited_filtered_unindexed_count_background( 1 ) > 0;
14✔
272
        }
273

274
        /**
275
         * Determine whether background indexation should be performed.
276
         *
277
         * @param int $shutdown_limit The shutdown limit used to determine whether indexation should be run.
278
         *
279
         * @return bool Should background indexation be performed.
280
         */
281
        protected function should_index_on_shutdown( $shutdown_limit ) {
12✔
282
                if ( ! $this->yoast_admin_and_dashboard_conditional->is_met() || ! $this->get_request_conditional->is_met() ) {
12✔
283
                        return false;
4✔
284
                }
285

286
                if ( ! $this->indexable_helper->should_index_indexables() ) {
8✔
287
                        return false;
2✔
288
                }
289

290
                if ( $this->wp_cron_enabled_conditional->is_met() ) {
6✔
291
                        return false;
2✔
292
                }
293

294
                $total_unindexed = $this->indexing_helper->get_limited_filtered_unindexed_count_background( $shutdown_limit );
4✔
295
                if ( $total_unindexed === 0 || $total_unindexed > $shutdown_limit ) {
4✔
296
                        return false;
2✔
297
                }
298

299
                return true;
2✔
300
        }
301

302
        /**
303
         * Retrieves the shutdown limit. This limit is the amount of indexables that is generated in the background.
304
         *
305
         * @return int The shutdown limit.
306
         */
307
        protected function get_shutdown_limit() {
12✔
308
                /**
309
                 * Filter 'wpseo_shutdown_indexation_limit' - Allow filtering the number of objects that can be indexed during shutdown.
310
                 *
311
                 * @param int $limit The maximum number of objects indexed.
312
                 */
313
                return \apply_filters( 'wpseo_shutdown_indexation_limit', 25 );
12✔
314
        }
315

316
        /**
317
         * Removes the cron indexing job from the scheduled event queue.
318
         *
319
         * @return void
320
         */
321
        protected function unschedule_cron_indexing() {
2✔
322
                $scheduled = \wp_next_scheduled( 'wpseo_indexable_index_batch' );
2✔
323
                if ( $scheduled ) {
2✔
324
                        \wp_unschedule_event( $scheduled, 'wpseo_indexable_index_batch' );
2✔
325
                }
326
        }
1✔
327

328
        /**
329
         * Registers a method to be executed on shutdown.
330
         * This wrapper mostly exists for making this class more unittestable.
331
         *
332
         * @param string $method_name The name of the method on the current instance to register.
333
         *
334
         * @return void
335
         */
336
        protected function register_shutdown_function( $method_name ) {
×
337
                \register_shutdown_function( [ $this, $method_name ] );
×
338
        }
339
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc