PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 28.3
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v28.3
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 19.1 All 128 releases
wordpress-seo / src / commands / index-command.php

index-command.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 28.3, at src/commands/index-command.php

314 lines 10.5 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\Commands;
4
5 use WP_CLI;
6 use WP_CLI\Utils;
7 use Yoast\WP\Lib\Model;
8 use Yoast\WP\SEO\Actions\Indexing\Indexable_General_Indexation_Action;
9 use Yoast\WP\SEO\Actions\Indexing\Indexable_Indexing_Complete_Action;
10 use Yoast\WP\SEO\Actions\Indexing\Indexable_Post_Indexation_Action;
11 use Yoast\WP\SEO\Actions\Indexing\Indexable_Post_Type_Archive_Indexation_Action;
12 use Yoast\WP\SEO\Actions\Indexing\Indexable_Term_Indexation_Action;
13 use Yoast\WP\SEO\Actions\Indexing\Indexation_Action_Interface;
14 use Yoast\WP\SEO\Actions\Indexing\Indexing_Prepare_Action;
15 use Yoast\WP\SEO\Actions\Indexing\Post_Link_Indexing_Action;
16 use Yoast\WP\SEO\Actions\Indexing\Term_Link_Indexing_Action;
17 use Yoast\WP\SEO\Exceptions\Indexable\Indexing_Failed_Exception;
18 use Yoast\WP\SEO\Helpers\Indexable_Helper;
19 use Yoast\WP\SEO\Main;
20
21 /**
22 * Command to generate indexables for all posts and terms.
23 */
24 class Index_Command implements Command_Interface {
25
26 /**
27 * The post indexation action.
28 *
29 * @var Indexable_Post_Indexation_Action
30 */
31 private $post_indexation_action;
32
33 /**
34 * The term indexation action.
35 *
36 * @var Indexable_Term_Indexation_Action
37 */
38 private $term_indexation_action;
39
40 /**
41 * The post type archive indexation action.
42 *
43 * @var Indexable_Post_Type_Archive_Indexation_Action
44 */
45 private $post_type_archive_indexation_action;
46
47 /**
48 * The general indexation action.
49 *
50 * @var Indexable_General_Indexation_Action
51 */
52 private $general_indexation_action;
53
54 /**
55 * The term link indexing action.
56 *
57 * @var Term_Link_Indexing_Action
58 */
59 private $term_link_indexing_action;
60
61 /**
62 * The post link indexing action.
63 *
64 * @var Post_Link_Indexing_Action
65 */
66 private $post_link_indexing_action;
67
68 /**
69 * The complete indexation action.
70 *
71 * @var Indexable_Indexing_Complete_Action
72 */
73 private $complete_indexation_action;
74
75 /**
76 * The indexing prepare action.
77 *
78 * @var Indexing_Prepare_Action
79 */
80 private $prepare_indexing_action;
81
82 /**
83 * Represents the indexable helper.
84 *
85 * @var Indexable_Helper
86 */
87 protected $indexable_helper;
88
89 /**
90 * Generate_Indexables_Command constructor.
91 *
92 * @param Indexable_Post_Indexation_Action $post_indexation_action The post indexation
93 * action.
94 * @param Indexable_Term_Indexation_Action $term_indexation_action The term indexation
95 * action.
96 * @param Indexable_Post_Type_Archive_Indexation_Action $post_type_archive_indexation_action The post type archive
97 * indexation action.
98 * @param Indexable_General_Indexation_Action $general_indexation_action The general indexation
99 * action.
100 * @param Indexable_Indexing_Complete_Action $complete_indexation_action The complete indexation
101 * action.
102 * @param Indexing_Prepare_Action $prepare_indexing_action The prepare indexing
103 * action.
104 * @param Post_Link_Indexing_Action $post_link_indexing_action The post link indexation
105 * action.
106 * @param Term_Link_Indexing_Action $term_link_indexing_action The term link indexation
107 * action.
108 * @param Indexable_Helper $indexable_helper The indexable helper.
109 */
110 public function __construct(
111 Indexable_Post_Indexation_Action $post_indexation_action,
112 Indexable_Term_Indexation_Action $term_indexation_action,
113 Indexable_Post_Type_Archive_Indexation_Action $post_type_archive_indexation_action,
114 Indexable_General_Indexation_Action $general_indexation_action,
115 Indexable_Indexing_Complete_Action $complete_indexation_action,
116 Indexing_Prepare_Action $prepare_indexing_action,
117 Post_Link_Indexing_Action $post_link_indexing_action,
118 Term_Link_Indexing_Action $term_link_indexing_action,
119 Indexable_Helper $indexable_helper
120 ) {
121 $this->post_indexation_action = $post_indexation_action;
122 $this->term_indexation_action = $term_indexation_action;
123 $this->post_type_archive_indexation_action = $post_type_archive_indexation_action;
124 $this->general_indexation_action = $general_indexation_action;
125 $this->complete_indexation_action = $complete_indexation_action;
126 $this->prepare_indexing_action = $prepare_indexing_action;
127 $this->post_link_indexing_action = $post_link_indexing_action;
128 $this->term_link_indexing_action = $term_link_indexing_action;
129 $this->indexable_helper = $indexable_helper;
130 }
131
132 /**
133 * Gets the namespace.
134 *
135 * @return string
136 */
137 public static function get_namespace() {
138 return Main::WP_CLI_NAMESPACE;
139 }
140
141 /**
142 * Indexes all your content to ensure the best performance.
143 *
144 * ## OPTIONS
145 *
146 * [--network]
147 * : Performs the indexation on all sites within the network.
148 *
149 * [--reindex]
150 * : Removes all existing indexables and then reindexes them.
151 *
152 * [--skip-confirmation]
153 * : Skips the confirmations (for automated systems).
154 *
155 * [--interval=<interval>]
156 * : The number of microseconds (millionths of a second) to wait between index actions.
157 * ---
158 * default: 500000
159 * ---
160 *
161 * ## EXAMPLES
162 *
163 * wp yoast index
164 *
165 * @when after_wp_load
166 *
167 * @param array<string>|null $args The arguments.
168 * @param array<string, string|bool>|null $assoc_args The associative arguments.
169 *
170 * @return void
171 */
172 public function index( $args = null, $assoc_args = null ) {
173 if ( ! $this->indexable_helper->should_index_indexables() ) {
174 WP_CLI::log(
175 \__( 'Your WordPress environment is running on a non-production site. Indexables can only be created on production environments. Please check your `WP_ENVIRONMENT_TYPE` settings.', 'wordpress-seo' ),
176 );
177
178 return;
179 }
180
181 if ( ! isset( $assoc_args['network'] ) ) {
182 $this->run_indexation_actions( $assoc_args );
183
184 return;
185 }
186
187 $criteria = [
188 'fields' => 'ids',
189 'spam' => 0,
190 'deleted' => 0,
191 'archived' => 0,
192 ];
193 $blog_ids = \get_sites( $criteria );
194
195 foreach ( $blog_ids as $blog_id ) {
196 \switch_to_blog( $blog_id );
197 \do_action( '_yoast_run_migrations' );
198 $this->run_indexation_actions( $assoc_args );
199 \restore_current_blog();
200 }
201 }
202
203 /**
204 * Runs all indexation actions.
205 *
206 * @param array<string, string|bool> $assoc_args The associative arguments.
207 *
208 * @return void
209 */
210 protected function run_indexation_actions( $assoc_args ) {
211 // See if we need to clear all indexables before repopulating.
212 if ( isset( $assoc_args['reindex'] ) ) {
213
214 // Argument --skip-confirmation to prevent confirmation (for automated systems).
215 if ( ! isset( $assoc_args['skip-confirmation'] ) ) {
216 WP_CLI::confirm( 'This will clear all previously indexed objects. Are you certain you wish to proceed?' );
217 }
218
219 // Truncate the tables.
220 $this->clear();
221
222 // Delete the transients to make sure re-indexing runs every time.
223 \delete_transient( Indexable_Post_Indexation_Action::UNINDEXED_COUNT_TRANSIENT );
224 \delete_transient( Indexable_Post_Type_Archive_Indexation_Action::UNINDEXED_COUNT_TRANSIENT );
225 \delete_transient( Indexable_Term_Indexation_Action::UNINDEXED_COUNT_TRANSIENT );
226 }
227
228 $indexation_actions = [
229 'posts' => $this->post_indexation_action,
230 'terms' => $this->term_indexation_action,
231 'post type archives' => $this->post_type_archive_indexation_action,
232 'general objects' => $this->general_indexation_action,
233 'post links' => $this->post_link_indexing_action,
234 'term links' => $this->term_link_indexing_action,
235 ];
236
237 $this->prepare_indexing_action->prepare();
238
239 $interval = (int) $assoc_args['interval'];
240 foreach ( $indexation_actions as $name => $indexation_action ) {
241 $this->run_indexation_action( $name, $indexation_action, $interval );
242 }
243
244 $this->complete_indexation_action->complete();
245 }
246
247 /**
248 * Runs an indexation action.
249 *
250 * @param string $name The name of the object to be indexed.
251 * @param Indexation_Action_Interface $indexation_action The indexation action.
252 * @param int $interval Number of microseconds (millionths of a second) to wait between index actions.
253 *
254 * @return void
255 */
256 protected function run_indexation_action( $name, Indexation_Action_Interface $indexation_action, $interval ) {
257 $total = $indexation_action->get_total_unindexed();
258 if ( $total > 0 ) {
259 $limit = $indexation_action->get_limit();
260 $progress = Utils\make_progress_bar( 'Indexing ' . $name, $total );
261 do {
262 try {
263 $indexables = $indexation_action->index();
264 } catch ( Indexing_Failed_Exception $exception ) {
265 $progress->finish();
266
267 $previous = $exception->getPrevious();
268 WP_CLI::error(
269 \sprintf(
270 'Could not optimize %1$s while indexing %2$s: %3$s',
271 $exception->get_object_description(),
272 $name,
273 ( $previous !== null ) ? $previous->getMessage() : $exception->getMessage(),
274 ),
275 );
276
277 return;
278 }
279 $count = \count( $indexables );
280 $progress->tick( $count );
281 \usleep( $interval );
282 Utils\wp_clear_object_cache();
283 } while ( $count >= $limit );
284 $progress->finish();
285 }
286 }
287
288 /**
289 * Clears the database related to the indexables.
290 *
291 * @return void
292 */
293 protected function clear() {
294 global $wpdb;
295
296 // For the PreparedSQLPlaceholders issue, see: https://github.com/WordPress/WordPress-Coding-Standards/issues/1903.
297 // For the DirectDBQuery issue, see: https://github.com/WordPress/WordPress-Coding-Standards/issues/1947.
298 // phpcs:disable WordPress.DB -- Table names should not be quoted and truncate queries can not be cached.
299 $wpdb->query(
300 $wpdb->prepare(
301 'TRUNCATE TABLE %1$s',
302 Model::get_table_name( 'Indexable' ),
303 ),
304 );
305 $wpdb->query(
306 $wpdb->prepare(
307 'TRUNCATE TABLE %1$s',
308 Model::get_table_name( 'Indexable_Hierarchy' ),
309 ),
310 );
311 // phpcs:enable
312 }
313 }
314