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

Yoast / wordpress-seo / b961a40c4e03131cc8c75ccf8d5090e5e16f19f9

05 Jul 2024 01:16PM UTC coverage: 54.068% (+5.4%) from 48.645%
b961a40c4e03131cc8c75ccf8d5090e5e16f19f9

push

github

mhkuu
Merge branch 'trunk' of github.com:Yoast/wordpress-seo into feature/fix-assessments

7451 of 13463 branches covered (55.34%)

Branch coverage included in aggregate %.

287 of 380 new or added lines in 34 files covered. (75.53%)

1 existing line in 1 file now uncovered.

29380 of 54657 relevant lines covered (53.75%)

61031.68 hits per line

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

84.67
/src/integrations/cleanup-integration.php
1
<?php
2

3
namespace Yoast\WP\SEO\Integrations;
4

5
use Closure;
6
use Yoast\WP\SEO\Helpers\Indexable_Helper;
7
use Yoast\WP\SEO\Repositories\Indexable_Cleanup_Repository;
8

9
/**
10
 * Adds cleanup hooks.
11
 */
12
class Cleanup_Integration implements Integration_Interface {
13

14
        /**
15
         * Identifier used to determine the current task.
16
         */
17
        public const CURRENT_TASK_OPTION = 'wpseo-cleanup-current-task';
18

19
        /**
20
         * Identifier for the cron job.
21
         */
22
        public const CRON_HOOK = 'wpseo_cleanup_cron';
23

24
        /**
25
         * Identifier for starting the cleanup.
26
         */
27
        public const START_HOOK = 'wpseo_start_cleanup_indexables';
28

29
        /**
30
         * The indexable helper.
31
         *
32
         * @var Indexable_Helper
33
         */
34
        private $indexable_helper;
35

36
        /**
37
         * The cleanup repository.
38
         *
39
         * @var Indexable_Cleanup_Repository
40
         */
41
        private $cleanup_repository;
42

43
        /**
44
         * The constructor.
45
         *
46
         * @param Indexable_Cleanup_Repository $cleanup_repository The cleanup repository.
47
         * @param Indexable_Helper             $indexable_helper   The indexable helper.
48
         */
NEW
49
        public function __construct(
×
50
                Indexable_Cleanup_Repository $cleanup_repository,
51
                Indexable_Helper $indexable_helper
52
        ) {
UNCOV
53
                $this->cleanup_repository = $cleanup_repository;
×
NEW
54
                $this->indexable_helper   = $indexable_helper;
×
55
        }
56

57
        /**
58
         * Initializes the integration.
59
         *
60
         * This is the place to register hooks and filters.
61
         *
62
         * @return void
63
         */
64
        public function register_hooks() {
2✔
65
                \add_action( self::START_HOOK, [ $this, 'run_cleanup' ] );
2✔
66
                \add_action( self::CRON_HOOK, [ $this, 'run_cleanup_cron' ] );
2✔
67
                \add_action( 'wpseo_deactivate', [ $this, 'reset_cleanup' ] );
2✔
68
        }
1✔
69

70
        /**
71
         * Returns the conditionals based on which this loadable should be active.
72
         *
73
         * @return array<string> The array of conditionals.
74
         */
75
        public static function get_conditionals() {
2✔
76
                return [];
2✔
77
        }
78

79
        /**
80
         * Starts the indexables cleanup.
81
         *
82
         * @return void
83
         */
84
        public function run_cleanup() {
6✔
85
                $this->reset_cleanup();
6✔
86

87
                if ( ! $this->indexable_helper->should_index_indexables() ) {
6✔
NEW
88
                        \wp_unschedule_hook( self::START_HOOK );
×
NEW
89
                        return;
×
90
                }
91

92
                $cleanups = $this->get_cleanup_tasks();
6✔
93
                $limit    = $this->get_limit();
6✔
94

95
                foreach ( $cleanups as $name => $action ) {
6✔
96
                        $items_cleaned = $action( $limit );
6✔
97

98
                        if ( $items_cleaned === false ) {
6✔
99
                                return;
2✔
100
                        }
101

102
                        if ( $items_cleaned < $limit ) {
4✔
103
                                continue;
2✔
104
                        }
105

106
                        // There are more items to delete for the current cleanup job, start a cronjob at the specified job.
107
                        $this->start_cron_job( $name );
2✔
108

109
                        return;
2✔
110
                }
111
        }
1✔
112

113
        /**
114
         * Returns an array of cleanup tasks.
115
         *
116
         * @return Closure[] The cleanup tasks.
117
         */
118
        public function get_cleanup_tasks() {
16✔
119
                return \array_merge(
16✔
120
                        [
8✔
121
                                'clean_indexables_with_object_type_and_object_sub_type_shop_order' => function ( $limit ) {
8✔
122
                                        return $this->cleanup_repository->clean_indexables_with_object_type_and_object_sub_type( 'post', 'shop_order', $limit );
8✔
123
                                },
16✔
124
                                'clean_indexables_by_post_status_auto-draft' => function ( $limit ) {
8✔
125
                                        return $this->cleanup_repository->clean_indexables_with_post_status( 'auto-draft', $limit );
8✔
126
                                },
16✔
127
                                'clean_indexables_for_non_publicly_viewable_post' => function ( $limit ) {
8✔
128
                                        return $this->cleanup_repository->clean_indexables_for_non_publicly_viewable_post( $limit );
2✔
129
                                },
16✔
130
                                'clean_indexables_for_non_publicly_viewable_taxonomies' => function ( $limit ) {
8✔
131
                                        return $this->cleanup_repository->clean_indexables_for_non_publicly_viewable_taxonomies( $limit );
2✔
132
                                },
16✔
133
                                'clean_indexables_for_non_publicly_viewable_post_type_archive_pages' => function ( $limit ) {
8✔
134
                                        return $this->cleanup_repository->clean_indexables_for_non_publicly_viewable_post_type_archive_pages( $limit );
2✔
135
                                },
16✔
136
                                'clean_indexables_for_authors_archive_disabled' => function ( $limit ) {
8✔
137
                                        return $this->cleanup_repository->clean_indexables_for_authors_archive_disabled( $limit );
2✔
138
                                },
16✔
139
                                'clean_indexables_for_authors_without_archive' => function ( $limit ) {
8✔
140
                                        return $this->cleanup_repository->clean_indexables_for_authors_without_archive( $limit );
2✔
141
                                },
16✔
142
                                'update_indexables_author_to_reassigned' => function ( $limit ) {
8✔
143
                                        return $this->cleanup_repository->update_indexables_author_to_reassigned( $limit );
2✔
144
                                },
16✔
145
                                'clean_orphaned_user_indexables_without_wp_user' => function ( $limit ) {
8✔
146
                                        return $this->cleanup_repository->clean_indexables_for_orphaned_users( $limit );
2✔
147
                                },
16✔
148
                                'clean_orphaned_user_indexables_without_wp_post' => function ( $limit ) {
8✔
149
                                        return $this->cleanup_repository->clean_indexables_for_object_type_and_source_table( 'posts', 'ID', 'post', $limit );
2✔
150
                                },
16✔
151
                                'clean_orphaned_user_indexables_without_wp_term' => function ( $limit ) {
8✔
152
                                        return $this->cleanup_repository->clean_indexables_for_object_type_and_source_table( 'terms', 'term_id', 'term', $limit );
2✔
153
                                },
16✔
154
                        ],
8✔
155
                        $this->get_additional_indexable_cleanups(),
16✔
156
                        [
8✔
157
                                /* These should always be the last ones to be called. */
158
                                'clean_orphaned_content_indexable_hierarchy' => function ( $limit ) {
8✔
159
                                        return $this->cleanup_repository->cleanup_orphaned_from_table( 'Indexable_Hierarchy', 'indexable_id', $limit );
2✔
160
                                },
16✔
161
                                'clean_orphaned_content_seo_links_indexable_id' => function ( $limit ) {
8✔
162
                                        return $this->cleanup_repository->cleanup_orphaned_from_table( 'SEO_Links', 'indexable_id', $limit );
2✔
163
                                },
16✔
164
                                'clean_orphaned_content_seo_links_target_indexable_id' => function ( $limit ) {
8✔
165
                                        return $this->cleanup_repository->cleanup_orphaned_from_table( 'SEO_Links', 'target_indexable_id', $limit );
4✔
166
                                },
16✔
167

168
                        ],
8✔
169
                        $this->get_additional_misc_cleanups()
16✔
170
                );
8✔
171
        }
172

173
        /**
174
         * Gets additional tasks from the 'wpseo_cleanup_tasks' filter.
175
         *
176
         * @return Closure[] Associative array of indexable cleanup functions.
177
         */
178
        private function get_additional_indexable_cleanups() {
×
179

180
                /**
181
                 * Filter: Adds the possibility to add additional indexable cleanup functions.
182
                 *
183
                 * @param array $additional_tasks Associative array with unique keys. Value should be a cleanup function that receives a limit.
184
                 */
185
                $additional_tasks = \apply_filters( 'wpseo_cleanup_tasks', [] );
×
186

187
                return $this->validate_additional_tasks( $additional_tasks );
×
188
        }
189

190
        /**
191
         * Gets additional tasks from the 'wpseo_misc_cleanup_tasks' filter.
192
         *
193
         * @return Closure[] Associative array of indexable cleanup functions.
194
         */
195
        private function get_additional_misc_cleanups() {
×
196

197
                /**
198
                 * Filter: Adds the possibility to add additional non-indexable cleanup functions.
199
                 *
200
                 * @param array $additional_tasks Associative array with unique keys. Value should be a cleanup function that receives a limit.
201
                 */
202
                $additional_tasks = \apply_filters( 'wpseo_misc_cleanup_tasks', [] );
×
203

204
                return $this->validate_additional_tasks( $additional_tasks );
×
205
        }
206

207
        /**
208
         * Validates the additional tasks.
209
         *
210
         * @param Closure[] $additional_tasks The additional tasks to validate.
211
         *
212
         * @return Closure[] The validated additional tasks.
213
         */
214
        private function validate_additional_tasks( $additional_tasks ) {
×
215
                if ( ! \is_array( $additional_tasks ) ) {
×
216
                        return [];
×
217
                }
218

219
                foreach ( $additional_tasks as $key => $value ) {
×
220
                        if ( \is_int( $key ) ) {
×
221
                                return [];
×
222
                        }
223
                        if ( ( ! \is_object( $value ) ) || ! ( $value instanceof Closure ) ) {
×
224
                                return [];
×
225
                        }
226
                }
227

228
                return $additional_tasks;
×
229
        }
230

231
        /**
232
         * Gets the deletion limit for cleanups.
233
         *
234
         * @return int The limit for the amount of entities to be cleaned.
235
         */
236
        private function get_limit() {
16✔
237
                /**
238
                 * Filter: Adds the possibility to limit the number of items that are deleted from the database on cleanup.
239
                 *
240
                 * @param int $limit Maximum number of indexables to be cleaned up per query.
241
                 */
242
                $limit = \apply_filters( 'wpseo_cron_query_limit_size', 1000 );
16✔
243

244
                if ( ! \is_int( $limit ) ) {
16✔
245
                        $limit = 1000;
2✔
246
                }
247

248
                return \abs( $limit );
16✔
249
        }
250

251
        /**
252
         * Resets and stops the cleanup integration.
253
         *
254
         * @return void
255
         */
256
        public function reset_cleanup() {
6✔
257
                \delete_option( self::CURRENT_TASK_OPTION );
6✔
258
                \wp_unschedule_hook( self::CRON_HOOK );
6✔
259
        }
3✔
260

261
        /**
262
         * Starts the cleanup cron job.
263
         *
264
         * @param string $task_name     The task name of the next cleanup task to run.
265
         * @param int    $schedule_time The time in seconds to wait before running the first cron job. Default is 1 hour.
266
         *
267
         * @return void
268
         */
269
        public function start_cron_job( $task_name, $schedule_time = 3600 ) {
2✔
270
                \update_option( self::CURRENT_TASK_OPTION, $task_name );
2✔
271
                \wp_schedule_event(
2✔
272
                        ( \time() + $schedule_time ),
2✔
273
                        'hourly',
2✔
274
                        self::CRON_HOOK
2✔
275
                );
1✔
276
        }
1✔
277

278
        /**
279
         * The callback that is called for the cleanup cron job.
280
         *
281
         * @return void
282
         */
283
        public function run_cleanup_cron() {
14✔
284
                if ( ! $this->indexable_helper->should_index_indexables() ) {
14✔
285
                        $this->reset_cleanup();
2✔
286

287
                        return;
2✔
288
                }
289

290
                $current_task_name = \get_option( self::CURRENT_TASK_OPTION );
12✔
291

292
                if ( $current_task_name === false ) {
12✔
293
                        $this->reset_cleanup();
2✔
294

295
                        return;
2✔
296
                }
297

298
                $limit = $this->get_limit();
10✔
299
                $tasks = $this->get_cleanup_tasks();
10✔
300

301
                // The task may have been added by a filter that has been removed, in that case just start over.
302
                if ( ! isset( $tasks[ $current_task_name ] ) ) {
10✔
303
                        $current_task_name = \key( $tasks );
×
304
                }
305

306
                $current_task = \current( $tasks );
10✔
307
                while ( $current_task !== false ) {
10✔
308
                        // Skip the tasks that have already been done.
309
                        if ( \key( $tasks ) !== $current_task_name ) {
10✔
310
                                $current_task = \next( $tasks );
8✔
311
                                continue;
8✔
312
                        }
313

314
                        // Call the cleanup callback function that accompanies the current task.
315
                        $items_cleaned = $current_task( $limit );
10✔
316

317
                        if ( $items_cleaned === false ) {
10✔
318
                                $this->reset_cleanup();
2✔
319

320
                                return;
2✔
321
                        }
322

323
                        if ( $items_cleaned === 0 ) {
8✔
324
                                // Check if we are finished with all tasks.
325
                                if ( \next( $tasks ) === false ) {
4✔
326
                                        $this->reset_cleanup();
2✔
327

328
                                        return;
2✔
329
                                }
330

331
                                // Continue with the next task next time the cron job is run.
332
                                \update_option( self::CURRENT_TASK_OPTION, \key( $tasks ) );
2✔
333

334
                                return;
2✔
335
                        }
336

337
                        // There were items deleted for the current task, continue with the same task next cron call.
338
                        return;
4✔
339
                }
340
        }
341
}
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