PluginProbe
ElasticPress / 4.4.1
ElasticPress v4.4.1
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 / Search / Weighting.php

Weighting.php in ElasticPress 4.4.1, at includes/classes/Feature/Search/Weighting.php

730 lines 23.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Weighting dashboard for ElasticPress
4 *
5 * @package elasticpress
6 */
7
8 namespace ElasticPress\Feature\Search;
9
10 use ElasticPress\Features;
11 use ElasticPress\Indexable\Post\Post;
12 use ElasticPress\Utils as Utils;
13
14 /**
15 * Controls search weighting and search fields dashboard
16 *
17 * @package ElasticPress\Feature\Search
18 */
19 class Weighting {
20
21 /**
22 * Sets up the weighting module
23 */
24 public function setup() {
25 /**
26 * Filter to disable loading of Search weighting engine.
27 *
28 * @hook ep_disable_search_weighting
29 * @since 4.0
30 * @param bool Whether to disable search weighting engine. Defaults to false.
31 * @return bool Whether to disable search weighting engine.
32 */
33 if ( apply_filters( 'ep_disable_search_weighting', false ) ) {
34 return;
35 }
36
37 add_action( 'admin_menu', [ $this, 'add_weighting_submenu_page' ], 15 );
38 add_action( 'admin_post_ep-weighting', [ $this, 'handle_save' ] );
39 add_filter( 'ep_formatted_args', [ $this, 'do_weighting' ], 20, 2 ); // After date decay, etc are injected
40 add_filter( 'ep_query_weighting_fields', [ $this, 'adjust_weight_for_cross_fields' ], 10, 5 );
41 }
42
43 /**
44 * Returns a grouping of all the fields that support weighting for the post type
45 *
46 * @param string $post_type Post type
47 *
48 * @return array
49 */
50 public function get_weightable_fields_for_post_type( $post_type ) {
51 $fields = array(
52 'attributes' => array(
53 'label' => __( 'Attributes', 'elasticpress' ),
54 'children' => array(
55 'post_title' => array(
56 'key' => 'post_title',
57 'label' => 'Title',
58 ),
59 'post_content' => array(
60 'key' => 'post_content',
61 'label' => 'Content',
62 ),
63 'post_excerpt' => array(
64 'key' => 'post_excerpt',
65 'label' => 'Excerpt',
66 ),
67 'author_name' => array(
68 'key' => 'author_name',
69 'label' => 'Author',
70 ),
71 ),
72 ),
73 );
74
75 $public_taxonomies = get_taxonomies(
76 [
77 'public' => true,
78 ]
79 );
80
81 $post_type_taxonomies = get_object_taxonomies( $post_type );
82
83 $taxonomies = array_intersect( $public_taxonomies, $post_type_taxonomies );
84
85 if ( $taxonomies ) {
86 $fields['taxonomies'] = [
87 'label' => __( 'Taxonomies', 'elasticpress' ),
88 'children' => [],
89 ];
90
91 foreach ( $taxonomies as $taxonomy ) {
92 $key = "terms.{$taxonomy}.name";
93 $taxonomy_object = get_taxonomy( $taxonomy );
94
95 $fields['taxonomies']['children'][ $key ] = [
96 'key' => $key,
97 'label' => $taxonomy_object->labels->name,
98 ];
99 }
100 }
101
102 /**
103 * Filter weighting fields for a post type
104 *
105 * @hook ep_weighting_fields_for_post_type
106 * @param {array} $fields Current weighting fields
107 * @param {string} $post_type Current post type
108 * @return {array} New fields
109 */
110 return apply_filters( 'ep_weighting_fields_for_post_type', $fields, $post_type );
111 }
112
113 /**
114 * Returns default settings for any post type
115 *
116 * Defaults to title, content, excerpt, and author name enabled with zero weight
117 *
118 * @param string $post_type Post Type we need settings for
119 *
120 * @return array Defaults for post type
121 */
122 public function get_post_type_default_settings( $post_type ) {
123 $post_type_defaults = [
124 'post_title' => [
125 'enabled' => true,
126 'weight' => 1,
127 ],
128 'post_content' => [
129 'enabled' => true,
130 'weight' => 1,
131 ],
132 'post_excerpt' => [
133 'enabled' => true,
134 'weight' => 1,
135 ],
136 'author_name' => [
137 'enabled' => true,
138 'weight' => 1,
139 ],
140 ];
141
142 $post_type_taxonomies = get_object_taxonomies( $post_type );
143
144 /**
145 * Filter install status
146 *
147 * Previous behavior had post_tag and category enabled by default, so if this is supported on the post type
148 * we add them as enabled by default
149 *
150 * @hook ep_weighting_default_enabled_taxonomies
151 * @param {array} $enabled_taxonomies Taxonomies that should be enabled by default
152 * @param {string} $post_type Post type slug
153 * @return {array} New taxonomies
154 * @since 3.6.5
155 */
156 $enabled_by_default = apply_filters( 'ep_weighting_default_enabled_taxonomies', [ 'post_tag', 'category' ], $post_type );
157
158 foreach ( $enabled_by_default as $default_tax ) {
159 if ( in_array( $default_tax, $post_type_taxonomies, true ) ) {
160 $post_type_defaults[ 'terms.' . $default_tax . '.name' ] = [
161 'enabled' => true,
162 'weight' => 1,
163 ];
164 }
165 }
166
167 /**
168 * Filter weighting defaults for post type
169 *
170 * @hook ep_weighting_default_post_type_weights
171 * @param {array} $post_type_defaults Current weighting defaults
172 * @param {string} $post_type Current post type
173 * @return {array} New defaults
174 */
175 return apply_filters( 'ep_weighting_default_post_type_weights', $post_type_defaults, $post_type );
176 }
177
178 /**
179 * Returns the current weighting configuration
180 *
181 * @return array
182 */
183 public function get_weighting_configuration() {
184 /**
185 * Filter weighting configuration
186 *
187 * @hook ep_weighting_configuration
188 * @param {array} $config Current configuration
189 * @return {array} New configuration
190 */
191 return apply_filters( 'ep_weighting_configuration', get_option( 'elasticpress_weighting', [] ) );
192 }
193
194 /**
195 * Adds the submenu page for controlling weighting
196 */
197 public function add_weighting_submenu_page() {
198 add_submenu_page(
199 'elasticpress',
200 esc_html__( 'ElasticPress Search Fields & Weighting', 'elasticpress' ),
201 esc_html__( 'Search Fields & Weighting', 'elasticpress' ),
202 'manage_options',
203 'elasticpress-weighting',
204 [ $this, 'render_settings_page' ]
205 );
206 }
207
208 /**
209 * Renders the settings page that controls weighting
210 */
211 public function render_settings_page() {
212 include EP_PATH . '/includes/partials/header.php'; ?>
213 <div class="wrap">
214
215 <h1><?php esc_html_e( 'Manage Search Fields & Weighting', 'elasticpress' ); ?></h1>
216 <p><?php esc_html_e( 'Adding more weight to an item will mean it will have more presence during searches. Add more weight to the items that are more important and need more prominence during searches.', 'elasticpress' ); ?></p>
217 <p><?php esc_html_e( 'For example, adding more weight to the title attribute will cause search matches on the post title to appear more prominently.', 'elasticpress' ); ?></p>
218
219 <form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post" class="weighting-settings metabox-holder">
220 <input type="hidden" name="action" value="ep-weighting">
221 <?php wp_nonce_field( 'save-weighting', 'ep-weighting-nonce' ); ?>
222 <?php
223 if ( isset( $_GET['settings-updated'] ) ) : // phpcs:ignore WordPress.Security.NonceVerification
224 if ( $_GET['settings-updated'] ) : // phpcs:ignore WordPress.Security.NonceVerification
225 ?>
226 <div class="notice notice-success is-dismissible">
227 <p><?php esc_html_e( 'Changes Saved!', 'elasticpress' ); ?></p>
228 </div>
229 <?php else : ?>
230 <div class="notice notice-error is-dismissible">
231 <p><?php esc_html_e( 'An error occurred when saving!', 'elasticpress' ); ?></p>
232 </div>
233 <?php
234 endif;
235 endif;
236
237 /** Features Class @var Features $features */
238 $features = Features::factory();
239
240 /** Search Feature @var Feature\Search\Search $search */
241 $search = $features->get_registered_feature( 'search' );
242
243 $post_types = $search->get_searchable_post_types();
244
245 $current_values = $this->get_weighting_configuration();
246
247 foreach ( $post_types as $post_type ) :
248 $fields = $this->get_weightable_fields_for_post_type( $post_type );
249 $post_type_object = get_post_type_object( $post_type );
250 ?>
251 <div class="postbox">
252 <h2 class="hndle"><?php echo esc_html( $post_type_object->labels->menu_name ); ?></h2>
253
254 <?php
255 foreach ( $fields as $field_group ) :
256 $this->render_settings_section( $post_type, $field_group, $current_values );
257 endforeach;
258 ?>
259 </div>
260 <?php
261 endforeach;
262
263 submit_button();
264 ?>
265 </form>
266 </div>
267 <?php
268 }
269
270 /**
271 * Recursively renders each settings section and its children
272 *
273 * @param string $post_type Current post type we're rendering
274 * @param array $field Current field to render
275 * @param array $current_values Current stored weighting values
276 */
277 public function render_settings_section( $post_type, $field, $current_values ) {
278 if ( isset( $field['children'] ) && ! empty( $field['children'] ) ) :
279 ?>
280 <div class="field-group">
281 <h3><?php echo esc_html( $field['label'] ); ?></h3>
282 <div class="fields">
283 <?php
284 foreach ( $field['children'] as $child ) {
285 $this->render_settings_section( $post_type, $child, $current_values );
286 }
287 ?>
288 </div>
289 </div>
290 <?php
291 elseif ( isset( $field['key'] ) ) :
292 $key = $field['key'];
293
294 $post_type_settings = isset( $current_values[ $post_type ] ) ? $current_values[ $post_type ] : $this->get_post_type_default_settings( $post_type );
295
296 $weight = isset( $post_type_settings[ $key ] ) && isset( $post_type_settings[ $key ]['weight'] ) ? (int) $post_type_settings[ $key ]['weight'] : 0;
297
298 $range_disabled = '';
299
300 $enabled = (
301 isset( $post_type_settings ) &&
302 isset( $post_type_settings[ $key ] ) &&
303 isset( $post_type_settings[ $key ]['enabled'] )
304 )
305 ? boolval( $post_type_settings[ $key ]['enabled'] ) : false;
306
307 if ( ! $enabled ) {
308 $range_disabled = 'disabled="disabled" ';
309 $weight = 0;
310 }
311 ?>
312 <fieldset>
313 <legend><?php echo esc_html( $field['label'] ); ?></legend>
314
315 <p class="searchable">
316 <input type="checkbox" value="on" <?php checked( $enabled ); ?> id="<?php echo esc_attr( "{$post_type}-{$key}-enabled" ); ?>" name="weighting[<?php echo esc_attr( $post_type ); ?>][<?php echo esc_attr( $key ); ?>][enabled]">
317 <label for="<?php echo esc_attr( "{$post_type}-{$key}-enabled" ); ?>"><?php esc_html_e( 'Searchable', 'elasticpress' ); ?></label>
318 </p>
319
320 <p class="weighting">
321 <label for="<?php echo esc_attr( "{$post_type}-{$key}-weight" ); ?>">
322 <?php esc_html_e( 'Weight: ', 'elasticpress' ); ?>
323 <span class="weighting-value">
324 <?php echo esc_html( $weight ); ?>
325 </span>
326 </label>
327 <input type="range" min="1" max="100" step="1" value="<?php echo esc_attr( $weight ); ?>" id="<?php echo esc_attr( "{$post_type}-{$key}-weight" ); ?>" name="weighting[<?php echo esc_attr( $post_type ); ?>][<?php echo esc_attr( $key ); ?>][weight]" <?php echo $range_disabled; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
328 </p>
329 </fieldset>
330 <?php
331 endif;
332 }
333
334 /**
335 * Handles processing the new weighting values and saving them to the elasticpress.io service
336 */
337 public function handle_save() {
338 if ( ! isset( $_POST['ep-weighting-nonce'] ) || ! wp_verify_nonce( $_POST['ep-weighting-nonce'], 'save-weighting' ) ) {
339 return;
340 }
341
342 if ( ! current_user_can( 'manage_options' ) ) {
343 return;
344 }
345
346 $this->save_weighting_configuration( $_POST );
347
348 $redirect_url = admin_url( 'admin.php?page=elasticpress-weighting' );
349 $redirect_url = add_query_arg( 'settings-updated', true, $redirect_url );
350
351 $this->redirect( $redirect_url );
352 }
353
354 /**
355 * We need this method to test handle_save properly.
356 *
357 * @param string $redirect_url Redirect URL.
358 */
359 protected function redirect( $redirect_url ) {
360 // @codeCoverageIgnoreStart
361 wp_safe_redirect( $redirect_url );
362 exit();
363 // @codeCoverageIgnoreEnd
364 }
365
366 /**
367 * Save weighting configuration for each searchable post_type
368 *
369 * @param array $settings weighting settings
370 *
371 * @return array final settings
372 * @since 3.4.1
373 */
374 public function save_weighting_configuration( $settings ) {
375 $new_config = array();
376 $previous_config_formatted = array();
377 $current_config = $this->get_weighting_configuration();
378
379 foreach ( $current_config as $post_type => $post_type_weighting ) {
380 // This also ensures the string is safe, since this would return false otherwise
381 if ( ! post_type_exists( $post_type ) ) {
382 continue;
383 }
384
385 // We need a way to know if fields have been explicitly set before, let's compare a previous state against $_POST['weighting']
386 foreach ( $post_type_weighting as $weighting_field => $weighting_values ) {
387 $previous_config_formatted[ $post_type ][ sanitize_text_field( $weighting_field ) ] = [
388 'weight' => isset( $settings['weighting'][ $post_type ][ $weighting_field ]['weight'] ) ? intval( $settings['weighting'][ $post_type ][ $weighting_field ]['weight'] ) : 0,
389 'enabled' => isset( $settings['weighting'][ $post_type ][ $weighting_field ]['enabled'] ) && 'on' === $settings['weighting'][ $post_type ][ $weighting_field ]['enabled'] ? true : false,
390 ];
391 }
392 }
393
394 $search = Features::factory()->get_registered_feature( 'search' );
395 $post_types = $search->get_searchable_post_types();
396
397 foreach ( $post_types as $post_type ) {
398 // This also ensures the string is safe, since this would return false otherwise
399 if ( ! post_type_exists( $post_type ) ) {
400 continue;
401 }
402
403 /** override default post_type settings while saving */
404 $new_config[ $post_type ] = array();
405
406 if ( isset( $settings['weighting'][ $post_type ] ) ) {
407 foreach ( $settings['weighting'][ $post_type ] as $weighting_field => $weighting_values ) {
408 $new_config[ $post_type ][ sanitize_text_field( $weighting_field ) ] = [
409 'weight' => isset( $weighting_values['weight'] ) ? intval( $weighting_values['weight'] ) : 0,
410 'enabled' => isset( $weighting_values['enabled'] ) && 'on' === $weighting_values['enabled'] ? true : false,
411 ];
412 }
413 }
414 }
415
416 $final_config = array_replace_recursive( $previous_config_formatted, $new_config );
417
418 update_option( 'elasticpress_weighting', $final_config );
419
420 /**
421 * Fires right after the weighting configuration is saved.
422 *
423 * @since 3.5.x
424 * @hook ep_saved_weighting_configuration
425 */
426 do_action( 'ep_saved_weighting_configuration' );
427
428 return $final_config;
429 }
430
431 /**
432 * Iterates through arrays in the formatted args to find "fields" and injects weighting values
433 *
434 * @param array $fieldset Current subset of formatted ES args
435 * @param array $weights Weight configuration
436 */
437 public function recursively_inject_weights_to_fields( &$fieldset, $weights ) {
438 if ( ! is_array( $fieldset ) ) {
439 return;
440 }
441
442 if ( is_array( $fieldset ) && isset( $fieldset['fields'] ) ) {
443 // Add any fields to the search that aren't already in there (weighting handled in next step)
444 foreach ( $weights as $field => $settings ) {
445 if ( ! in_array( $field, $fieldset['fields'], true ) ) {
446 $fieldset['fields'][] = $field;
447 }
448 }
449
450 foreach ( $fieldset['fields'] as $key => $field ) {
451 if ( isset( $weights[ $field ] ) && false !== $weights[ $field ]['enabled'] ) {
452 $weight = (int) $weights[ $field ]['weight'];
453
454 if ( 0 !== $weight ) {
455 if ( 'author_name' === $field ) {
456 $field = 'post_author.display_name';
457 }
458
459 /**
460 * Filter fields and their weitghting as used in the Elasticsearch query.
461 *
462 * @hook ep_query_weighting_fields
463 * @param {string} $weighted_field The field and its weight as used in the ES query.
464 * @param {string} $field Field name
465 * @param {string} $weight Weight value
466 * @param {array} $fieldset Current subset of formatted ES args
467 * @param {array} $weights Weight configuration
468 * @return {array} New weighted field string
469 *
470 * @since 3.5.5
471 */
472 $fieldset['fields'][ $key ] = apply_filters(
473 'ep_query_weighting_fields',
474 "{$field}^{$weight}",
475 $field,
476 $weight,
477 $fieldset,
478 $weights
479 );
480 }
481 } else {
482 // this handles removing post_author.login field added in Post::format_args() if author search field has being disabled
483 if ( 'author_name' === $field ) {
484 $author_key = array_search( 'post_author.login', $fieldset['fields'], true );
485 if ( false !== $author_key ) {
486 unset( $fieldset['fields'][ $author_key ] );
487 }
488 }
489 unset( $fieldset['fields'][ $key ] );
490 }
491 // else: Leave anything that isn't explicitly disabled alone. Could have been added by search_fields, and if it is not present in the UI, we shouldn't touch it here
492
493 // If fieldset has fuzziness enabled and fuzziness is disabled for this field, unset the field
494 if ( isset( $fieldset['fuzziness'] ) && $fieldset['fuzziness'] && isset( $weights[ $field ]['fuzziness'] ) && false === $weights[ $field ]['fuzziness'] ) {
495 unset( $fieldset['fields'][ $key ] );
496 }
497 }
498
499 // Reindex the array
500 $fieldset['fields'] = array_values( $fieldset['fields'] );
501 } else {
502 foreach ( $fieldset as &$field ) {
503 $this->recursively_inject_weights_to_fields( $field, $weights );
504 }
505 }
506
507 // Most likely to occur with the ordering results not being allowed in fuzzy, and weighting turning off fields for this otherwise
508 if ( isset( $fieldset['fields'] ) && empty( $fieldset['fields'] ) ) {
509 $fieldset = null;
510 }
511 }
512
513 /**
514 * Determine if a post type has any fields enabled for search
515 *
516 * @param string $post_type Post Type
517 * @param array $args WP_Query args
518 * @return boolean true/false depending on any fields enabled == true
519 */
520 public function post_type_has_fields( $post_type, $args = [] ) {
521 // define keys which are irrelevant for this consideration
522
523 /**
524 * Filter fields considered in weighting
525 *
526 * @hook ep_weighting_ignore_fields_in_consideration
527 * @param {array} $fields Current fields
528 * @return {array} New fields
529 */
530 $ignore_keys = apply_filters( 'ep_weighting_ignore_fields_in_consideration', [ 'terms.ep_custom_result.name' => true ] );
531 $weight_config = $this->get_weighting_configuration();
532
533 /**
534 * Filter weighting configuration for search
535 *
536 * @hook ep_weighting_configuration_for_search
537 * @param {array} $weight_config Current weight config
538 * @param {array} $args WP Query arguments
539 * @return {array} New configutation
540 */
541 $weight_config = apply_filters( 'ep_weighting_configuration_for_search', $weight_config, $args );
542
543 if ( ! isset( $weight_config[ $post_type ] ) ) {
544 $weights = $this->get_post_type_default_settings( $post_type );
545 } else {
546 $weights = $weight_config[ $post_type ];
547 }
548
549 $fields = array_diff_key( $weights, $ignore_keys );
550
551 $found_enabled = false;
552 foreach ( $fields as $field ) {
553 if ( filter_var( $field['enabled'], FILTER_VALIDATE_BOOLEAN ) ) {
554 $found_enabled = true;
555 break;
556 }
557 }
558
559 return $found_enabled;
560 }
561
562 /**
563 * Adjusts the query for configured weighting values
564 *
565 * @param array $formatted_args Formatted ES args
566 * @param array $args WP_Query args
567 *
568 * @return array Formatted ES args
569 */
570 public function do_weighting( $formatted_args, $args ) {
571
572 /**
573 * If search fields is set on the query, we should use those instead of the weighting, since the query was
574 * overridden by some custom code
575 */
576 if ( isset( $args['search_fields'] ) && ! empty( $args['search_fields'] ) ) {
577 return $formatted_args;
578 }
579
580 $weight_config = $this->get_weighting_configuration();
581
582 /**
583 * Filter weighting configuration for search
584 *
585 * @hook ep_weighting_configuration_for_search
586 * @param {array} $weight_config Current weight config
587 * @param {array} $args WP Query arguments
588 * @return {array} New configuration
589 */
590 $weight_config = apply_filters( 'ep_weighting_configuration_for_search', $weight_config, $args );
591
592 $should_do_weighting = Utils\is_integrated_request( 'weighting', [ 'public', 'rest' ] ) && ! empty( $args['s'] );
593
594 /**
595 * Filter whether to enable weighting configuration
596 *
597 * @hook ep_enable_do_weighting
598 * @since 4.2.2
599 * @param {bool} Whether to enable weight config, defaults to true for search requests that are public or REST
600 * @param {array} $weight_config Current weight config
601 * @param {array} $args WP Query arguments
602 * @param {array} $formatted_args Formatted ES arguments
603 * @return {bool} Whether to use weighting configuration
604 */
605 if ( apply_filters( 'ep_enable_do_weighting', $should_do_weighting, $weight_config, $args, $formatted_args ) ) {
606 $formatted_args = $this->apply_weighting( $formatted_args, $args, $weight_config );
607 }
608
609 return $formatted_args;
610 }
611
612 /**
613 * Applies weighting based on ES args
614 *
615 * @since 4.2.2
616 * @param array $formatted_args Formatted ES args
617 * @param array $args WP_Query args
618 * @param array $weight_config Weight configuration to apply
619 *
620 * @return array $formatted_args Formatted ES args with weightings applied
621 */
622 protected function apply_weighting( $formatted_args, $args, $weight_config ) {
623 /*
624 * This section splits up the single query clause for all post types into separate nested clauses (one for each post type)
625 * which then get combined into one result set. By having separate clauses for each post type, we can then
626 * weight fields such as post_title per post type so that we can have fine grained control over weights by post
627 * type, rather than globally on the query
628 */
629 $new_query = [
630 'bool' => [
631 'should' => [],
632 ],
633 ];
634
635 // grab the query and keep track of whether or not it is nested in a function score
636 $function_score = isset( $formatted_args['query']['function_score'] );
637 $query = $function_score ? $formatted_args['query']['function_score']['query'] : $formatted_args['query'];
638
639 foreach ( (array) $args['post_type'] as $post_type ) {
640 if ( false === $this->post_type_has_fields( $post_type, $args ) ) {
641 continue;
642 }
643 // Copy the query, so we can set specific weight values
644 $current_query = $query;
645
646 if ( isset( $weight_config[ $post_type ] ) ) {
647 // Find all "fields" values and inject weights for the current post type
648 $this->recursively_inject_weights_to_fields( $current_query, $weight_config[ $post_type ] );
649 } else {
650 // Use the default values for the post type
651 $this->recursively_inject_weights_to_fields( $current_query, $this->get_post_type_default_settings( $post_type ) );
652 }
653
654 // Check for any segments with null fields from recursively_inject function and remove them
655 if ( isset( $current_query['bool'] ) && isset( $current_query['bool']['should'] ) ) {
656 foreach ( $current_query['bool']['should'] as $index => $current_bool_should ) {
657 if ( isset( $current_bool_should['multi_match'] ) && null === $current_bool_should['multi_match'] ) {
658 unset( $current_query['bool']['should'][ $index ] );
659 }
660 }
661 }
662
663 /**
664 * Filter weighting query for a post type
665 *
666 * @hook ep_weighted_query_for_post_type
667 * @param {array} $query Weighting query
668 * @param {string} $post_type Post type
669 * @param {array} $args WP Query arguments
670 * @return {array} New query
671 */
672 $new_query['bool']['should'][] = apply_filters(
673 'ep_weighted_query_for_post_type',
674 [
675 'bool' => [
676 'must' => [
677 $current_query,
678 ],
679 'filter' => [
680 [
681 'match' => [
682 'post_type.raw' => $post_type,
683 ],
684 ],
685 ],
686 ],
687 ],
688 $post_type,
689 $args
690 );
691 }
692
693 // put the new query back in the correct location
694 if ( $function_score ) {
695 $formatted_args['query']['function_score']['query'] = $new_query;
696 } else {
697 $formatted_args['query'] = $new_query;
698 }
699
700 /**
701 * Hook after weighting is added to Elasticsearch query
702 *
703 * @hook ep_weighting_added
704 * @param {array} $formatted_args Elasticsearch query
705 * @param {array} $args WP Query arguments
706 */
707 do_action( 'ep_weighting_added', $formatted_args, $args );
708
709 return $formatted_args;
710 }
711
712 /**
713 * Adjust weighting when the type is cross_fields, as it just works with weight = 1.
714 *
715 * @since 4.0.0
716 *
717 * @param string $weighted_field The field and its weight as used in the ES query.
718 * @param string $field Field name
719 * @param string $weight Weight value
720 * @param array $fieldset Current subset of formatted ES args
721 * @return array New weighted field string
722 */
723 public function adjust_weight_for_cross_fields( $weighted_field, $field, $weight, $fieldset ) {
724 if ( ! empty( $fieldset['type'] ) && 'cross_fields' === $fieldset['type'] ) {
725 $weighted_field = "{$field}^1";
726 }
727 return $weighted_field;
728 }
729 }
730