PluginProbe
ElasticPress / 5.3.5
ElasticPress v5.3.5
5.3.5 5.3.4 3.6.5 3.6.6 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.4.0 4.4.1 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.7.0 4.7.1 4.7.2 5.0.0 5.0.1 5.0.2 All 108 releases
← All changes | includes/classes/Command.php +384 -251 4.4.05.3.5 View file →
@@ -9,18 +9,21 @@
9 9 */
10 10
11 11 namespace ElasticPress;
12 12
13 -use \WP_CLI_Command as WP_CLI_Command;
14 -use \WP_CLI as WP_CLI;
15 -use \WP_Hook as WP_Hook;
16 -use ElasticPress\Features as Features;
17 -use ElasticPress\Utils as Utils;
18 -use ElasticPress\Elasticsearch as Elasticsearch;
19 -use ElasticPress\Indexables as Indexables;
13 +use WP_CLI_Command;
14 +use WP_CLI;
15 +use ElasticPress\Command\Utility;
16 +use ElasticPress\Elasticsearch;
17 +use ElasticPress\FeatureRequirementsStatus;
18 +use ElasticPress\Features;
19 +use ElasticPress\Indexables;
20 +use ElasticPress\Utils;
20 21
21 22 if ( ! defined( 'ABSPATH' ) ) {
23 + // @codeCoverageIgnoreStart
22 24 exit; // Exit if accessed directly.
25 + // @codeCoverageIgnoreEnd
23 26 }
24 27
25 28 /**
26 29 * CLI Commands for ElasticPress
@@ -71,9 +74,9 @@
71 74 *
72 75 * @since 3.5.2
73 76 */
74 77 public function __construct() {
75 - add_filter( 'pre_transient_ep_wpcli_sync_interrupted', [ $this, 'custom_get_transient' ], 10, 2 );
78 + add_filter( 'pre_transient_ep_wpcli_sync_interrupted', [ Utility::class, 'custom_get_transient' ], 10, 2 );
76 79 }
77 80
78 81 /**
79 82 * Activate a feature. If a re-indexing is required, you will need to do it manually.
@@ -102,14 +105,14 @@
102 105 }
103 106
104 107 $status = $feature->requirements_status();
105 108
106 - if ( 2 === $status->code ) {
109 + if ( FeatureRequirementsStatus::FORCE_DISABLED === $status->get_code() ) {
107 110 /* translators: Error message */
108 - WP_CLI::error( sprintf( esc_html__( 'Feature requirements are not met: %s', 'elasticpress' ), implode( "\n\n", (array) $status->message ) ) );
109 - } elseif ( 1 === $status->code ) {
111 + WP_CLI::error( sprintf( esc_html__( 'Feature requirements are not met: %s', 'elasticpress' ), implode( "\n\n", (array) $status->get_message() ) ) );
112 + } elseif ( FeatureRequirementsStatus::MANUALLY_ENABLED === $status->get_code() && ! empty( $status->get_message() ) ) {
110 113 /* translators: Warning message */
111 - WP_CLI::warning( sprintf( esc_html__( 'Feature is usable but there are warnings: %s', 'elasticpress' ), implode( "\n\n", (array) $status->message ) ) );
114 + WP_CLI::warning( sprintf( esc_html__( 'Feature is usable but there are warnings: %s', 'elasticpress' ), implode( "\n\n", (array) $status->get_message() ) ) );
112 115 }
113 116
114 117 Features::factory()->activate_feature( $feature->slug );
115 118
@@ -120,9 +123,9 @@
120 123 WP_CLI::success( esc_html__( 'Feature activated', 'elasticpress' ) );
121 124 }
122 125
123 126 /**
124 - * Dectivate a feature.
127 + * Deactivate a feature.
125 128 *
126 129 * ## OPTIONS
127 130 *
128 131 * <feature-slug>
@@ -141,13 +144,18 @@
141 144 if ( empty( $feature ) ) {
142 145 WP_CLI::error( esc_html__( 'No feature with that slug is registered', 'elasticpress' ) );
143 146 }
144 147
145 - $active_features = Utils\get_option( 'ep_feature_settings', [] );
148 + $active_features = (array) Features::factory()->get_feature_settings();
149 + $active_features_draft = (array) Features::factory()->get_feature_settings_draft();
146 150
147 - $key = array_search( $feature->slug, array_keys( $active_features ), true );
151 + $key_current = array_search( $feature->slug, array_keys( $active_features ), true );
152 + $key_draft = array_search( $feature->slug, array_keys( $active_features_draft ), true );
148 153
149 - if ( false === $key || empty( $active_features[ $feature->slug ]['active'] ) ) {
154 + $in_current = false !== $key_current && ! empty( $active_features[ $feature->slug ]['active'] );
155 + $in_draft = false !== $key_draft && ! empty( $active_features_draft[ $feature->slug ]['active'] );
156 +
157 + if ( ! $in_current && ! $in_draft ) {
150 158 WP_CLI::error( esc_html__( 'Feature is not active', 'elasticpress' ) );
151 159 }
152 160
153 161 Features::factory()->deactivate_feature( $feature->slug );
@@ -168,11 +176,12 @@
168 176 * @param array $args Positional CLI args.
169 177 * @param array $assoc_args Associative CLI args.
170 178 */
171 179 public function list_features( $args, $assoc_args ) {
180 + $list_all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', null );
172 181
173 - if ( empty( $assoc_args['all'] ) ) {
174 - $features = Utils\get_option( 'ep_feature_settings', [] );
182 + if ( empty( $list_all ) ) {
183 + $features = Features::factory()->get_feature_settings();
175 184
176 185 WP_CLI::line( esc_html__( 'Active features:', 'elasticpress' ) );
177 186
178 187 foreach ( array_keys( $features ) as $feature_slug ) {
@@ -199,9 +208,9 @@
199 208 *
200 209 * ## OPTIONS
201 210 *
202 211 * [--network-wide]
203 - * : Force mappings to be sent for every index in the network.
212 + * : Force mappings to be sent for every index in the network. `--network-wide` takes an optional argument to limit the number of mappings to be sent where 0 is no limit. For example, `--network-wide=5` would send mappings for only 5 blogs on the network.
204 213 *
205 214 * [--indexables=<indexables>]
206 215 * : List of indexables
207 216 *
@@ -220,12 +229,9 @@
220 229 $this->maybe_change_host( $assoc_args );
221 230 $this->maybe_change_index_prefix( $assoc_args );
222 231 $this->connect_check();
223 232 $this->index_occurring();
224 -
225 - if ( ! $this->put_mapping_helper( $args, $assoc_args ) ) {
226 - exit( 1 );
227 - }
233 + $this->put_mapping_helper( $args, $assoc_args );
228 234 }
229 235
230 236 /**
231 237 * Add document mappings for every indexable
@@ -249,15 +255,11 @@
249 255 if ( ! is_numeric( $assoc_args['network-wide'] ) ) {
250 256 $assoc_args['network-wide'] = 0;
251 257 }
252 258
253 - $sites = Utils\get_sites( $assoc_args['network-wide'] );
259 + $sites = Utils\get_sites( $assoc_args['network-wide'], true );
254 260
255 261 foreach ( $sites as $site ) {
256 - if ( ! Utils\is_site_indexable( $site['blog_id'] ) ) {
257 - continue;
258 - }
259 -
260 262 switch_to_blog( $site['blog_id'] );
261 263
262 264 foreach ( $non_global_indexable_objects as $indexable ) {
263 265 /**
@@ -270,9 +272,9 @@
270 272 /* translators: 1. Indexable; 2. Site ID */
271 273 WP_CLI::line( sprintf( esc_html__( 'Adding %1$s mapping for site %2$d…', 'elasticpress' ), esc_html( strtolower( $indexable->labels['singular'] ) ), (int) $site['blog_id'] ) );
272 274
273 275 $indexable->delete_index();
274 - $result = $indexable->put_mapping();
276 + $result = $indexable->put_mapping( 'raw' );
275 277
276 278 /**
277 279 * Fires after CLI put mapping
278 280 *
@@ -282,14 +284,18 @@
282 284 * @param {array} $assoc_args CLI command associative args
283 285 */
284 286 do_action( 'ep_cli_put_mapping', $indexable, $args, $assoc_args );
285 287
286 - if ( $result ) {
288 + if ( ! is_wp_error( $result ) ) {
287 289 WP_CLI::success( esc_html__( 'Mapping sent', 'elasticpress' ) );
288 290 } else {
289 - WP_CLI::error( esc_html__( 'Mapping failed', 'elasticpress' ), false );
290 -
291 - return false;
291 + WP_CLI::error(
292 + sprintf(
293 + /* translators: Error message */
294 + esc_html__( 'Mapping failed: %s', 'elasticpress' ),
295 + Utils\get_elasticsearch_error_reason( $result->get_error_message() )
296 + )
297 + );
292 298 }
293 299 }
294 300
295 301 restore_current_blog();
@@ -306,9 +312,9 @@
306 312 /* translators: Indexable label */
307 313 WP_CLI::line( sprintf( esc_html__( 'Adding %s mapping…', 'elasticpress' ), esc_html( strtolower( $indexable->labels['singular'] ) ) ) );
308 314
309 315 $indexable->delete_index();
310 - $result = $indexable->put_mapping();
316 + $result = $indexable->put_mapping( 'raw' );
311 317
312 318 /**
313 319 * Fires after CLI put mapping
314 320 *
@@ -318,14 +324,18 @@
318 324 * @param {array} $assoc_args CLI command associative args
319 325 */
320 326 do_action( 'ep_cli_put_mapping', $indexable, $args, $assoc_args );
321 327
322 - if ( $result ) {
328 + if ( ! is_wp_error( $result ) ) {
323 329 WP_CLI::success( esc_html__( 'Mapping sent', 'elasticpress' ) );
324 330 } else {
325 - WP_CLI::error( esc_html__( 'Mapping failed', 'elasticpress' ), false );
326 -
327 - return false;
331 + WP_CLI::error(
332 + sprintf(
333 + /* translators: Error message */
334 + esc_html__( 'Mapping failed: %s', 'elasticpress' ),
335 + Utils\get_elasticsearch_error_reason( $result->get_error_message() )
336 + )
337 + );
328 338 }
329 339 }
330 340 }
331 341
@@ -343,9 +353,9 @@
343 353 /* translators: Indexable label */
344 354 WP_CLI::line( sprintf( esc_html__( 'Adding %s mapping…', 'elasticpress' ), esc_html( strtolower( $indexable->labels['singular'] ) ) ) );
345 355
346 356 $indexable->delete_index();
347 - $result = $indexable->put_mapping();
357 + $result = $indexable->put_mapping( 'raw' );
348 358
349 359 /**
350 360 * Fires after CLI put mapping
351 361 *
@@ -355,14 +365,18 @@
355 365 * @param {array} $assoc_args CLI command associative args
356 366 */
357 367 do_action( 'ep_cli_put_mapping', $indexable, $args, $assoc_args );
358 368
359 - if ( $result ) {
369 + if ( ! is_wp_error( $result ) ) {
360 370 WP_CLI::success( esc_html__( 'Mapping sent', 'elasticpress' ) );
361 371 } else {
362 - WP_CLI::error( esc_html__( 'Mapping failed', 'elasticpress' ), false );
363 -
364 - return false;
372 + WP_CLI::error(
373 + sprintf(
374 + /* translators: Error message */
375 + esc_html__( 'Mapping failed: %s', 'elasticpress' ),
376 + Utils\get_elasticsearch_error_reason( $result->get_error_message() )
377 + )
378 + );
365 379 }
366 380 }
367 381
368 382 return true;
@@ -384,15 +398,17 @@
384 398 * @param array $args Positional CLI args.
385 399 * @param array $assoc_args Associative CLI args.
386 400 */
387 401 public function get_mapping( $args, $assoc_args ) {
388 - $index_names = (array) ( isset( $assoc_args['index-name'] ) ? $assoc_args['index-name'] : $this->get_index_names() );
402 + $pretty = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pretty' );
403 + $index_name = \WP_CLI\Utils\get_flag_value( $assoc_args, 'index-name' );
404 + $index_names = (array) ( ! empty( $index_name ) ? $index_name : $this->get_index_names() );
389 405
390 406 $path = join( ',', $index_names ) . '/_mapping';
391 407
392 408 $response = Elasticsearch::factory()->remote_request( $path );
393 409
394 - $this->print_json_response( $response, ! empty( $assoc_args['pretty'] ) );
410 + $this->print_json_response( $response, $pretty );
395 411 }
396 412
397 413 /**
398 414 * Return all indices from the cluster as a JSON object.
@@ -407,12 +423,13 @@
407 423 * @param array $args Positional CLI args.
408 424 * @param array $assoc_args Associative CLI args.
409 425 */
410 426 public function get_cluster_indices( $args, $assoc_args ) {
427 + $pretty = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pretty' );
411 428
412 429 $cluster_indices = Elasticsearch::factory()->get_cluster_indices();
413 430
414 - $this->pretty_json_encode( $cluster_indices, ! empty( $assoc_args['pretty'] ) );
431 + $this->pretty_json_encode( $cluster_indices, $pretty );
415 432 }
416 433
417 434 /**
418 435 * Return all index names as a JSON object.
@@ -421,27 +438,37 @@
421 438 *
422 439 * [--pretty]
423 440 * : Use this flag to render a pretty-printed version of the JSON response.
424 441 *
442 + * [--status=<status>]
443 + * : Use this flag to render a pretty-printed version of the JSON response.
444 + *
425 445 * @subcommand get-indices
426 - * @since 4.4.0, `--pretty` introduced in 4.1.0
446 + * @since 4.4.0, `--pretty` introduced in 4.1.0, `--status` introduced in 4.5.0
427 447 * @param array $args Positional CLI args.
428 448 * @param array $assoc_args Associative CLI args.
429 449 */
430 450 public function get_indices( $args, $assoc_args ) {
431 - $index_names = $this->get_index_names();
451 + $defaults = [
452 + 'status' => 'active',
453 + ];
432 454
433 - $this->pretty_json_encode( $index_names, ! empty( $assoc_args['pretty'] ) );
455 + $assoc_args = wp_parse_args( $assoc_args, $defaults );
456 + $pretty = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pretty' );
457 + $index_names = $this->get_index_names( $assoc_args['status'] );
458 +
459 + $this->pretty_json_encode( $index_names, $pretty );
434 460 }
435 461
436 462 /**
437 463 * Get all index names.
438 464 *
439 - * @since 3.6.4
465 + * @param string $status Whether to return active indexables or all registered.
466 + * @since 3.6.4, 4.5.0 Added $status
440 467 * @return array
441 468 */
442 - protected function get_index_names() {
443 - return Elasticsearch::factory()->get_index_names();
469 + protected function get_index_names( $status = 'active' ) {
470 + return Elasticsearch::factory()->get_index_names( $status );
444 471 }
445 472
446 473 /**
447 474 * Delete the index for each indexable. !!Warning!! This removes your elasticsearch index(s) for the entire site.
@@ -451,9 +478,9 @@
451 478 * [--index-name=<index_name>]
452 479 * : The name of the index to be deleted. If not passed, all indexes will be deleted
453 480 *
454 481 * [--network-wide]
455 - * : Force every index on the network to be deleted.
482 + * : Force every index on the network to be deleted. `--network-wide` takes an optional argument to limit the number of indices to be deleted where 0 is no limit. For example, `--network-wide=5` would limit to only 5 indices on the network to be deleted.
456 483 *
457 484 * [--yes]
458 485 * : Skip confirmation
459 486 *
@@ -483,13 +510,13 @@
483 510
484 511 $non_global_indexable_objects = Indexables::factory()->get_all( false );
485 512 $global_indexable_objects = Indexables::factory()->get_all( true );
486 513
487 - if ( isset( $assoc_args['network-wide'] ) && is_multisite() ) {
514 + if ( isset( $assoc_args['network-wide'] ) && defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
488 515 if ( ! is_numeric( $assoc_args['network-wide'] ) ) {
489 516 $assoc_args['network-wide'] = 0;
490 517 }
491 - $sites = Utils\get_sites( $assoc_args['network-wide'] );
518 + $sites = Utils\get_sites( $assoc_args['network-wide'], false );
492 519
493 520 foreach ( $sites as $site ) {
494 521 switch_to_blog( $site['blog_id'] );
495 522
@@ -590,11 +617,25 @@
590 617
591 618 add_action( 'ep_epio_wp_cli_set_autosuggest', [ $autosuggest_feature, 'epio_send_autosuggest_public_request' ] );
592 619
593 620 do_action( 'ep_epio_wp_cli_set_autosuggest', $args, $assoc_args );
621 +
622 + WP_CLI::success( esc_html__( 'Done.', 'elasticpress' ) );
594 623 }
595 624
596 625 /**
626 + * A WP-CLI wrapper to run `Autosuggest::post_deactivation()`.
627 + *
628 + * @subcommand epio-reset-autosuggest
629 + * @since 5.3.2
630 + */
631 + public function epio_reset_autosuggest() {
632 + Features::factory()->get_registered_feature( 'autosuggest' )->post_deactivation();
633 +
634 + WP_CLI::success( esc_html__( 'Done.', 'elasticpress' ) );
635 + }
636 +
637 + /**
597 638 * Helper method for creating the network alias for an indexable
598 639 *
599 640 * @param Indexable $indexable Instance of indexable.
600 641 * @since 0.9
@@ -600,16 +641,12 @@
600 641 * @since 0.9
601 642 * @return array|bool
602 643 */
603 644 private function create_network_alias_helper( Indexable $indexable ) {
604 - $sites = Utils\get_sites();
645 + $sites = Utils\get_sites( 0, true );
605 646 $indexes = [];
606 647
607 648 foreach ( $sites as $site ) {
608 - if ( ! Utils\is_site_indexable( $site['blog_id'] ) ) {
609 - continue;
610 - }
611 -
612 649 switch_to_blog( $site['blog_id'] );
613 650
614 651 $indexes[] = $indexable->get_index_name();
615 652
@@ -625,13 +662,10 @@
625 662 * @param int $signal_no Signal number
626 663 * @since 3.3
627 664 */
628 665 public function delete_transient_on_int( $signal_no ) {
629 - if ( SIGINT === $signal_no ) {
630 - $this->delete_transient();
631 - WP_CLI::log( esc_html__( 'Indexing cleaned up.', 'elasticpress' ) );
632 - exit;
633 - }
666 + _deprecated_function( __METHOD__, '4.5.0', '\ElasticPress\Command\Utility::delete_transient_on_int' );
667 + Utility::delete_transient_on_int( $signal_no );
634 668 }
635 669
636 670 /**
637 671 * Index all posts for a site or network wide.
@@ -643,8 +677,11 @@
643 677 *
644 678 * [--setup]
645 679 * : Clear the index first and re-send the put mapping. Use `--yes` to skip the confirmation
646 680 *
681 + * [--force]
682 + * : Stop any ongoing sync
683 + *
647 684 * [--per-page=<per_page_number>]
648 685 * : Determine the amount of posts to be indexed per bulk index (or cycle)
649 686 *
650 687 * [--nobulk]
@@ -661,8 +698,11 @@
661 698 *
662 699 * [--show-nobulk-errors]
663 700 * : Display the error message returned from Elasticsearch when a post fails to index while not using the /_bulk endpoint
664 701 *
702 + * [--stop-on-error]
703 + * : Stop indexing if an error is encountered and display the error.
704 + *
665 705 * [--offset=<offset_number>]
666 706 * : Skip the first n posts (don't forget to remove the `--setup` flag when resuming or the index will be emptied before starting again).
667 707 *
668 708 * [--indexables=<indexables>]
@@ -696,28 +736,41 @@
696 736 * @since 4.4.0
697 737 * @param array $assoc_args Associative CLI args.
698 738 */
699 739 public function sync( $args, $assoc_args ) {
700 - global $wp_actions;
740 + $setup_option = \WP_CLI\Utils\get_flag_value( $assoc_args, 'setup', false );
741 + $force_option = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force', false );
701 742
702 - $setup_option = isset( $assoc_args['setup'] ) ? $assoc_args['setup'] : false;
743 + if ( $setup_option ) {
744 + $message = sprintf(
745 + /* translators: ElasticPress.io or Elasticsearch */
746 + esc_html__( 'Syncing with the --setup option will delete your existing index in %s. Are you sure you want to delete your Elasticsearch index', 'elasticpress' ),
747 + Utils\is_epio() ? 'ElasticPress.io' : 'Elasticsearch'
748 + );
749 + WP_CLI::confirm( $message, $assoc_args );
750 + }
703 751
704 - if ( true === $setup_option ) {
705 - WP_CLI::confirm( esc_html__( 'Indexing with setup option needs to delete Elasticsearch index first, are you sure you want to delete your Elasticsearch index?', 'elasticpress' ), $assoc_args );
752 + if ( $force_option ) {
753 + WP_CLI::confirm( esc_html__( 'Are you sure you want to stop any other ongoing sync?', 'elasticpress' ), $assoc_args );
706 754 }
707 755
708 756 if ( ! function_exists( 'pcntl_signal' ) ) {
709 - WP_CLI::warning( esc_html__( 'Function pcntl_signal not available. Make sure to run `wp elasticpress clear-index` in case the process is killed.', 'elasticpress' ) );
757 + WP_CLI::warning( esc_html__( 'Function pcntl_signal not available. Make sure to run `wp elasticpress clear-sync` in case the process is killed.', 'elasticpress' ) );
710 758 } else {
711 759 declare( ticks = 1 );
712 - pcntl_signal( SIGINT, [ $this, 'delete_transient_on_int' ] );
760 + pcntl_signal( SIGINT, [ Utility::class, 'delete_transient_on_int' ] );
713 761 }
714 762
715 763 $this->maybe_change_host( $assoc_args );
716 764 $this->maybe_change_index_prefix( $assoc_args );
717 765 $this->connect_check();
718 - $this->index_occurring();
719 766
767 + if ( $force_option ) {
768 + $this->clear_sync();
769 + } else {
770 + $this->index_occurring();
771 + }
772 +
720 773 $indexables = null;
721 774
722 775 if ( ! empty( $assoc_args['indexables'] ) ) {
723 776 $indexables = explode( ',', str_replace( ' ', '', $assoc_args['indexables'] ) );
@@ -737,29 +790,38 @@
737 790 * @param {array} $assoc_args CLI command associative args
738 791 */
739 792 do_action( 'ep_wp_cli_pre_index', $args, $assoc_args );
740 793
741 - $this->timer_start();
794 + Utility::timer_start();
742 795
743 - add_action( 'ep_sync_put_mapping', [ $this, 'stop_on_failed_mapping' ], 10, 3 );
744 - add_action( 'ep_sync_put_mapping', [ $this, 'call_ep_cli_put_mapping' ], 10, 2 );
745 - add_action( 'ep_index_batch_new_attempt', [ $this, 'should_interrupt_sync' ] );
796 + add_action( 'ep_sync_put_mapping', [ Utility::class, 'stop_on_failed_mapping' ], 10, 3 );
797 + add_action( 'ep_sync_put_mapping', [ Utility::class, 'call_ep_cli_put_mapping' ], 10, 2 );
798 + add_action( 'ep_index_batch_new_attempt', [ Utility::class, 'should_interrupt_sync' ] );
746 799
747 - $no_bulk = ! empty( $assoc_args['nobulk'] );
800 + $no_bulk = ! empty( $assoc_args['nobulk'] );
801 + $static_bulk = \WP_CLI\Utils\get_flag_value( $assoc_args, 'static-bulk', null );
802 + $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network-wide', null );
748 803
749 804 $index_args = [
750 805 'method' => 'cli',
751 806 'total_attempts' => 1,
752 807 'indexables' => $indexables,
753 - 'put_mapping' => ! empty( $setup_option ),
808 + 'put_mapping' => $setup_option,
754 809 'output_method' => [ $this, 'index_output' ],
755 - 'network_wide' => ( ! empty( $assoc_args['network-wide'] ) ) ? $assoc_args['network-wide'] : null,
810 + 'network_wide' => $network_wide,
756 811 'nobulk' => $no_bulk,
757 812 'offset' => ( ! empty( $assoc_args['offset'] ) ) ? absint( $assoc_args['offset'] ) : 0,
758 - 'static_bulk' => ( ! empty( $assoc_args['static-bulk'] ) ) ? $assoc_args['static-bulk'] : null,
813 + 'static_bulk' => $static_bulk,
759 814 ];
760 815
761 - if ( isset( $assoc_args['show-errors'] ) || ( isset( $assoc_args['show-bulk-errors'] ) && ! $no_bulk ) || ( isset( $assoc_args['show-nobulk-errors'] ) && $no_bulk ) ) {
816 + $index_args['stop_on_error'] = WP_CLI\Utils\get_flag_value( $assoc_args, 'stop-on-error', false );
817 +
818 + $show_errors = $index_args['stop_on_error'] ||
819 + WP_CLI\Utils\get_flag_value( $assoc_args, 'show-errors', false ) ||
820 + ( WP_CLI\Utils\get_flag_value( $assoc_args, 'show-bulk-errors', false ) && ! $no_bulk ) ||
821 + ( WP_CLI\Utils\get_flag_value( $assoc_args, 'show-nobulk-errors', false ) && $no_bulk );
822 +
823 + if ( $show_errors ) {
762 824 $index_args['show_errors'] = true;
763 825 }
764 826
765 827 if ( ! empty( $assoc_args['post-ids'] ) ) {
@@ -792,13 +854,13 @@
792 854 }
793 855
794 856 \ElasticPress\IndexHelper::factory()->full_index( $index_args );
795 857
796 - remove_action( 'ep_sync_put_mapping', [ $this, 'stop_on_failed_mapping' ] );
797 - remove_action( 'ep_sync_put_mapping', [ $this, 'call_ep_cli_put_mapping' ], 10, 2 );
798 - remove_action( 'ep_index_batch_new_attempt', [ $this, 'should_interrupt_sync' ] );
858 + remove_action( 'ep_sync_put_mapping', [ Utility::class, 'stop_on_failed_mapping' ] );
859 + remove_action( 'ep_sync_put_mapping', [ Utility::class, 'call_ep_cli_put_mapping' ], 10, 2 );
860 + remove_action( 'ep_index_batch_new_attempt', [ Utility::class, 'should_interrupt_sync' ] );
799 861
800 - $sync_time_in_ms = $this->timer_stop();
862 + $sync_time_in_ms = Utility::timer_stop();
801 863
802 864 /**
803 865 * Fires after executing a CLI index
804 866 *
@@ -809,11 +871,11 @@
809 871 * @since 3.5.5
810 872 */
811 873 do_action( 'ep_wp_cli_after_index', $args, $assoc_args );
812 874
813 - WP_CLI::log( WP_CLI::colorize( '%Y' . esc_html__( 'Total time elapsed: ', 'elasticpress' ) . '%N' . $this->timer_format( $sync_time_in_ms ) ) );
875 + WP_CLI::log( WP_CLI::colorize( '%Y' . esc_html__( 'Total time elapsed: ', 'elasticpress' ) . '%N' . Utility::timer_format( $sync_time_in_ms ) ) );
814 876
815 - $this->delete_transient();
877 + Utility::delete_transient();
816 878
817 879 WP_CLI::success( esc_html__( 'Done!', 'elasticpress' ) );
818 880 }
819 881
@@ -824,10 +886,8 @@
824 886 */
825 887 public function status() {
826 888 $this->connect_check();
827 889
828 - $request_args = [ 'headers' => Elasticsearch::factory()->format_request_headers() ];
829 -
830 890 $registered_index_names = $this->get_index_names();
831 891
832 892 $response_cat_indices = Elasticsearch::factory()->remote_request( '_cat/indices?format=json' );
833 893
@@ -846,9 +906,9 @@
846 906 }
847 907
848 908 $index_names_imploded = implode( ',', $index_names );
849 909
850 - $request = wp_remote_get( trailingslashit( Utils\get_host( true ) ) . $index_names_imploded . '/_recovery/?pretty', $request_args );
910 + $request = Elasticsearch::factory()->remote_request( $index_names_imploded . '/_recovery/?pretty' );
851 911
852 912 if ( is_wp_error( $request ) ) {
853 913 WP_CLI::error( implode( "\n", $request->get_error_messages() ) );
854 914 }
@@ -869,10 +929,8 @@
869 929 */
870 930 public function stats() {
871 931 $this->connect_check();
872 932
873 - $request_args = array( 'headers' => Elasticsearch::factory()->format_request_headers() );
874 -
875 933 $registered_index_names = $this->get_index_names();
876 934
877 935 $response_cat_indices = Elasticsearch::factory()->remote_request( '_cat/indices?format=json' );
878 936
@@ -891,9 +949,10 @@
891 949 }
892 950
893 951 $index_names_imploded = implode( ',', $index_names );
894 952
895 - $request = wp_remote_get( trailingslashit( Utils\get_host( true ) ) . $index_names_imploded . '/_stats/', $request_args );
953 + Elasticsearch::factory()->refresh_indices();
954 + $request = Elasticsearch::factory()->remote_request( $index_names_imploded . '/_stats/' );
896 955
897 956 if ( is_wp_error( $request ) ) {
898 957 WP_CLI::error( implode( "\n", $request->get_error_messages() ) );
899 958 }
@@ -935,17 +994,10 @@
935 994 *
936 995 * @since 3.1
937 996 */
938 997 private function delete_transient() {
939 - \ElasticPress\IndexHelper::factory()->clear_index_meta();
940 -
941 - if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
942 - delete_site_transient( 'ep_cli_sync_progress' );
943 - delete_site_transient( 'ep_wpcli_sync_interrupted' );
944 - } else {
945 - delete_transient( 'ep_cli_sync_progress' );
946 - delete_transient( 'ep_wpcli_sync_interrupted' );
947 - }
998 + _deprecated_function( __METHOD__, '4.5.0', '\ElasticPress\Command\Utility::delete_transient()' );
999 + Utility::delete_transient();
948 1000 }
949 1001
950 1002 /**
951 1003 * Clear a sync/index process.
@@ -965,9 +1017,9 @@
965 1017 * @since 3.5.5
966 1018 */
967 1019 do_action( 'ep_cli_before_clear_index' );
968 1020
969 - $this->delete_transient();
1021 + Utility::delete_transient();
970 1022
971 1023 /**
972 1024 * Fires after the CLI `clear-sync` command is executed.
973 1025 *
@@ -976,9 +1028,9 @@
976 1028 * @since 3.5.5
977 1029 */
978 1030 do_action( 'ep_cli_after_clear_index' );
979 1031
980 - WP_CLI::log( esc_html__( 'Index cleared.', 'elasticpress' ) );
1032 + WP_CLI::log( esc_html__( 'Sync cleared.', 'elasticpress' ) );
981 1033 }
982 1034
983 1035 /**
984 1036 * Returns the status of an ongoing index operation in JSON array.
@@ -999,8 +1051,9 @@
999 1051 * @param array $args Positional CLI args.
1000 1052 * @param array $assoc_args Associative CLI args.
1001 1053 */
1002 1054 public function get_ongoing_sync_status( $args, $assoc_args ) {
1055 + $pretty = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pretty' );
1003 1056 $indexing_status = Utils\get_indexing_status();
1004 1057
1005 1058 if ( empty( $indexing_status ) ) {
1006 1059 $indexing_status = [
@@ -1010,9 +1063,9 @@
1010 1063 'total_items' => -1,
1011 1064 ];
1012 1065 }
1013 1066
1014 - $this->pretty_json_encode( $indexing_status, ! empty( $assoc_args['pretty'] ) );
1067 + $this->pretty_json_encode( $indexing_status, $pretty );
1015 1068 }
1016 1069
1017 1070 /**
1018 1071 * Returns a JSON array with the results of the last index (if present) or an empty array.
@@ -1028,11 +1081,12 @@
1028 1081 * @param array $args Positional CLI args.
1029 1082 * @param array $assoc_args Associative CLI args.
1030 1083 */
1031 1084 public function get_last_sync( $args, $assoc_args ) {
1032 - $last_sync = \ElasticPress\IndexHelper::factory()->get_last_index();
1085 + $pretty = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pretty' );
1086 + $last_sync = \ElasticPress\IndexHelper::factory()->get_last_sync();
1033 1087
1034 - $this->pretty_json_encode( $last_sync, ! empty( $assoc_args['pretty'] ) );
1088 + $this->pretty_json_encode( $last_sync, $pretty );
1035 1089 }
1036 1090
1037 1091 /**
1038 1092 * Returns a JSON array with the results of the last CLI sync (if present) or an empty array.
@@ -1050,8 +1104,9 @@
1050 1104 * @param array $args Positional CLI args.
1051 1105 * @param array $assoc_args Associative CLI args.
1052 1106 */
1053 1107 public function get_last_cli_sync( $args, $assoc_args ) {
1108 + $pretty = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pretty' );
1054 1109 $last_sync = Utils\get_option( 'ep_last_cli_index', array() );
1055 1110
1056 1111 if ( isset( $assoc_args['clear'] ) ) {
1057 1112 Utils\delete_option( 'ep_last_cli_index' );
@@ -1056,9 +1111,9 @@
1056 1111 if ( isset( $assoc_args['clear'] ) ) {
1057 1112 Utils\delete_option( 'ep_last_cli_index' );
1058 1113 }
1059 1114
1060 - $this->pretty_json_encode( $last_sync, ! empty( $assoc_args['pretty'] ) );
1115 + $this->pretty_json_encode( $last_sync, $pretty );
1061 1116 }
1062 1117
1063 1118
1064 1119 /**
@@ -1071,9 +1126,9 @@
1071 1126 private function maybe_change_host( $assoc_args ) {
1072 1127 if ( isset( $assoc_args['ep-host'] ) ) {
1073 1128 add_filter(
1074 1129 'ep_host',
1075 - function ( $host ) use ( $assoc_args ) {
1130 + function () use ( $assoc_args ) {
1076 1131 return $assoc_args['ep-host'];
1077 1132 }
1078 1133 );
1079 1134 }
@@ -1078,9 +1133,8 @@
1078 1133 );
1079 1134 }
1080 1135 }
1081 1136
1082 -
1083 1137 /**
1084 1138 * maybe change index prefix on the fly
1085 1139 *
1086 1140 * @param array $assoc_args Associative CLI args.
@@ -1090,9 +1144,9 @@
1090 1144 private function maybe_change_index_prefix( $assoc_args ) {
1091 1145 if ( isset( $assoc_args['ep-prefix'] ) ) {
1092 1146 add_filter(
1093 1147 'ep_index_prefix',
1094 - function ( $prefix ) use ( $assoc_args ) {
1148 + function ( $prefix ) use ( $assoc_args ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
1095 1149 return $assoc_args['ep-prefix'];
1096 1150 }
1097 1151 );
1098 1152 }
@@ -1103,15 +1157,10 @@
1103 1157 *
1104 1158 * @since 3.5.2
1105 1159 */
1106 1160 public function should_interrupt_sync() {
1107 - $should_interrupt_sync = get_transient( 'ep_wpcli_sync_interrupted' );
1108 -
1109 - if ( $should_interrupt_sync ) {
1110 - WP_CLI::line( esc_html__( 'Sync was interrupted', 'elasticpress' ) );
1111 - $this->delete_transient_on_int( 2 );
1112 - WP_CLI::halt();
1113 - }
1161 + _deprecated_function( __METHOD__, '4.5.0', '\ElasticPress\Command\Utility::should_interrupt_sync' );
1162 + Utility::should_interrupt_sync();
1114 1163 }
1115 1164
1116 1165 /**
1117 1166 * Stop the Sync operation started from the dashboard.
@@ -1232,39 +1281,14 @@
1232 1281 * @param string $transient Transient name.
1233 1282 * @return true|null
1234 1283 */
1235 1284 public function custom_get_transient( $pre_transient, $transient ) {
1236 - global $wpdb;
1237 -
1238 - if ( wp_using_ext_object_cache() ) {
1239 - /**
1240 - * When external object cache is used we need to make sure to force a remote fetch,
1241 - * so that the value from the local memory is discarded.
1242 - */
1243 - $should_interrupt_sync = wp_cache_get( $transient, 'transient', true );
1244 - } else {
1245 - $options = $wpdb->options;
1246 -
1247 - $should_interrupt_sync = $wpdb->get_var(
1248 - // phpcs:disable
1249 - $wpdb->prepare(
1250 - "
1251 - SELECT option_value
1252 - FROM $options
1253 - WHERE option_name = %s
1254 - LIMIT 1
1255 - ",
1256 - "_transient_{$transient}"
1257 - )
1258 - // phpcs:enable
1259 - );
1260 - }
1261 -
1262 - return $should_interrupt_sync ? (bool) $should_interrupt_sync : null;
1285 + _deprecated_function( __METHOD__, '4.5.0', '\ElasticPress\Command\Utility::custom_get_transient' );
1286 + return Utility::custom_get_transient( $pre_transient, $transient );
1263 1287 }
1264 1288
1265 1289 /**
1266 - * Utilitary function to render Stats for a given index.
1290 + * Utility function to render Stats for a given index.
1267 1291 *
1268 1292 * @since 3.5.6
1269 1293 * @param string $current_index The index name.
1270 1294 * @param array $body The response body.
@@ -1282,9 +1306,9 @@
1282 1306 }
1283 1307 }
1284 1308
1285 1309 /**
1286 - * Function used to ouput messages coming from IndexHelper
1310 + * Function used to output messages coming from IndexHelper
1287 1311 *
1288 1312 * @param array $message Message data
1289 1313 * @param array $args Args sent and processed by IndexHelper
1290 1314 * @param array $index_meta Current index state
@@ -1301,8 +1325,9 @@
1301 1325 case 'warning':
1302 1326 if ( empty( $args['show_errors'] ) ) {
1303 1327 return;
1304 1328 }
1329 +
1305 1330 WP_CLI::warning( $message['message'] );
1306 1331 break;
1307 1332
1308 1333 case 'error':
@@ -1315,17 +1340,19 @@
1315 1340 break;
1316 1341 }
1317 1342
1318 1343 if ( 'index_next_batch' === $context ) {
1319 - $counter++;
1344 + ++$counter;
1320 1345 if ( ( $counter % 10 ) === 0 ) {
1321 - $time_elapsed_diff = $time_elapsed > 0 ? ' (+' . (string) ( $this->timer_stop() - $time_elapsed ) . ')' : '';
1322 - $time_elapsed = $this->timer_stop( 2 );
1323 - WP_CLI::log( WP_CLI::colorize( '%Y' . esc_html__( 'Time elapsed: ', 'elasticpress' ) . '%N' . $this->timer_format( $time_elapsed ) . $time_elapsed_diff ) );
1346 + $time_elapsed_diff = $time_elapsed > 0 ? ' (+' . (string) ( Utility::timer_stop() - $time_elapsed ) . ')' : '';
1347 + $time_elapsed = Utility::timer_stop( 2 );
1348 + WP_CLI::log( WP_CLI::colorize( '%Y' . esc_html__( 'Time elapsed: ', 'elasticpress' ) . '%N' . Utility::timer_format( $time_elapsed ) . $time_elapsed_diff ) );
1324 1349
1325 - $current_memory = round( memory_get_usage() / 1024 / 1024, 2 ) . 'mb';
1326 - $peak_memory = ' (Peak: ' . round( memory_get_peak_usage() / 1024 / 1024, 2 ) . 'mb)';
1327 - WP_CLI::log( WP_CLI::colorize( '%Y' . esc_html__( 'Memory Usage: ', 'elasticpress' ) . '%N' . $current_memory . $peak_memory ) );
1350 + $current_memory = memory_get_usage() / 1024 / 1024;
1351 + $current_memory = ( $current_memory > 1000 ) ? round( $current_memory / 1024, 2 ) . 'gb' : round( $current_memory, 2 ) . 'mb';
1352 + $peak_memory = memory_get_peak_usage() / 1024 / 1024;
1353 + $peak_memory = ( $peak_memory > 1000 ) ? round( $peak_memory / 1024, 2 ) . 'gb' : round( $peak_memory, 2 ) . 'mb';
1354 + WP_CLI::log( WP_CLI::colorize( '%Y' . esc_html__( 'Memory Usage: ', 'elasticpress' ) . '%N' . $current_memory . ' (Peak: ' . $peak_memory . ')' ) );
1328 1355 }
1329 1356 }
1330 1357 }
1331 1358
@@ -1336,13 +1363,10 @@
1336 1363 * @param Indexable $indexable Indexable object
1337 1364 * @param bool $result Whether the request was successful or not
1338 1365 */
1339 1366 public function stop_on_failed_mapping( $index_meta, $indexable, $result ) {
1340 - if ( ! $result ) {
1341 - $this->delete_transient();
1342 -
1343 - exit( 1 );
1344 - }
1367 + _deprecated_function( __METHOD__, '4.5.0', '\ElasticPress\Command\Utility::stop_on_failed_mapping' );
1368 + Utility::stop_on_failed_mapping( $index_meta, $indexable, $result );
1345 1369 }
1346 1370
1347 1371 /**
1348 1372 * Ties the `ep_cli_put_mapping` action to `ep_sync_put_mapping`.
@@ -1353,17 +1377,10 @@
1353 1377 * @param Indexable $indexable Indexable object
1354 1378 * @return void
1355 1379 */
1356 1380 public function call_ep_cli_put_mapping( $index_meta, $indexable ) {
1357 - /**
1358 - * Fires after CLI put mapping
1359 - *
1360 - * @hook ep_cli_put_mapping
1361 - * @param {Indexable} $indexable Indexable involved in mapping
1362 - * @param {array} $args CLI command position args
1363 - * @param {array} $assoc_args CLI command associative args
1364 - */
1365 - do_action( 'ep_cli_put_mapping', $indexable, $this->args, $this->assoc_args );
1381 + _deprecated_function( __METHOD__, '4.5.0', '\ElasticPress\Command\Utility::call_ep_cli_put_mapping' );
1382 + Utility::call_ep_cli_put_mapping( $index_meta, $indexable );
1366 1383 }
1367 1384
1368 1385 /**
1369 1386 * Send a HTTP request to Elasticsearch
@@ -1392,8 +1409,9 @@
1392 1409 * @param array $args Positional CLI args.
1393 1410 * @param array $assoc_args Associative CLI args.
1394 1411 */
1395 1412 public function request( $args, $assoc_args ) {
1413 + $pretty = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pretty' );
1396 1414 $path = $args[0];
1397 1415 $method = isset( $assoc_args['method'] ) ? $assoc_args['method'] : 'GET';
1398 1416 $body = isset( $assoc_args['body'] ) ? $assoc_args['body'] : '';
1399 1417 $request_args = [
@@ -1402,54 +1420,9 @@
1402 1420 if ( 'GET' !== $method && ! empty( $body ) ) {
1403 1421 $request_args['body'] = $body;
1404 1422 }
1405 1423
1406 - if ( ! empty( $assoc_args['debug-http-request'] ) ) {
1407 - add_filter(
1408 - 'http_api_debug',
1409 - function ( $response, $context, $transport, $request_args, $url ) {
1410 - // phpcs:disable WordPress.PHP.DevelopmentFunctions
1411 - WP_CLI::line(
1412 - sprintf(
1413 - /* translators: URL of the request */
1414 - esc_html__( 'URL: %s', 'elasticpress' ),
1415 - $url
1416 - )
1417 - );
1418 - WP_CLI::line(
1419 - sprintf(
1420 - /* translators: Request arguments (outputted with print_r()) */
1421 - esc_html__( 'Request Args: %s', 'elasticpress' ),
1422 - print_r( $request_args, true )
1423 - )
1424 - );
1425 - WP_CLI::line(
1426 - sprintf(
1427 - /* translators: HTTP transport used */
1428 - esc_html__( 'Transport: %s', 'elasticpress' ),
1429 - $transport
1430 - )
1431 - );
1432 - WP_CLI::line(
1433 - sprintf(
1434 - /* translators: Context under which the http_api_debug hook is fired */
1435 - esc_html__( 'Context: %s', 'elasticpress' ),
1436 - $context
1437 - )
1438 - );
1439 - WP_CLI::line(
1440 - sprintf(
1441 - /* translators: HTTP response (outputted with print_r()) */
1442 - esc_html__( 'Response: %s', 'elasticpress' ),
1443 - print_r( $response, true )
1444 - )
1445 - );
1446 - // phpcs:enable WordPress.PHP.DevelopmentFunctions
1447 - },
1448 - 10,
1449 - 5
1450 - );
1451 - }
1424 + $this->maybe_add_http_api_debug_filter( $assoc_args );
1452 1425 $response = Elasticsearch::factory()->remote_request( $path, $request_args, [], 'wp_cli_request' );
1453 1426
1454 1427 if ( is_wp_error( $response ) ) {
1455 1428 WP_CLI::error( $response->get_error_message() );
@@ -1454,9 +1427,9 @@
1454 1427 if ( is_wp_error( $response ) ) {
1455 1428 WP_CLI::error( $response->get_error_message() );
1456 1429 }
1457 1430
1458 - $this->print_json_response( $response, ! empty( $assoc_args['pretty'] ) );
1431 + $this->print_json_response( $response, $pretty );
1459 1432 }
1460 1433
1461 1434 /**
1462 1435 * Reset all ElasticPress settings stored in WP options and transients.
@@ -1483,45 +1456,10 @@
1483 1456
1484 1457 WP_CLI::line( esc_html__( 'Settings deleted.', 'elasticpress' ) );
1485 1458 }
1486 1459
1487 - /**
1488 - * Starts the timer.
1489 - *
1490 - * @since 4.2.0
1491 - * @return true
1492 - */
1493 - protected function timer_start() {
1494 - $this->time_start = microtime( true );
1495 - return true;
1496 - }
1497 1460
1498 1461 /**
1499 - * Stops the timer.
1500 - *
1501 - * @since 4.2.0
1502 - * @param int $precision The number of digits from the right of the decimal to display. Default 3.
1503 - * @return float Time spent so far
1504 - */
1505 - protected function timer_stop( $precision = 3 ) {
1506 - $diff = microtime( true ) - $this->time_start;
1507 - return (float) number_format( (float) $diff, $precision );
1508 - }
1509 -
1510 - /**
1511 - * Given a timestamp in microseconds, returns it in the given format.
1512 - *
1513 - * @since 4.2.0
1514 - * @param float $microtime Unix timestamp in ms
1515 - * @param string $format Desired format
1516 - * @return string
1517 - */
1518 - protected function timer_format( $microtime, $format = 'H:i:s.u' ) {
1519 - $microtime_date = \DateTime::createFromFormat( 'U.u', number_format( (float) $microtime, 3, '.', '' ) );
1520 - return $microtime_date->format( $format );
1521 - }
1522 -
1523 - /**
1524 1462 * Print an HTTP response.
1525 1463 *
1526 1464 * @since 4.1.0
1527 1465 * @param array $response HTTP Response.
@@ -1550,8 +1488,203 @@
1550 1488 * @param array $json_obj The JSON object or array.
1551 1489 * @param boolean $pretty_print_flag Whether it should or not be formatted.
1552 1490 */
1553 1491 protected function pretty_json_encode( $json_obj, $pretty_print_flag ) {
1554 - $flag = $pretty_print_flag ? JSON_PRETTY_PRINT : null;
1492 + $flag = $pretty_print_flag ? JSON_PRETTY_PRINT : 0;
1555 1493 WP_CLI::line( wp_json_encode( $json_obj, $flag ) );
1494 + }
1495 +
1496 + /**
1497 + * Gets the Instant Results search template.
1498 + *
1499 + * ## OPTIONS
1500 + *
1501 + * [--pretty]
1502 + * : Use this flag to render a pretty-printed version of the JSON response.
1503 + *
1504 + * @since 4.5.0
1505 + * @param array $args Positional CLI args.
1506 + * @param array $assoc_args Associative CLI args.
1507 + *
1508 + * @subcommand get-search-template
1509 + */
1510 + public function get_search_template( $args, $assoc_args ) {
1511 + $pretty = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pretty' );
1512 + $instant_results = Features::factory()->get_registered_feature( 'instant-results' );
1513 + $template = json_decode( $instant_results->epio_get_search_template() );
1514 +
1515 + $this->pretty_json_encode( $template, $pretty );
1516 + }
1517 +
1518 + /**
1519 + * Saves the Instant Results search template to EPIO.
1520 + *
1521 + * ## OPTIONS
1522 + *
1523 + * [--network-wide]
1524 + * : Save the template for all sites in the network if plugin is network activated. Otherwise, save the template for the current site only.
1525 + *
1526 + * @since 4.5.0
1527 + * @param array $args Positional CLI args.
1528 + * @param array $assoc_args Associative CLI args.
1529 + * @subcommand put-search-template
1530 + */
1531 + public function put_search_template( $args, $assoc_args ) {
1532 + $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network-wide', false );
1533 + $instant_results = Features::factory()->get_registered_feature( 'instant-results' );
1534 +
1535 + $instant_results->epio_save_site_search_template( $network_wide );
1536 +
1537 + WP_CLI::success( esc_html__( 'Done.', 'elasticpress' ) );
1538 + }
1539 +
1540 + /**
1541 + * Deletes the Instant Results search template.
1542 + *
1543 + * ## OPTIONS
1544 + *
1545 + * [--network-wide]
1546 + * : Delete the template for all sites in the network if plugin is network activated. Otherwise, delete the template for the current site only.
1547 + *
1548 + * @since 4.5.0
1549 + * @param array $args Positional CLI args.
1550 + * @param array $assoc_args Associative CLI args.
1551 + * @subcommand delete-search-template
1552 + */
1553 + public function delete_search_template( $args, $assoc_args ) {
1554 + $network_wide = \WP_CLI\Utils\get_flag_value( $assoc_args, 'network-wide', false );
1555 + $instant_results = Features::factory()->get_registered_feature( 'instant-results' );
1556 +
1557 + $instant_results->epio_delete_site_search_template( $network_wide );
1558 +
1559 + WP_CLI::success( esc_html__( 'Done.', 'elasticpress' ) );
1560 + }
1561 +
1562 + /**
1563 + * Get an index settings
1564 + *
1565 + * ## OPTIONS
1566 + *
1567 + * <index_name>
1568 + * : Index name
1569 + *
1570 + * [--pretty]
1571 + * : Use this flag to render a pretty-printed version of the JSON response.
1572 + *
1573 + * @subcommand get-index-settings
1574 + *
1575 + * @since 4.7.0
1576 + *
1577 + * @param array $args Positional CLI args.
1578 + * @param array $assoc_args Associative CLI args.
1579 + */
1580 + public function get_index_settings( $args, $assoc_args ) {
1581 + $response = Elasticsearch::factory()->get_index_settings( $args[0], true );
1582 + $pretty = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pretty' );
1583 +
1584 + $this->pretty_json_encode( $response, $pretty );
1585 + }
1586 +
1587 + /**
1588 + * Get a specific content in Elasticsearch
1589 + *
1590 + * ## OPTIONS
1591 + *
1592 + * <indexable>
1593 + * : Indexable slug. Example: `post`
1594 + *
1595 + * <ID>
1596 + * : Content ID
1597 + *
1598 + * [--debug-http-request]
1599 + * : Enable debugging
1600 + *
1601 + * [--pretty]
1602 + * : Use this flag to render a pretty-printed version of the JSON response.
1603 + *
1604 + * @since 4.7.0
1605 + *
1606 + * @param array $args Positional CLI args.
1607 + * @param array $assoc_args Associative CLI args.
1608 + */
1609 + public function get( $args, $assoc_args ) {
1610 + $indexables = Indexables::factory();
1611 +
1612 + $indexable = $indexables->get( $args[0] );
1613 + if ( ! $indexable || ! $indexables->is_active( $args[0] ) ) {
1614 + $message = wp_sprintf(
1615 + /* translators: list of active indexables slugs */
1616 + esc_html__( 'Indexable not found or inactive. Active indexables are: %l', 'elasticpress' ),
1617 + $indexables->get_all( null, true )
1618 + );
1619 + WP_CLI::error( $message );
1620 + }
1621 +
1622 + $this->maybe_add_http_api_debug_filter( $assoc_args );
1623 +
1624 + $object = $indexable->get( $args[1] );
1625 + if ( ! $object ) {
1626 + WP_CLI::error( esc_html__( 'Not found', 'elasticpress' ) );
1627 + }
1628 +
1629 + $pretty = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pretty' );
1630 +
1631 + $this->pretty_json_encode( $object, $pretty );
1632 + }
1633 +
1634 + /**
1635 + * Given associative CLI args, conditionally displays HTTP debug info
1636 + *
1637 + * @since 4.7.0
1638 + * @param array $assoc_args Associative CLI args.
1639 + */
1640 + protected function maybe_add_http_api_debug_filter( $assoc_args ) {
1641 + $debug_http_request = \WP_CLI\Utils\get_flag_value( $assoc_args, 'debug-http-request' );
1642 +
1643 + if ( ! empty( $debug_http_request ) ) {
1644 + add_filter(
1645 + 'http_api_debug',
1646 + function ( $response, $context, $transport, $request_args, $url ) {
1647 + // phpcs:disable WordPress.PHP.DevelopmentFunctions
1648 + WP_CLI::line(
1649 + sprintf(
1650 + /* translators: URL of the request */
1651 + esc_html__( 'URL: %s', 'elasticpress' ),
1652 + $url
1653 + )
1654 + );
1655 + WP_CLI::line(
1656 + sprintf(
1657 + /* translators: Request arguments (outputted with print_r()) */
1658 + esc_html__( 'Request Args: %s', 'elasticpress' ),
1659 + print_r( $request_args, true )
1660 + )
1661 + );
1662 + WP_CLI::line(
1663 + sprintf(
1664 + /* translators: HTTP transport used */
1665 + esc_html__( 'Transport: %s', 'elasticpress' ),
1666 + $transport
1667 + )
1668 + );
1669 + WP_CLI::line(
1670 + sprintf(
1671 + /* translators: Context under which the http_api_debug hook is fired */
1672 + esc_html__( 'Context: %s', 'elasticpress' ),
1673 + $context
1674 + )
1675 + );
1676 + WP_CLI::line(
1677 + sprintf(
1678 + /* translators: HTTP response (outputted with print_r()) */
1679 + esc_html__( 'Response: %s', 'elasticpress' ),
1680 + print_r( $response, true )
1681 + )
1682 + );
1683 + // phpcs:enable WordPress.PHP.DevelopmentFunctions
1684 + },
1685 + 10,
1686 + 5
1687 + );
1688 + }
1556 1689 }
1557 1690 }