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/Feature/Autosuggest/Autosuggest.php +285 -297 4.4.05.3.5 View file →
@@ -8,14 +8,14 @@
8 8 */
9 9
10 10 namespace ElasticPress\Feature\Autosuggest;
11 11
12 -use ElasticPress\Feature as Feature;
13 -use ElasticPress\Features as Features;
14 -use ElasticPress\Utils as Utils;
15 -use ElasticPress\FeatureRequirementsStatus as FeatureRequirementsStatus;
16 -use ElasticPress\Indexables as Indexables;
17 12 use ElasticPress\Elasticsearch;
13 +use ElasticPress\Feature;
14 +use ElasticPress\FeatureRequirementsStatus;
15 +use ElasticPress\Features;
16 +use ElasticPress\Indexables;
17 +use ElasticPress\Utils;
18 18
19 19 if ( ! defined( 'ABSPATH' ) ) {
20 20 exit; // Exit if accessed directly.
21 21 }
@@ -39,14 +39,10 @@
39 39 */
40 40 public function __construct() {
41 41 $this->slug = 'autosuggest';
42 42
43 - $this->title = esc_html__( 'Autosuggest', 'elasticpress' );
43 + $this->group = 'live-search';
44 44
45 - $this->summary = __( 'Suggest relevant content as text is entered into the search field.', 'elasticpress' );
46 -
47 - $this->docs_url = __( 'https://elasticpress.zendesk.com/hc/en-us/articles/360050447492-Configuring-ElasticPress-via-the-Plugin-Dashboard#autosuggest', 'elasticpress' );
48 -
49 45 $this->requires_install_reindex = true;
50 46
51 47 $this->default_settings = [
52 48 'endpoint_url' => '',
@@ -55,20 +51,27 @@
55 51 ];
56 52
57 53 $this->available_during_installation = true;
58 54
55 + $this->is_powered_by_epio = Utils\is_epio();
56 +
59 57 parent::__construct();
60 58 }
61 59
62 60 /**
63 - * Output feature box long
61 + * Sets i18n strings.
64 62 *
65 - * @since 2.4
63 + * @return void
64 + * @since 5.2.0
66 65 */
67 - public function output_feature_box_long() {
68 - ?>
69 - <p><?php esc_html_e( 'Input fields of type "search" or with the CSS class "search-field" or "ep-autosuggest" will be enhanced with autosuggest functionality. As text is entered into the search field, suggested content will appear below it, based on top search results for the text. Suggestions link directly to the content.', 'elasticpress' ); ?></p>
70 - <?php
66 + public function set_i18n_strings(): void {
67 + $this->title = esc_html__( 'Autosuggest', 'elasticpress' );
68 +
69 + $this->short_title = esc_html__( 'Autosuggest', 'elasticpress' );
70 +
71 + $this->summary = '<p>' . __( 'Input fields of type "search" or with the CSS class "search-field" or "ep-autosuggest" will be enhanced with autosuggest functionality. As text is entered into the search field, suggested content will appear below it, based on top search results for the text. Suggestions link directly to the content.', 'elasticpress' ) . '</p>';
72 +
73 + $this->docs_url = __( 'https://www.elasticpress.io/resources/articles/configuring-elasticpress-via-the-plugin-dashboard/#autosuggest', 'elasticpress' );
71 74 }
72 75
73 76 /**
74 77 * Setup feature functionality
@@ -82,76 +85,12 @@
82 85 add_filter( 'ep_post_fuzziness_arg', [ $this, 'set_fuzziness' ], 10, 3 );
83 86 add_filter( 'ep_weighted_query_for_post_type', [ $this, 'adjust_fuzzy_fields' ], 10, 3 );
84 87 add_filter( 'ep_saved_weighting_configuration', [ $this, 'epio_send_autosuggest_public_request' ] );
85 88 add_filter( 'wp', [ $this, 'epio_send_autosuggest_allowed' ] );
86 - add_filter( 'ep_pre_dashboard_index', [ $this, 'epio_send_autosuggest_public_request' ] );
87 - add_filter( 'ep_wp_cli_pre_index', [ $this, 'epio_send_autosuggest_public_request' ] );
88 -
89 - add_action( 'ep_cli_after_set_search_algorithm_version', [ $this, 'delete_cached_query' ] );
90 - add_action( 'ep_wp_cli_after_index', [ $this, 'delete_cached_query' ] );
91 - add_action( 'ep_after_dashboard_index', [ $this, 'delete_cached_query' ] );
92 - add_action( 'ep_after_update_feature', [ $this, 'delete_cached_query' ] );
93 - add_action( 'ep_cli_after_clear_index', [ $this, 'delete_cached_query' ] );
89 + add_filter( 'ep_pre_sync_index', [ $this, 'epio_send_autosuggest_public_request' ] );
94 90 }
95 91
96 92 /**
97 - * Display decaying settings on dashboard.
98 - *
99 - * @since 2.4
100 - */
101 - public function output_feature_box_settings() {
102 - $settings = $this->get_settings();
103 -
104 - if ( ! $settings ) {
105 - $settings = [];
106 - }
107 -
108 - $settings = wp_parse_args( $settings, $this->default_settings );
109 -
110 - ?>
111 - <div class="field">
112 - <div class="field-name status"><label for="feature_autosuggest_selector"><?php esc_html_e( 'Autosuggest Selector', 'elasticpress' ); ?></label></div>
113 - <div class="input-wrap">
114 - <input value="<?php echo empty( $settings['autosuggest_selector'] ) ? '.ep-autosuggest' : esc_attr( $settings['autosuggest_selector'] ); ?>" type="text" name="settings[autosuggest_selector]" id="feature_autosuggest_selector">
115 - <p class="field-description"><?php esc_html_e( 'Input additional selectors where you would like to include autosuggest separated by a comma. Example: .custom-selector, #custom-id, input[type="text"]', 'elasticpress' ); ?></p>
116 - </div>
117 - </div>
118 -
119 - <div class="field">
120 - <div class="field-name status"><?php esc_html_e( 'Google Analytics Events', 'elasticpress' ); ?></div>
121 - <div class="input-wrap">
122 - <label><input name="settings[trigger_ga_event]" <?php checked( (bool) $settings['trigger_ga_event'] ); ?> type="radio" value="1"><?php esc_html_e( 'Enabled', 'elasticpress' ); ?></label><br>
123 - <label><input name="settings[trigger_ga_event]" <?php checked( ! (bool) $settings['trigger_ga_event'] ); ?> type="radio" value="0"><?php esc_html_e( 'Disabled', 'elasticpress' ); ?></label>
124 - <p class="field-description"><?php esc_html_e( 'When enabled, a gtag tracking event is fired when an autosuggest result is clicked.', 'elasticpress' ); ?></p>
125 - </div>
126 - </div>
127 - <?php
128 -
129 - if ( Utils\is_epio() ) {
130 - $this->epio_allowed_parameters();
131 - return;
132 - }
133 -
134 - $endpoint_url = ( defined( 'EP_AUTOSUGGEST_ENDPOINT' ) && EP_AUTOSUGGEST_ENDPOINT ) ? EP_AUTOSUGGEST_ENDPOINT : $settings['endpoint_url'];
135 - ?>
136 -
137 - <div class="field">
138 - <div class="field-name status"><label for="feature_autosuggest_endpoint_url"><?php esc_html_e( 'Endpoint URL', 'elasticpress' ); ?></label></div>
139 - <div class="input-wrap">
140 - <input <?php disabled( defined( 'EP_AUTOSUGGEST_ENDPOINT' ) && EP_AUTOSUGGEST_ENDPOINT ); ?> value="<?php echo esc_url( $endpoint_url ); ?>" type="text" name="settings[endpoint_url]" id="feature_autosuggest_endpoint_url">
141 -
142 - <?php if ( defined( 'EP_AUTOSUGGEST_ENDPOINT' ) && EP_AUTOSUGGEST_ENDPOINT ) : ?>
143 - <p class="field-description"><?php esc_html_e( 'Your autosuggest endpoint is set in wp-config.php', 'elasticpress' ); ?></p>
144 - <?php endif; ?>
145 -
146 - <p class="field-description"><?php esc_html_e( 'This address will be exposed to the public.', 'elasticpress' ); ?></p>
147 - </div>
148 - </div>
149 -
150 - <?php
151 - }
152 -
153 - /**
154 93 * Add mapping for suggest fields
155 94 *
156 95 * @param array $mapping ES mapping.
157 96 * @since 2.4
@@ -157,46 +96,27 @@
157 96 * @since 2.4
158 97 * @return array
159 98 */
160 99 public function mapping( $mapping ) {
161 - $mapping['settings']['analysis']['analyzer']['edge_ngram_analyzer'] = array(
162 - 'type' => 'custom',
163 - 'tokenizer' => 'standard',
164 - 'filter' => array(
165 - 'lowercase',
166 - 'edge_ngram',
167 - ),
168 - );
100 + $post_indexable = Indexables::factory()->get( 'post' );
169 101
170 - if ( version_compare( Elasticsearch::factory()->get_elasticsearch_version(), '7.0', '<' ) ) {
171 - $text_type = $mapping['mappings']['post']['properties']['post_content']['type'];
102 + $mapping = $post_indexable->add_ngram_analyzer( $mapping );
103 + $mapping = $post_indexable->add_term_suggest_field( $mapping );
172 104
173 - $mapping['mappings']['post']['properties']['post_title']['fields']['suggest'] = array(
174 - 'type' => $text_type,
175 - 'analyzer' => 'edge_ngram_analyzer',
176 - 'search_analyzer' => 'standard',
177 - );
178 -
179 - $mapping['mappings']['post']['properties']['term_suggest'] = array(
180 - 'type' => $text_type,
181 - 'analyzer' => 'edge_ngram_analyzer',
182 - 'search_analyzer' => 'standard',
183 - );
105 + // Note the assignment by reference below.
106 + if ( version_compare( (string) Elasticsearch::factory()->get_elasticsearch_version(), '7.0', '<' ) ) {
107 + $mapping_properties = &$mapping['mappings']['post']['properties'];
184 108 } else {
185 - $text_type = $mapping['mappings']['properties']['post_content']['type'];
109 + $mapping_properties = &$mapping['mappings']['properties'];
110 + }
186 111
187 - $mapping['mappings']['properties']['post_title']['fields']['suggest'] = array(
188 - 'type' => $text_type,
189 - 'analyzer' => 'edge_ngram_analyzer',
190 - 'search_analyzer' => 'standard',
191 - );
112 + $text_type = $mapping_properties['post_content']['type'];
192 113
193 - $mapping['mappings']['properties']['term_suggest'] = array(
194 - 'type' => $text_type,
195 - 'analyzer' => 'edge_ngram_analyzer',
196 - 'search_analyzer' => 'standard',
197 - );
198 - }
114 + $mapping_properties['post_title']['fields']['suggest'] = array(
115 + 'type' => $text_type,
116 + 'analyzer' => 'edge_ngram_analyzer',
117 + 'search_analyzer' => 'standard',
118 + );
199 119
200 120 return $mapping;
201 121 }
202 122
@@ -208,9 +128,9 @@
208 128 * @param array $args Array of ES args
209 129 * @return array
210 130 */
211 131 public function set_fuzziness( $fuzziness, $search_fields, $args ) {
212 - if ( Utils\is_integrated_request( $this->slug, [ 'public' ] ) && ! empty( $args['s'] ) ) {
132 + if ( Utils\is_integrated_request( $this->slug, $this->get_contexts() ) && ! empty( $args['s'] ) ) {
213 133 return 'auto';
214 134 }
215 135 return $fuzziness;
216 136 }
@@ -223,9 +143,9 @@
223 143 * @param array $args WP_Query args
224 144 * @return array $query adjusted ES Query arguments
225 145 */
226 146 public function adjust_fuzzy_fields( $query, $post_type, $args ) {
227 - if ( ! Utils\is_integrated_request( $this->slug, [ 'public' ] ) || empty( $args['s'] ) ) {
147 + if ( ! Utils\is_integrated_request( $this->slug, $this->get_contexts() ) || empty( $args['s'] ) ) {
228 148 return $query;
229 149 }
230 150
231 151 if ( ! isset( $query['bool'] ) || ! isset( $query['bool']['must'] ) ) {
@@ -372,30 +292,21 @@
372 292 if ( Utils\is_indexing() ) {
373 293 return;
374 294 }
375 295
376 - $host = Utils\get_host();
377 - $endpoint_url = false;
378 - $settings = $this->get_settings();
296 + $host = Utils\get_host();
297 + $settings = $this->get_settings();
379 298
380 299 if ( defined( 'EP_AUTOSUGGEST_ENDPOINT' ) && EP_AUTOSUGGEST_ENDPOINT ) {
381 300 $endpoint_url = EP_AUTOSUGGEST_ENDPOINT;
301 + } elseif ( Utils\is_epio() ) {
302 + $endpoint_url = trailingslashit( $host ) . Indexables::factory()->get( 'post' )->get_index_name() . '/autosuggest';
382 303 } else {
383 - if ( Utils\is_epio() ) {
384 - $endpoint_url = trailingslashit( $host ) . Indexables::factory()->get( 'post' )->get_index_name() . '/autosuggest';
385 - } else {
386 - if ( ! $settings ) {
387 - $settings = [];
388 - }
304 + $endpoint_url = $settings['endpoint_url'];
305 + }
389 306
390 - $settings = wp_parse_args( $settings, $this->default_settings );
391 -
392 - if ( empty( $settings['endpoint_url'] ) ) {
393 - return;
394 - }
395 -
396 - $endpoint_url = $settings['endpoint_url'];
397 - }
307 + if ( empty( $endpoint_url ) ) {
308 + return;
398 309 }
399 310
400 311 wp_enqueue_script(
401 312 'elasticpress-autosuggest',
@@ -419,16 +330,8 @@
419 330
420 331 /** Search Feature @var Feature\Search\Search $search */
421 332 $search = $features->get_registered_feature( 'search' );
422 333
423 - $post_types = $search->get_searchable_post_types();
424 - $post_status = get_post_stati(
425 - [
426 - 'public' => true,
427 - 'exclude_from_search' => false,
428 - ]
429 - );
430 -
431 334 $query = $this->generate_search_query();
432 335
433 336 $epas_options = [
434 337 'query' => $query['body'],
@@ -455,8 +358,9 @@
455 358 */
456 359 'http_headers' => apply_filters( 'ep_autosuggest_http_headers', [] ),
457 360 'triggerAnalytics' => ! empty( $settings['trigger_ga_event'] ),
458 361 'addSearchTermHeader' => false,
362 + 'requestIdBase' => Utils\get_request_id_base(),
459 363 ];
460 364
461 365 if ( Utils\is_epio() ) {
462 366 $epas_options['addSearchTermHeader'] = true;
@@ -546,47 +450,47 @@
546 450 * @return {array} New post statuses
547 451 */
548 452 $post_status = apply_filters( 'ep_term_suggest_post_status', array_values( $post_status ) );
549 453
550 - add_filter( 'ep_intercept_remote_request', '__return_true' );
551 - add_filter( 'ep_weighting_configuration', [ $features->get_registered_feature( $this->slug ), 'apply_autosuggest_weighting' ], 10, 1 );
454 + add_filter( 'ep_weighting_configuration', [ $features->get_registered_feature( $this->slug ), 'apply_autosuggest_weighting' ] );
552 455
553 - add_filter( 'ep_do_intercept_request', [ $features->get_registered_feature( $this->slug ), 'intercept_search_request' ], 10, 4 );
456 + add_filter( 'ep_do_intercept_request', [ $features->get_registered_feature( $this->slug ), 'intercept_search_request' ], 10, 2 );
554 457
555 458 add_filter( 'posts_pre_query', [ $features->get_registered_feature( $this->slug ), 'return_empty_posts' ], 100, 1 ); // after ES Query to ensure we are not falling back to DB in any case
556 459
557 - new \WP_Query(
558 - /**
559 - * Filter WP Query args of the autosuggest query template.
560 - *
561 - * If you want to display 20 posts in autosuggest:
562 - *
563 - * ```
564 - * add_filter(
565 - * 'ep_autosuggest_query_args',
566 - * function( $args ) {
567 - * $args['posts_per_page'] = 20;
568 - * return $args;
569 - * }
570 - * );
571 - * ```
572 - *
573 - * @since 4.4.0
574 - * @hook ep_autosuggest_query_args
575 - * @param {array} $args Query args
576 - * @return {array} New query args
577 - */
578 - apply_filters(
579 - 'ep_autosuggest_query_args',
580 - [
581 - 'post_type' => $post_type,
582 - 'post_status' => $post_status,
583 - 's' => $placeholder,
584 - 'ep_integrate' => true,
585 - ]
586 - )
460 + /**
461 + * Filter WP Query args of the autosuggest query template.
462 + *
463 + * If you want to display 20 posts in autosuggest:
464 + *
465 + * ```
466 + * add_filter(
467 + * 'ep_autosuggest_query_args',
468 + * function( $args ) {
469 + * $args['posts_per_page'] = 20;
470 + * return $args;
471 + * }
472 + * );
473 + * ```
474 + *
475 + * @since 4.4.0
476 + * @hook ep_autosuggest_query_args
477 + * @param {array} $args Query args
478 + * @return {array} New query args
479 + */
480 + $args = apply_filters(
481 + 'ep_autosuggest_query_args',
482 + [
483 + 'post_type' => $post_type,
484 + 'post_status' => $post_status,
485 + 's' => $placeholder,
486 + 'ep_integrate' => true,
487 + 'ep_intercept_request' => true,
488 + ]
587 489 );
588 490
491 + new \WP_Query( $args );
492 +
589 493 remove_filter( 'posts_pre_query', [ $features->get_registered_feature( $this->slug ), 'return_empty_posts' ], 100 );
590 494
591 495 remove_filter( 'ep_do_intercept_request', [ $features->get_registered_feature( $this->slug ), 'intercept_search_request' ] );
592 496
@@ -591,13 +495,12 @@
591 495 remove_filter( 'ep_do_intercept_request', [ $features->get_registered_feature( $this->slug ), 'intercept_search_request' ] );
592 496
593 497 remove_filter( 'ep_weighting_configuration', [ $features->get_registered_feature( $this->slug ), 'apply_autosuggest_weighting' ] );
594 498
595 - remove_filter( 'ep_intercept_remote_request', '__return_true' );
596 -
597 499 return [
598 500 'body' => $this->autosuggest_query,
599 501 'placeholder' => $placeholder,
502 + 'query_vars' => $args,
600 503 ];
601 504 }
602 505
603 506 /**
@@ -628,68 +531,34 @@
628 531 return $config;
629 532 }
630 533
631 534 /**
632 - * Store intercepted request value and return (cached) request result
535 + * Store intercepted request value and return a fake successful request result
633 536 *
634 - * @param object $response Response
635 - * @param array $query Query
636 - * @param array $args WP_Query Argument array
637 - * @param int $failures Count of failures in request loop
638 - * @return object $response Response
537 + * @param array $response Response
538 + * @param array $query ES Query
539 + * @return array $response Response
639 540 */
640 - public function intercept_search_request( $response, $query = [], $args = [], $failures = 0 ) {
541 + public function intercept_search_request( $response, $query = [] ) {
641 542 $this->autosuggest_query = $query['args']['body'];
642 543
643 - // Let's make sure we also fire off the dummy request if settings have changed.
644 - // But only fire this if we have object caching as otherwise this comes with a performance penalty.
645 - // If we do not have object caching we cache only one value for 5 minutes in a transient.
646 - if ( wp_using_ext_object_cache() ) {
647 - $cache_key = md5( wp_json_encode( $query['url'] ) . wp_json_encode( $args ) );
648 - $request = wp_cache_get( $cache_key, 'ep_autosuggest' );
649 - if ( false === $request ) {
650 - $request = wp_remote_request( $query['url'], $args );
651 - if ( isset( $request->http_response ) && isset( $request->http_response->body ) ) {
652 - $request->http_response->body = '';
653 - }
654 - wp_cache_set( $cache_key, $request, 'ep_autosuggest' );
655 - }
656 - } else {
657 - $cache_key = 'ep_autosuggest_query_request_cache';
658 - $request = get_transient( $cache_key );
659 - if ( false === $request ) {
660 - $request = wp_remote_request( $query['url'], $args );
661 - if ( isset( $request->http_response ) && isset( $request->http_response->body ) ) {
662 - $request->http_response->body = '';
663 - }
664 - set_transient( $cache_key, $request, 5 * MINUTE_IN_SECONDS );
665 - }
666 - }
544 + $message = wp_json_encode(
545 + [
546 + esc_html__( 'This is a fake request to build the ElasticPress Autosuggest query. It is not really sent.', 'elasticpress' ),
547 + ]
548 + );
667 549
668 - return $request;
550 + return [
551 + 'is_ep_fake_request' => true,
552 + 'body' => $message,
553 + 'response' => [
554 + 'code' => 200,
555 + 'message' => $message,
556 + ],
557 + ];
669 558 }
670 559
671 560 /**
672 - * Delete the cached query for autosuggest.
673 - *
674 - * @since 3.5.5
675 - */
676 - public function delete_cached_query() {
677 - global $wp_object_cache;
678 - if ( wp_using_ext_object_cache() ) {
679 - if ( function_exists( 'wp_cache_supports_group_flush' ) && wp_cache_supports_group_flush() ) {
680 - wp_cache_flush_group( 'ep_autosuggest' );
681 - } else {
682 - // Try to delete the entire group.
683 - // This may fail because the `$cache` property is not standardized.
684 - unset( $wp_object_cache->cache['ep_autosuggest'] );
685 - }
686 - } else {
687 - delete_transient( 'ep_autosuggest_query_request_cache' );
688 - }
689 - }
690 -
691 - /**
692 561 * Tell user whether requirements for feature are met or not.
693 562 *
694 563 * @return array $status Status array
695 564 * @since 2.4
@@ -694,9 +563,9 @@
694 563 * @return array $status Status array
695 564 * @since 2.4
696 565 */
697 566 public function requirements_status() {
698 - $status = new FeatureRequirementsStatus( 0 );
567 + $status = new FeatureRequirementsStatus( 0, null, $this );
699 568
700 569 $status->message = [];
701 570
702 571 $status->message[] = esc_html__( 'This feature modifies the site’s default user experience by presenting a list of suggestions below detected search fields as text is entered into the field.', 'elasticpress' );
@@ -721,21 +590,17 @@
721 590 if ( ! Utils\is_epio() ) {
722 591 return;
723 592 }
724 593
725 - $url = add_query_arg(
726 - [
727 - 's' => 'search test',
728 - 'ep_epio_set_autosuggest' => 1,
729 - 'ep_epio_nonce' => wp_create_nonce( 'ep-epio-set-autosuggest' ),
730 - 'nocache' => time(), // Here just to avoid the request hitting a CDN.
731 - ],
732 - home_url( '/' )
733 - );
594 + $url = $this->get_epio_public_request_url();
734 595
735 596 // Pass the same cookies, so the same authenticated user is used (and we can check the nonce).
736 597 $cookies = [];
737 598 foreach ( $_COOKIE as $name => $value ) {
599 + if ( ! is_string( $name ) || ! is_string( $value ) ) {
600 + continue;
601 + }
602 +
738 603 $cookies[] = new \WP_Http_Cookie(
739 604 [
740 605 'name' => $name,
741 606 'value' => $value,
@@ -752,14 +617,33 @@
752 617 );
753 618 }
754 619
755 620 /**
621 + * Get the public request URL that saves the autosuggest allowed parameters.
622 + *
623 + * @since 5.3.0
624 + * @return string
625 + */
626 + public function get_epio_public_request_url(): string {
627 + return add_query_arg(
628 + [
629 + 's' => 'search test',
630 + 'ep_epio_set_autosuggest' => 1,
631 + 'ep_epio_nonce' => wp_create_nonce( 'ep-epio-set-autosuggest' ),
632 + 'nocache' => time(), // Here just to avoid the request hitting a CDN.
633 + ],
634 + home_url( '/' )
635 + );
636 + }
637 +
638 + /**
756 639 * Send the allowed parameters for autosuggest to ElasticPress.io.
757 640 */
758 641 public function epio_send_autosuggest_allowed() {
759 - if ( empty( $_REQUEST['ep_epio_nonce'] ) || ! wp_verify_nonce( $_REQUEST['ep_epio_nonce'], 'ep-epio-set-autosuggest' ) ) {
642 + if ( empty( $_REQUEST['ep_epio_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ep_epio_nonce'] ), 'ep-epio-set-autosuggest' ) ) {
760 643 return;
761 644 }
645 +
762 646 if ( empty( $_GET['ep_epio_set_autosuggest'] ) ) {
763 647 return;
764 648 }
765 649
@@ -770,14 +654,16 @@
770 654 * @since 3.5.x
771 655 */
772 656 do_action( 'ep_epio_pre_send_autosuggest_allowed' );
773 657
658 + $search_query = $this->generate_search_query();
659 +
774 660 /**
775 661 * The same ES query sent by autosuggest.
776 662 *
777 663 * Sometimes it'll be a string, sometimes it'll be already an array.
778 664 */
779 - $es_search_query = $this->generate_search_query()['body'];
665 + $es_search_query = $search_query['body'];
780 666 $es_search_query = ( is_array( $es_search_query ) ) ? $es_search_query : json_decode( $es_search_query, true );
781 667
782 668 /**
783 669 * Filter autosuggest ES query
@@ -799,9 +685,10 @@
799 685 $index = Indexables::factory()->get( 'post' )->get_index_name();
800 686
801 687 add_filter( 'ep_format_request_headers', [ $this, 'add_ep_set_autosuggest_header' ] );
802 688
803 - Elasticsearch::factory()->query( $index, 'post', $es_search_query, [] );
689 + $search_query['query_vars']['ep_intercept_request'] = false;
690 + Elasticsearch::factory()->query( $index, 'post', $es_search_query, $search_query['query_vars'] );
804 691
805 692 remove_filter( 'ep_format_request_headers', [ $this, 'add_ep_set_autosuggest_header' ] );
806 693
807 694 /**
@@ -853,63 +740,24 @@
853 740 ?>
854 741 <div class="field js-toggle-feature" data-feature="<?php echo esc_attr( $this->slug ); ?>">
855 742 <div class="field-name status"><?php esc_html_e( 'Connection', 'elasticpress' ); ?></div>
856 743 <div class="input-wrap">
857 - <?php
858 - $epio_link = '';
859 - $epio_autosuggest_kb_link = 'https://elasticpress.zendesk.com/hc/en-us/articles/360055402791';
744 + <?php
745 + $epio_link = 'https://elasticpress.io';
746 + $epio_autosuggest_kb_link = 'https://www.elasticpress.io/resources/articles/elasticpress-io-autosuggest/';
747 + $status_report_link = defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ? network_admin_url( 'admin.php?page=elasticpress-status-report' ) : admin_url( 'admin.php?page=elasticpress-status-report' );
860 748
861 - // If WordPress 5.2+, show debug in Health Check. Otherwise, show it if WP_DEBUG is enabled.
862 - if ( version_compare( $wp_version, '5.2', '>=' ) || 0 === stripos( $wp_version, '5.2-' ) ) {
863 - printf(
864 - /* translators: 1: <a> tag (ElasticPress.io); 2. </a>; 3: <a> tag (KB article); 4. </a>; 5: <a> tag (Site Health Debug Section); 6. </a>; */
865 - esc_html__( 'You are directly connected to %1$sElasticPress.io%2$s, ensuring the most performant Autosuggest experience. %3$sLearn more about what this means%4$s or %5$sclick here for debug information%6$s.', 'elasticpress' ),
866 - '<a href="' . esc_url( $epio_link ) . '">',
867 - '</a>',
868 - '<a href="' . esc_url( $epio_autosuggest_kb_link ) . '">',
869 - '</a>',
870 - '<a href="' . esc_url( admin_url( 'site-health.php?tab=debug' ) ) . '">',
871 - '</a>'
872 - );
873 - } else {
874 - printf(
875 - /* translators: 1: <a> tag (ElasticPress.io); 2. </a>; 3: <a> tag (KB article); 4. </a>; */
876 - esc_html__( 'You are directly connected to %1$sElasticPress.io%2$s, ensuring the most performant Autosuggest experience. %1$sLearn more about what this means%2$s.', 'elasticpress' ),
877 - '<a href="' . esc_url( $epio_link ) . '">',
878 - '</a>',
879 - '<a href="' . esc_url( $epio_autosuggest_kb_link ) . '">',
880 - '</a>'
881 - );
882 -
883 - if ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || ( defined( 'WP_EP_DEBUG' ) && WP_EP_DEBUG ) ) {
884 - ?>
885 - <p><?php esc_html_e( 'These are the allowed parameters stored in ElasticPress.io', 'elasticpress' ); ?></p>
886 - <?php
887 - $allowed_params = wp_parse_args(
888 - $allowed_params,
889 - [
890 - 'postTypes' => [],
891 - 'postStatus' => [],
892 - 'searchFields' => [],
893 - 'returnFields' => '',
894 - ]
895 - );
896 -
897 - $fields = [
898 - wp_sprintf( esc_html__( 'Post Types: %l', 'elasticpress' ), $allowed_params['postTypes'] ),
899 - wp_sprintf( esc_html__( 'Post Status: %l', 'elasticpress' ), $allowed_params['postStatus'] ),
900 - wp_sprintf( esc_html__( 'Search Fields: %l', 'elasticpress' ), $allowed_params['searchFields'] ),
901 - /* translators: List of files allowed to be returned wrapped by var_export() */
902 - wp_sprintf( esc_html__( 'Returned Fields: %s', 'elasticpress' ), var_export( $allowed_params['returnFields'], true ) ), // phpcs:ignore
903 - ];
904 -
905 - echo implode( '<br>', $fields ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
906 - }
907 - }
908 - ?>
909 - <p>
910 - <img width="150" src="<?php echo esc_url( plugins_url( '/images/logo-elasticpress-io.svg', EP_FILE ) ); ?>">
911 - </p>
749 + printf(
750 + /* translators: 1: <a> tag (ElasticPress.io); 2. </a>; 3: <a> tag (KB article); 4. </a>; 5: <a> tag (Site Health Debug Section); 6. </a>; */
751 + esc_html__( 'You are directly connected to %1$sElasticPress.io%2$s, ensuring the most performant Autosuggest experience. %3$sLearn more about what this means%4$s or %5$sclick here for debug information%6$s.', 'elasticpress' ),
752 + '<a href="' . esc_url( $epio_link ) . '">',
753 + '</a>',
754 + '<a href="' . esc_url( $epio_autosuggest_kb_link ) . '">',
755 + '</a>',
756 + '<a href="' . esc_url( $status_report_link ) . '">',
757 + '</a>'
758 + );
759 + ?>
912 760 </div>
913 761 </div>
914 762 <?php
915 763 }
@@ -930,13 +778,153 @@
930 778 $allowed_params = [];
931 779 break;
932 780 }
933 781
934 - if ( empty( $allowed_params ) ) {
935 - $this->epio_send_autosuggest_public_request( true );
782 + // We have what we need, no need to retry.
783 + if ( ! empty( $allowed_params ) ) {
784 + break;
936 785 }
786 +
787 + // Send to EP.io what should be autosuggest's allowed values and try to get them again.
788 + $this->epio_send_autosuggest_public_request( true );
937 789 }
938 790
939 791 return $allowed_params;
940 792 }
941 793
794 + /**
795 + * Send a request to EP.io to reset the allowed parameters for autosuggest.
796 + *
797 + * @since 5.3.2
798 + */
799 + public function post_deactivation() {
800 + $index = Indexables::factory()->get( 'post' )->get_index_name();
801 +
802 + add_filter( 'ep_format_request_headers', [ $this, 'add_ep_set_autosuggest_header' ] );
803 +
804 + Elasticsearch::factory()->query( $index, 'post', [], [] );
805 +
806 + remove_filter( 'ep_format_request_headers', [ $this, 'add_ep_set_autosuggest_header' ] );
807 +
808 + // this action is documented in Feature.php
809 + do_action( 'ep_feature_post_deactivation', $this->slug, $this );
810 + }
811 +
812 + /**
813 + * Return true, so EP knows we want to intercept the remote request
814 + *
815 + * As we add and remove this function from `ep_intercept_remote_request`,
816 + * using `__return_true` could remove a *real* `__return_true` added by someone else.
817 + *
818 + * @since 4.7.0
819 + * @see https://github.com/10up/ElasticPress/issues/2887
820 + * @return true
821 + */
822 + public function intercept_remote_request() {
823 + _doing_it_wrong(
824 + __METHOD__,
825 + esc_html__( 'Use the WP_Query argument `ep_intercept_request` instead.', 'elasticpress' ),
826 + 'ElasticPress 5.3.0'
827 + );
828 +
829 + return true;
830 + }
831 +
832 + /**
833 + * Conditionally add EP.io information to the settings schema
834 + *
835 + * @since 5.0.0
836 + */
837 + protected function maybe_add_epio_settings_schema() {
838 + if ( ! Utils\is_epio() ) {
839 + return;
840 + }
841 +
842 + $epio_link = 'https://elasticpress.io';
843 + $epio_autosuggest_kb_link = 'https://www.elasticpress.io/resources/articles/elasticpress-io-autosuggest/';
844 + $status_report_link = defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ? network_admin_url( 'admin.php?page=elasticpress-status-report' ) : admin_url( 'admin.php?page=elasticpress-status-report' );
845 +
846 + $this->settings_schema[] = [
847 + 'key' => 'epio',
848 + 'label' => sprintf(
849 + /* translators: 1: <a> tag (ElasticPress.io); 2. </a>; 3: <a> tag (KB article); 4. </a>; 5: <a> tag (Site Health Debug Section); 6. </a>; */
850 + __( 'You are directly connected to %1$sElasticPress.io%2$s, ensuring the most performant Autosuggest experience. %3$sLearn more about what this means%4$s or %5$sclick here for debug information%6$s.', 'elasticpress' ),
851 + '<a href="' . esc_url( $epio_link ) . '">',
852 + '</a>',
853 + '<a href="' . esc_url( $epio_autosuggest_kb_link ) . '">',
854 + '</a>',
855 + '<a href="' . esc_url( $status_report_link ) . '">',
856 + '</a>'
857 + ),
858 + 'type' => 'markup',
859 + ];
860 + }
861 +
862 + /**
863 + * Set the `settings_schema` attribute
864 + *
865 + * @since 5.0.0
866 + */
867 + protected function set_settings_schema() {
868 + $this->settings_schema = [
869 + [
870 + 'default' => '.ep-autosuggest',
871 + 'help' => __( 'Input additional selectors where you would like to include autosuggest, separated by a comma. Example: <code>.custom-selector, #custom-id, input[type="text"]</code>', 'elasticpress' ),
872 + 'key' => 'autosuggest_selector',
873 + 'label' => __( 'Additional selectors', 'elasticpress' ),
874 + 'type' => 'text',
875 + ],
876 + [
877 + 'default' => '0',
878 + 'key' => 'trigger_ga_event',
879 + 'help' => __( 'Enable to fire a gtag tracking event when an autosuggest result is clicked.', 'elasticpress' ),
880 + 'label' => __( 'Trigger Google Analytics events', 'elasticpress' ),
881 + 'type' => 'checkbox',
882 + ],
883 + ];
884 +
885 + $this->maybe_add_epio_settings_schema();
886 +
887 + if ( ! Utils\is_epio() ) {
888 + $set_in_wp_config = defined( 'EP_AUTOSUGGEST_ENDPOINT' ) && EP_AUTOSUGGEST_ENDPOINT;
889 +
890 + $this->settings_schema[] = [
891 + 'disabled' => $set_in_wp_config,
892 + 'help' => ! $set_in_wp_config ? __( 'A valid URL starting with <code>http://</code> or <code>https://</code>. This address will be exposed to the public.', 'elasticpress' ) : '',
893 + 'key' => 'endpoint_url',
894 + 'label' => __( 'Endpoint URL', 'elasticpress' ),
895 + 'type' => 'url',
896 + ];
897 + }
898 + }
899 +
900 + /**
901 + * DEPRECATED. Delete the cached query for autosuggest.
902 + *
903 + * @since 3.5.5
904 + */
905 + public function delete_cached_query() {
906 + _doing_it_wrong(
907 + __METHOD__,
908 + esc_html__( 'This method should not be called anymore, as autosuggest requests are not sent regularly anymore.', 'elasticpress' ),
909 + 'ElasticPress 4.7.0'
910 + );
911 + }
912 +
913 + /**
914 + * Get the contexts for autosuggest.
915 + *
916 + * @since 5.1.0
917 + * @return array
918 + */
919 + protected function get_contexts(): array {
920 + /**
921 + * Filter contexts for autosuggest.
922 + *
923 + * @hook ep_autosuggest_contexts
924 + * @since 5.1.0
925 + * @param {array} $contexts Contexts for autosuggest
926 + * @return {array} New contexts
927 + */
928 + return apply_filters( 'ep_autosuggest_contexts', [ 'public', 'ajax' ] );
929 + }
942 930 }