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
elasticpress / includes / classes / Feature / Facets / Facets.php

Facets.php in ElasticPress 5.3.5, at includes/classes/Feature/Facets/Facets.php

781 lines 21.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Facets feature
4 *
5 * @since 2.5
6 * @package elasticpress
7 */
8
9 namespace ElasticPress\Feature\Facets;
10
11 use ElasticPress\Feature;
12 use ElasticPress\Features;
13 use ElasticPress\Indexables;
14 use ElasticPress\REST;
15 use ElasticPress\Utils;
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit; // Exit if accessed directly.
19 }
20
21 /**
22 * Facets feature class
23 */
24 class Facets extends Feature {
25 /**
26 * Facet types (taxonomy, meta fields, etc.)
27 *
28 * @since 4.3.0
29 * @var array
30 */
31 public $types = [];
32
33 /**
34 * Initialize feature setting it's config
35 *
36 * @since 3.0
37 */
38 public function __construct() {
39 $this->slug = 'facets';
40
41 $this->group = 'core-search';
42
43 $this->requires_install_reindex = false;
44
45 $this->default_settings = [
46 'match_type' => 'all',
47 ];
48
49 $types = [
50 'taxonomy' => __NAMESPACE__ . '\Types\Taxonomy\FacetType',
51 ];
52
53 if ( version_compare( get_bloginfo( 'version' ), '5.8', '>=' ) ) {
54 $types['meta'] = __NAMESPACE__ . '\Types\Meta\FacetType';
55 $types['meta-range'] = __NAMESPACE__ . '\Types\MetaRange\FacetType';
56 $types['post-type'] = __NAMESPACE__ . '\Types\PostType\FacetType';
57 $types['date'] = __NAMESPACE__ . '\Types\Date\FacetType';
58
59 }
60
61 /**
62 * Filter the Facet types available.
63 *
64 * ```
65 * add_filter(
66 * 'ep_facet_types',
67 * function ( $types ) {
68 * $types['post_type'] = '\MyPlugin\PostType';
69 * return $types;
70 * }
71 * );
72 * ```
73 *
74 * @since 4.3.0
75 * @hook ep_facet_types
76 * @param {array} $types Array of types available. Keys are slugs, values are class names.
77 * @return {array} New array of types available
78 */
79 $types = apply_filters( 'ep_facet_types', $types );
80
81 foreach ( $types as $type => $class ) {
82 if ( is_a( $class, __NAMESPACE__ . '\FacetType', true ) ) {
83 $this->types[ $type ] = new $class();
84 }
85 }
86
87 parent::__construct();
88 }
89
90 /**
91 * Sets i18n strings.
92 *
93 * @return void
94 * @since 5.2.0
95 */
96 public function set_i18n_strings(): void {
97 $this->title = esc_html__( 'Filters', 'elasticpress' );
98
99 $this->summary = '<p>' .
100 ( wp_is_block_theme()
101 ? sprintf(
102 /* translators: Site Editor URL */
103 __( 'Adds <a href="%s">filter blocks</a> that administrators can add to the website’s templates and template parts, so that visitors can filter applicable content and search results by one or more taxonomy terms, metafields, and date ranges.', 'elasticpress' ),
104 esc_url( admin_url( 'site-editor.php' ) )
105 )
106 : sprintf(
107 /* translators: Widgets Edit Screen URL */
108 __( 'Adds <a href="%s">filter widgets</a> that administrators can add to the website’s sidebars (widgetized areas), so that visitors can filter applicable content and search results by one or more taxonomy terms, metafields, and date ranges.', 'elasticpress' ),
109 esc_url( admin_url( 'widgets.php' ) )
110 )
111 ) . '</p>';
112
113 $this->docs_url = __( 'https://www.elasticpress.io/resources/articles/configuring-elasticpress-via-the-plugin-dashboard/#filters', 'elasticpress' );
114 }
115
116 /**
117 * Setup hooks and filters for feature
118 *
119 * @since 2.5
120 */
121 public function setup() {
122 foreach ( $this->types as $type => $class ) {
123 $this->types[ $type ]->setup();
124 }
125
126 add_filter( 'widget_types_to_hide_from_legacy_widget_block', [ $this, 'hide_legacy_widget' ] );
127 add_action( 'ep_valid_response', [ $this, 'get_aggs' ], 10, 4 );
128 add_action( 'wp_enqueue_scripts', [ $this, 'front_scripts' ] );
129 add_action( 'enqueue_block_editor_assets', [ $this, 'front_scripts' ] );
130 add_action( 'ep_feature_box_settings_facets', [ $this, 'settings' ], 10, 1 );
131 add_filter( 'ep_post_formatted_args', [ $this, 'set_agg_filters' ], 10, 3 );
132 add_action( 'pre_get_posts', [ $this, 'facet_query' ] );
133 add_filter( 'ep_post_filters', [ $this, 'apply_facets_filters' ], 10, 3 );
134 add_action( 'rest_api_init', [ $this, 'setup_endpoints' ] );
135 }
136
137 /**
138 * Unsetup Facets related hooks
139 *
140 * @since 5.1.0
141 */
142 public function tear_down() {
143 remove_filter( 'widget_types_to_hide_from_legacy_widget_block', [ $this, 'hide_legacy_widget' ] );
144 remove_action( 'ep_valid_response', [ $this, 'get_aggs' ] );
145 remove_action( 'wp_enqueue_scripts', [ $this, 'front_scripts' ] );
146 remove_action( 'enqueue_block_editor_assets', [ $this, 'front_scripts' ] );
147 remove_action( 'ep_feature_box_settings_facets', [ $this, 'settings' ] );
148 remove_filter( 'ep_post_formatted_args', [ $this, 'set_agg_filters' ] );
149 remove_action( 'pre_get_posts', [ $this, 'facet_query' ] );
150 remove_filter( 'ep_post_filters', [ $this, 'apply_facets_filters' ] );
151 remove_action( 'rest_api_init', [ $this, 'setup_endpoints' ] );
152 }
153
154 /**
155 * If we are doing `or` matches, we need to remove filters from aggs.
156 *
157 * By default, the same filters applied to the main query are applied to aggregations.
158 * If doing `or` matches, those should be removed so we get a broader set of results.
159 *
160 * @param array $args ES arguments
161 * @param array $query_args Query arguments
162 * @param WP_Query $query WP Query instance
163 * @since 2.5
164 * @return array
165 */
166 public function set_agg_filters( $args, $query_args, $query ) {
167 // Not a facetable query
168 if ( empty( $query_args['ep_facet'] ) ) {
169 return $args;
170 }
171
172 if ( 'any' === $this->get_match_type() ) {
173 add_filter( 'ep_post_filters', [ $this, 'remove_facets_filter' ], 11 );
174 }
175
176 /**
177 * This flag is used to differentiate filters being applied to the query and to its aggregations.
178 */
179 $query_args['ep_facet_adding_agg_filters'] = true;
180
181 /**
182 * Filter WP query arguments that will be used to build the aggregations filter.
183 *
184 * The returned `$query_args` will be used to build the aggregations filter passing
185 * it through `Indexable\Post\Post::format_args()`.
186 *
187 * @hook ep_facet_agg_filters
188 * @since 4.3.0
189 * @param {array} $query_args Query arguments
190 * @param {array} $args ES arguments
191 * @param {array} $query WP Query instance
192 * @return {array} New facets aggregations
193 */
194 $query_args = apply_filters( 'ep_facet_agg_filters', $query_args, $args, $query );
195
196 remove_filter( 'ep_post_formatted_args', [ $this, 'set_agg_filters' ], 10, 3 );
197 $facet_formatted_args = Indexables::factory()->get( 'post' )->format_args( $query_args, $query );
198 add_filter( 'ep_post_formatted_args', [ $this, 'set_agg_filters' ], 10, 3 );
199
200 remove_filter( 'ep_post_filters', [ $this, 'remove_facets_filter' ], 11 );
201
202 $args['aggs']['terms']['filter'] = $facet_formatted_args['post_filter'];
203
204 return $args;
205 }
206
207 /**
208 * Output scripts for widget admin
209 *
210 * @param string $hook WP hook
211 * @since 2.5
212 */
213 public function admin_scripts( $hook ) {
214 _doing_it_wrong(
215 __METHOD__,
216 esc_html__( 'Facets no longer require admin styles.', 'elasticpress' ),
217 '4.7.0'
218 );
219 }
220
221 /**
222 * Output front end facets styles
223 *
224 * @since 2.5
225 */
226 public function front_scripts() {
227 wp_register_script(
228 'elasticpress-facets',
229 EP_URL . 'dist/js/facets-script.js',
230 Utils\get_asset_info( 'facets-script', 'dependencies' ),
231 Utils\get_asset_info( 'facets-script', 'version' ),
232 true
233 );
234
235 wp_set_script_translations( 'elasticpress-facets', 'elasticpress' );
236
237 wp_register_style(
238 'elasticpress-facets',
239 EP_URL . 'dist/css/facets-styles.css',
240 Utils\get_asset_info( 'facets-styles', 'dependencies' ),
241 Utils\get_asset_info( 'facets-styles', 'version' )
242 );
243 }
244
245 /**
246 * Figure out if we can/should facet the query
247 *
248 * @param WP_Query $query WP Query
249 * @since 2.5
250 * @return bool
251 */
252 public function is_facetable( $query ) {
253
254 /**
255 * Bypass the standard checks and set a query to be facetable.
256 *
257 * @deprecated 5.3.0 Use the 'ep_is_facetable' argument in WP_Query instead.
258 *
259 * @hook ep_is_facetable
260 * @param {bool} $bypass Defaults to false.
261 * @param {WP_Query} $query The current WP_Query.
262 * @return {bool} true to bypass, false to ignore
263 */
264 if ( apply_filters_deprecated(
265 'ep_is_facetable',
266 [ false, $query ],
267 'ElasticPress 5.3.0',
268 'WP_Query->ep_is_facetable argument'
269 ) ) {
270 return true;
271 }
272
273 $ep_is_facetable = $query->get( 'ep_is_facetable', null );
274 if ( null !== $ep_is_facetable ) {
275 return (bool) $ep_is_facetable;
276 }
277
278 if ( is_admin() || is_feed() ) {
279 return false;
280 }
281
282 if ( defined( 'WP_CLI' ) && WP_CLI ) {
283 return false;
284 }
285
286 if ( ! $query->is_main_query() ) {
287 return false;
288 }
289
290 $ep_integrate = $query->get( 'ep_integrate', null );
291
292 if ( false === $ep_integrate ) {
293 return false;
294 }
295
296 $woocommerce = Features::factory()->get_registered_feature( 'woocommerce' );
297
298 if ( ! $woocommerce->is_active() && ( function_exists( 'is_product_category' ) && is_product_category() ) ) {
299 return false;
300 }
301
302 if ( ! $this->is_facetable_page( $query ) ) {
303 return false;
304 }
305
306 return true;
307 }
308
309 /**
310 * We enable ElasticPress facet on all archive/search queries as well as non-static home pages. There is no way to know
311 * when a facet widget is used before the main query is executed so we enable EP
312 * everywhere where a facet widget could be used.
313 *
314 * @param WP_Query $query WP Query
315 * @since 2.5
316 */
317 public function facet_query( $query ) {
318 if ( ! $this->is_facetable( $query ) ) {
319 return;
320 }
321
322 // If any filter was selected, there is no reason to prepend the list with sticky posts.
323 $selected_filters = $this->get_selected();
324 if ( ! empty( array_filter( $selected_filters ) ) ) {
325 $query->set( 'ignore_sticky_posts', true );
326 }
327
328 /**
329 * Filter facet aggregations.
330 *
331 * This is used by facet types to add their own aggregations to the
332 * general facet.
333 *
334 * @hook ep_facet_wp_query_aggs_facet
335 * @since 4.3.0
336 * @param {array} $facets Facets aggregations
337 * @return {array} New facets aggregations
338 */
339 $facets = apply_filters( 'ep_facet_wp_query_aggs_facet', [] );
340
341 if ( empty( $facets ) ) {
342 return;
343 }
344
345 $query->set( 'ep_integrate', true );
346 $query->set( 'ep_facet', true );
347
348 $aggs = array(
349 'name' => 'terms',
350 'use-filter' => true,
351 'aggs' => $facets,
352 );
353
354 $query->set( 'aggs', $aggs );
355 }
356
357 /**
358 * Get aggregations from Elasticsearch response and store on query object
359 *
360 * @param array $response ES response
361 * @param array $query Prepared Elasticsearch query
362 * @param array $query_args Current WP Query arguments
363 * @param mixed $query_object Could be WP_Query, WP_User_Query, etc.
364 * @since 2.5
365 */
366 public function get_aggs( $response, $query, $query_args, $query_object ) {
367 if ( empty( $query_object ) || ! $query_object instanceof \WP_Query || ! $this->is_facetable( $query_object ) ) {
368 return;
369 }
370
371 if ( ! empty( $response['aggregations'] ) ) {
372 $processed_aggs = [];
373
374 if ( isset( $response['aggregations']['terms'] ) && is_array( $response['aggregations']['terms'] ) ) {
375 foreach ( $response['aggregations']['terms'] as $key => $agg ) {
376 if ( 'doc_count' === $key ) {
377 continue;
378 }
379
380 if ( ! is_array( $agg ) || ( empty( $agg['buckets'] ) && empty( $agg['value'] ) ) ) {
381 continue;
382 }
383
384 $processed_aggs[ $key ] = [];
385
386 if ( ! empty( $agg['value'] ) ) {
387 $processed_aggs[ $key ] = $agg['value'];
388 continue;
389 }
390
391 foreach ( $agg['buckets'] as $bucket ) {
392 $processed_aggs[ $key ][ $bucket['key'] ] = $bucket['doc_count'];
393 }
394 }
395 }
396
397 $this->set_query_aggregations( $query_object, $processed_aggs );
398 }
399 }
400
401 /**
402 * Set aggregation data for a query.
403 *
404 * @since 5.3.0
405 * @param \WP_Query $query The WP_Query object to store data for
406 * @param array $aggregations The aggregation data to store
407 */
408 public function set_query_aggregations( $query, $aggregations ): void {
409 // Store aggregations on the query object
410 $query->ep_aggregations = $aggregations;
411
412 if ( $query->is_main_query() && $this->should_sync_to_global( $query ) ) {
413 _doing_it_wrong(
414 __METHOD__,
415 esc_html__( 'The global variable $GLOBALS[\'ep_facet_aggs\'] is deprecated. Access aggregation data directly from the query object using $query->ep_aggregations or the Facets feature methods get_query_aggregations() and get_facet_aggregation().', 'elasticpress' ),
416 'ElasticPress 5.3.0'
417 );
418
419 $GLOBALS['ep_facet_aggs'] = $aggregations;
420 }
421 }
422
423 /**
424 * Get aggregation data for a specific query
425 *
426 * @since 5.3.0
427 * @param \WP_Query $query The WP_Query object
428 * @return array|false Aggregation data or false if not found
429 */
430 public function get_query_aggregations( $query ) {
431 if ( $query instanceof \WP_Query && isset( $query->ep_aggregations ) && false !== $query->ep_aggregations ) {
432 return $query->ep_aggregations;
433 }
434 // Fallback to global variable
435 return $GLOBALS['ep_facet_aggs'] ?? false;
436 }
437
438 /**
439 * Get aggregation data for a specific facet within a query
440 *
441 * @since 5.3.0
442 * @param \WP_Query $query The WP_Query object
443 * @param string $facet_name The name of the facet to retrieve
444 * @return array|false Facet aggregation data or false if not found
445 */
446 public function get_facet_aggregation( $query, $facet_name ) {
447 $aggregations = $this->get_query_aggregations( $query );
448
449 if ( false === $aggregations || ! isset( $aggregations[ $facet_name ] ) ) {
450 return false;
451 }
452
453 return $aggregations[ $facet_name ];
454 }
455
456 /**
457 * Determine if aggregations should be synced to global variable
458 *
459 * @since 5.3.0
460 * @param \WP_Query $query The query to evaluate
461 * @return bool True if should sync to global, false otherwise
462 */
463 protected function should_sync_to_global( $query ) {
464 /**
465 * Filter whether to sync query aggregations to global variable
466 *
467 * @since 5.3.0
468 * @hook ep_facet_sync_aggregations_to_global
469 * @param {bool} $sync Whether to sync (default: false)
470 * @param {WP_Query} $query The query object
471 * @return {bool} Whether to sync aggregations to global variable
472 */
473 return apply_filters( 'ep_facet_sync_aggregations_to_global', false, $query );
474 }
475
476 /**
477 * Get currently selected facets from query args
478 *
479 * @since 2.5
480 * @return array
481 */
482 public function get_selected() {
483 $allowed_args = $this->get_allowed_query_args();
484
485 $filters = [];
486 $filter_names = [];
487 foreach ( $this->types as $type_obj ) {
488 $filter_names[ $type_obj->get_filter_name() ] = $type_obj;
489 }
490
491 foreach ( $_GET as $key => $value ) { // phpcs:ignore WordPress.Security.NonceVerification
492 $key = sanitize_key( $key );
493
494 foreach ( $filter_names as $filter_name => $type_obj ) {
495 if ( 0 === strpos( $key, $filter_name ) ) {
496 if ( empty( $value ) ) {
497 continue;
498 }
499 $facet = str_replace( $filter_name, '', $key );
500
501 $filters = $type_obj->format_selected( $facet, $value, $filters );
502 }
503 }
504
505 if ( in_array( $key, $allowed_args, true ) ) {
506 $filters[ $key ] = $value;
507 }
508 }
509
510 /**
511 * Filter selected filters.
512 *
513 * @hook ep_facet_selected_filters
514 * @since 5.1.4
515 * @param {array} $filters Current filters
516 * @return {array} New filters
517 */
518 return apply_filters( 'ep_facet_selected_filters', $filters );
519 }
520
521 /**
522 * Build query url
523 *
524 * @since 2.5
525 * @param array $filters Facet filters
526 * @return string
527 */
528 public function build_query_url( $filters ) {
529 $query_params = array();
530
531 foreach ( $this->types as $type_obj ) {
532 if ( empty( $filters[ $type_obj->get_filter_type() ] ) ) {
533 continue;
534 }
535 $query_params = $type_obj->add_query_params( $query_params, $filters );
536 }
537
538 $feature = Features::factory()->get_registered_feature( 'facets' );
539 $allowed_args = $feature->get_allowed_query_args();
540
541 if ( ! empty( $filters ) ) {
542 foreach ( $filters as $filter => $value ) {
543 if ( in_array( $filter, $allowed_args, true ) ) {
544 $query_params[ $filter ] = $value;
545 }
546 }
547 }
548
549 $query_string = build_query( $query_params );
550
551 /**
552 * Filter facet query string
553 *
554 * @hook ep_facet_query_string
555 * @param {string} $query_string Current query string
556 * @param {array} $query_params Query parameters
557 * @return {string} New query string
558 */
559 $query_string = apply_filters( 'ep_facet_query_string', $query_string, $query_params );
560
561 $url = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
562 $pagination = strpos( $url, '/page' );
563 if ( false !== $pagination ) {
564 $url = substr( $url, 0, $pagination );
565 }
566
567 return strtok( trailingslashit( $url ), '?' ) . ( ( ! empty( $query_string ) ) ? '?' . $query_string : '' );
568 }
569
570 /**
571 * Register facet widget(s)
572 *
573 * @since 2.5, deprecated in 4.3.0
574 */
575 public function register_widgets() {
576 _deprecated_function( __METHOD__, '4.3.0', "\ElasticPress\Features::factory()->get_registered_feature( 'facets' )->types[ \$type ]->register_widgets()" );
577 }
578
579 /**
580 * Hide the legacy widget.
581 *
582 * Hides the legacy widget in favor of the Block when the block editor
583 * is in use and the legacy widget has not been used.
584 *
585 * @since 4.3
586 * @param array $widgets An array of excluded widget-type IDs.
587 * @return array array of excluded widget-type IDs to hide.
588 */
589 public function hide_legacy_widget( $widgets ) {
590 $widgets[] = 'ep-facet';
591 $widgets[] = 'ep-facet-date';
592 $widgets[] = 'ep-facet-meta';
593 $widgets[] = 'ep-facet-meta-range';
594
595 return $widgets;
596 }
597
598 /**
599 * Returns allowed query args for facets
600 *
601 * @return mixed|void
602 * @since 3.6.0
603 */
604 public function get_allowed_query_args() {
605 $args = array( 's', 'post_type', 'orderby' );
606
607 // Retrieve all registered query variables for public taxonomies
608 $taxonomies = get_taxonomies( [ 'public' => true ], 'objects' );
609 foreach ( $taxonomies as $taxonomy ) {
610 if ( $taxonomy->query_var ) {
611 $args[] = $taxonomy->query_var;
612 }
613 }
614 /**
615 * To keep backward compatibility, WordPress uses `'cat'` for default categories.
616 * It also allows access using the `?taxonomy=<tax>&term=<term>` format.
617 *
618 * @see get_term_link()
619 */
620 $args = array_merge( $args, [ 'cat', 'taxonomy', 'term' ] );
621
622 /**
623 * Filter allowed query args
624 *
625 * @hook ep_facet_allowed_query_args
626 * @since 3.6.0
627 * @param {array} $args Post types
628 * @return {array} New post types
629 */
630 return apply_filters( 'ep_facet_allowed_query_args', $args );
631 }
632
633 /**
634 * Get the facet filter name.
635 *
636 * @return string The filter name.
637 */
638 protected function get_filter_name() {
639 _deprecated_function( __METHOD__, '4.3.0', "\ElasticPress\Features::factory()->get_registered_feature( 'facets' )->types['taxonomy']->get_filter_name()" );
640
641 return $this->types['taxonomy']->get_filter_name();
642 }
643
644 /**
645 * Get all taxonomies that could be selected for a facet.
646 *
647 * @since 4.2.0, deprecated in 4.3.0
648 * @return array
649 */
650 public function get_facetable_taxonomies() {
651 _deprecated_function( __METHOD__, '4.3.0', "\ElasticPress\Features::factory()->get_registered_feature( 'facets' )->types['taxonomy']->get_facetable_taxonomies()" );
652
653 return $this->types['taxonomy']->get_filter_name();
654 }
655
656 /**
657 * Add a new filter to the ES query with selected facets
658 *
659 * @since 4.4.0
660 * @param array $filters Current filters
661 * @param array $args WP Query args
662 * @param WP_Query $query WP Query object
663 * @return array
664 */
665 public function apply_facets_filters( $filters, $args, $query ) {
666 if ( ! $this->is_facetable( $query ) ) {
667 return $filters;
668 }
669
670 /**
671 * Filter facet selection filters to be applied to the ES query
672 *
673 * @hook ep_facet_query_filters
674 * @since 4.4.0
675 * @param {array} $filters Current filters
676 * @param {array} $args WP Query args
677 * @param {WP_Query} $query WP Query object
678 * @return {array} New filters
679 */
680 $facets_filters = apply_filters( 'ep_facet_query_filters', [], $args, $query );
681
682 if ( empty( $facets_filters ) ) {
683 return $filters;
684 }
685
686 $es_operator = ( 'any' === $this->get_match_type() ) ? 'should' : 'must';
687
688 $filters['facets'] = [
689 'bool' => [
690 $es_operator => $facets_filters,
691 ],
692 ];
693
694 return $filters;
695 }
696
697 /**
698 * Utility function to retrieve the match type selected by the user.
699 *
700 * @since 4.4.0
701 * @return string
702 */
703 public function get_match_type() {
704 $settings = $this->get_settings();
705
706 /**
707 * Filter the match type of all facets. Can be 'all' or 'any'.
708 *
709 * @hook ep_facet_match_type
710 * @since 4.4.0
711 * @param {string} $match_type Current selection
712 * @return {string} New selection
713 */
714 return apply_filters( 'ep_facet_match_type', $settings['match_type'] );
715 }
716
717 /**
718 * Given an array of filters, remove the facets filter.
719 *
720 * This is used when the user wants posts matching ANY criteria, so aggregations should not restrict their results.
721 *
722 * @since 4.4.0
723 * @param array $filters Filters to be applied to the ES query
724 * @return array
725 */
726 public function remove_facets_filter( $filters ) {
727 unset( $filters['facets'] );
728 return $filters;
729 }
730
731 /**
732 * Set the `settings_schema` attribute
733 *
734 * @since 5.0.0
735 */
736 protected function set_settings_schema() {
737 $this->settings_schema[] = [
738 'key' => 'match_type',
739 'label' => __( 'Filter matching', 'elasticpress' ),
740 'options' => [
741 [
742 'label' => __( 'Show results that match <strong>all</strong> selected filters', 'elasticpress' ),
743 'value' => 'all',
744 ],
745 [
746 'label' => __( 'Show results that match <strong>any</strong> selected filter', 'elasticpress' ),
747 'value' => 'any',
748 ],
749 ],
750 'type' => 'radio',
751 ];
752 }
753
754 /**
755 * Figure out if Facet widget can display on page.
756 *
757 * @param WP_Query $query WP Query
758 * @since 4.2.1
759 * @return bool
760 */
761 protected function is_facetable_page( $query ) {
762 return $query->is_home() || $query->is_search() || $query->is_tax() || $query->is_tag() || $query->is_category() || $query->is_post_type_archive();
763 }
764
765 /**
766 * Setup REST endpoints
767 *
768 * @since 5.0.0
769 */
770 public function setup_endpoints() {
771 $meta_keys = new REST\MetaKeys();
772 $meta_keys->register_routes();
773
774 $meta_range = new REST\MetaRange();
775 $meta_range->register_routes();
776
777 $taxonomies = new REST\Taxonomies();
778 $taxonomies->register_routes();
779 }
780 }
781