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/Search/Search.php +454 -225 4.2.05.3.5 View file →
@@ -7,11 +7,12 @@
7 7 */
8 8
9 9 namespace ElasticPress\Feature\Search;
10 10
11 -use ElasticPress\Feature as Feature;
12 -use ElasticPress\Indexables as Indexables;
13 -use ElasticPress\Utils as Utils;
11 +use ElasticPress\Feature;
12 +use ElasticPress\Features;
13 +use ElasticPress\Indexables;
14 +use ElasticPress\Utils;
14 15
15 16 /**
16 17 * Search feature class
17 18 */
@@ -50,14 +51,10 @@
50 51 */
51 52 public function __construct() {
52 53 $this->slug = 'search';
53 54
54 - $this->title = esc_html__( 'Post Search', 'elasticpress' );
55 + $this->group = 'core-search';
55 56
56 - $this->summary = __( 'Instantly find the content you’re looking for. The first time.', 'elasticpress' );
57 -
58 - $this->docs_url = __( 'https://elasticpress.zendesk.com/hc/en-us/articles/360050447492-Configuring-ElasticPress-via-the-Plugin-Dashboard#post-search', 'elasticpress' );
59 -
60 57 $this->requires_install_reindex = false;
61 58
62 59 $this->default_settings = [
63 60 'decaying_enabled' => '1',
@@ -72,8 +69,29 @@
72 69 parent::__construct();
73 70 }
74 71
75 72 /**
73 + * Sets i18n strings.
74 + *
75 + * @return void
76 + * @since 5.2.0
77 + */
78 + public function set_i18n_strings(): void {
79 + $this->title = esc_html__( 'Post Search', 'elasticpress' );
80 +
81 + $this->summary = '<p>' . __( 'Instantly find the content you’re looking for. The first time.', 'elasticpress' ) . '</p>' .
82 + '<p>' . __( 'Overcome higher-end performance and functional limits posed by the traditional WordPress structured (SQL) database to deliver superior keyword search, instantly. ElasticPress indexes custom fields, tags, and other metadata to improve search results. Fuzzy matching accounts for misspellings and verb tenses.', 'elasticpress' ) . '</p>';
83 +
84 + $this->docs_url = __( 'https://www.elasticpress.io/resources/articles/configuring-elasticpress-via-the-plugin-dashboard/#post-search', 'elasticpress' );
85 +
86 + $this->field_group_map = [
87 + 'highlight_group' => [
88 + 'label' => esc_html__( 'Highlighting Options', 'elasticpress' ),
89 + ],
90 + ];
91 + }
92 +
93 + /**
76 94 * We need to delay search setup up since it will fire after protected content and protected
77 95 * content filters into the search setup
78 96 *
79 97 * @since 2.2
@@ -78,10 +96,11 @@
78 96 *
79 97 * @since 2.2
80 98 */
81 99 public function setup() {
100 + Indexables::factory()->activate( 'post' );
101 +
82 102 add_action( 'init', [ $this, 'search_setup' ] );
83 - add_filter( 'ep_sanitize_feature_settings', [ $this, 'sanitize_highlighting_settings' ] );
84 103
85 104 // Set up weighting sub-module
86 105 $this->weighting = new Weighting();
87 106 $this->weighting->setup();
@@ -103,8 +122,19 @@
103 122 add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
104 123 add_filter( 'ep_formatted_args', [ $this, 'add_search_highlight_tags' ], 10, 2 );
105 124 add_filter( 'ep_highlighting_tag', [ $this, 'get_highlighting_tag' ] );
106 125 add_action( 'ep_highlighting_pre_add_highlight', [ $this, 'allow_excerpt_html' ] );
126 +
127 + add_action( 'init', [ $this, 'register_meta' ], 20 );
128 + add_filter( 'ep_prepare_meta_allowed_keys', [ $this, 'add_exclude_from_search' ] );
129 + add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_block_editor_assets' ] );
130 + add_filter( 'ep_post_filters', [ $this, 'exclude_posts_from_search' ], 10, 3 );
131 + add_action( 'post_submitbox_misc_actions', [ $this, 'output_exclude_from_search_setting' ] );
132 + add_action( 'edit_post', [ $this, 'save_exclude_from_search_meta' ] );
133 + add_filter( 'ep_skip_query_integration', [ $this, 'skip_query_integration' ], 10, 2 );
134 +
135 + add_action( 'attachment_submitbox_misc_actions', [ $this, 'output_exclude_from_search_setting' ], 15 );
136 + add_action( 'edit_attachment', [ $this, 'save_exclude_from_search_meta' ] );
107 137 }
108 138
109 139
110 140 /**
@@ -112,21 +142,15 @@
112 142 */
113 143 public function enqueue_scripts() {
114 144 $settings = $this->get_settings();
115 145
116 - if ( ! $settings ) {
117 - $settings = [];
118 - }
119 -
120 - $settings = wp_parse_args( $settings, $this->default_settings );
121 -
122 - if ( true !== $settings['highlight_enabled'] ) {
146 + if ( '1' !== $settings['highlight_enabled'] ) {
123 147 return;
124 148 }
125 149
126 150 wp_enqueue_style(
127 151 'searchterm-highlighting',
128 - EP_URL . 'dist/css/highlighting-styles.min.css',
152 + EP_URL . 'dist/css/highlighting-styles.css',
129 153 Utils\get_asset_info( 'highlighting-styles', 'dependencies' ),
130 154 Utils\get_asset_info( 'highlighting-styles', 'version' )
131 155 );
132 156 }
@@ -153,15 +177,9 @@
153 177
154 178 // get current config
155 179 $settings = $this->get_settings();
156 180
157 - if ( ! $settings ) {
158 - $settings = [];
159 - }
160 -
161 - $settings = wp_parse_args( $settings, $this->default_settings );
162 -
163 - if ( true !== $settings['highlight_enabled'] ) {
181 + if ( '1' !== $settings['highlight_enabled'] ) {
164 182 return $formatted_args;
165 183 }
166 184
167 185 if ( empty( $args['s'] ) ) {
@@ -229,9 +247,9 @@
229 247 */
230 248 $highlight_class = apply_filters( 'ep_highlighting_class', 'ep-highlight' );
231 249
232 250 // tags
233 - $opening_tag = '<' . $highlight_tag . ' class="' . $highlight_class . '">';
251 + $opening_tag = '<' . $highlight_tag . " class='" . $highlight_class . "'>";
234 252 $closing_tag = '</' . $highlight_tag . '>';
235 253
236 254 foreach ( $fields_to_highlight as $field ) {
237 255 $formatted_args['highlight']['fields'][ $field ] = [
@@ -237,9 +255,18 @@
237 255 $formatted_args['highlight']['fields'][ $field ] = [
238 256 'pre_tags' => [ $opening_tag ],
239 257 'post_tags' => [ $closing_tag ],
240 258 'type' => 'plain',
241 - 'number_of_fragments' => 0,
259 + /**
260 + * Filter the maximum number of fragments highlighted for a searched field.
261 + *
262 + * @since 4.7.2
263 + * @hook ep_highlight_number_of_fragments
264 + * @param {int} $max_fragments Maximum number of fragments for field.
265 + * @param {string} $field Search field being setup.
266 + * @return {int} New maximum number of fragments to highlight for the searched field.
267 + */
268 + 'number_of_fragments' => apply_filters( 'ep_highlight_number_of_fragments', 0, $field ),
242 269 ];
243 270 }
244 271
245 272 return $formatted_args;
@@ -251,27 +278,17 @@
251 278 * Replaces the default excerpt with the custom excerpt, allowing
252 279 * for the selected tag to be displayed in it.
253 280 */
254 281 public function allow_excerpt_html() {
255 - if ( is_admin() ) {
282 + if ( ! Utils\is_integrated_request( 'highlighting', [ 'public' ] ) ) {
256 283 return;
257 284 }
258 285
259 - if ( empty( $_GET['s'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
260 - return;
261 - }
262 -
263 286 $settings = $this->get_settings();
264 287
265 - if ( ! $settings ) {
266 - $settings = [];
267 - }
268 -
269 - $settings = wp_parse_args( $settings, $this->default_settings );
270 -
271 - if ( ! empty( $settings['highlight_excerpt'] ) && true === $settings['highlight_excerpt'] ) {
288 + if ( ! empty( $settings['highlight_excerpt'] ) && '1' === $settings['highlight_excerpt'] ) {
272 289 remove_filter( 'get_the_excerpt', 'wp_trim_excerpt' );
273 - add_filter( 'get_the_excerpt', [ $this, 'ep_highlight_excerpt' ] );
290 + add_filter( 'get_the_excerpt', [ $this, 'ep_highlight_excerpt' ], 10, 2 );
274 291 add_filter( 'ep_highlighting_fields', [ $this, 'ep_highlight_add_excerpt_field' ] );
275 292 }
276 293 }
277 294
@@ -278,26 +295,26 @@
278 295 /**
279 296 * Called by allow_excerpt_html
280 297 * logic for the excerpt filter allowing the currently selected tag.
281 298 *
282 - * @param string $text - excerpt string
283 - * @return string $text - the new excerpt
299 + * @param string $text excerpt string
300 + * @param WP_Post $post Post Object
301 + *
302 + * @return string $text the new excerpt
284 303 */
285 - public function ep_highlight_excerpt( $text ) {
286 -
304 + public function ep_highlight_excerpt( $text, $post ) {
287 305 $settings = $this->get_settings();
288 306
289 - if ( ! $settings ) {
290 - $settings = [];
291 - }
307 + // reproduces wp_trim_excerpt filter, preserving the excerpt_more and excerpt_length filters
308 + if ( '' === $text ) {
309 + $text = get_the_content( '', false, $post );
292 310
293 - $settings = wp_parse_args( $settings, $this->default_settings );
311 + $text = strip_shortcodes( $text );
312 + $text = excerpt_remove_blocks( $text );
294 313
295 - // reproduces wp_trim_excerpt filter, preserving the excerpt_more and excerpt_length filters
296 - if ( '' === $text ) {
297 - $text = get_the_content( '' );
298 314 $text = apply_filters( 'the_content', $text );
299 315 $text = str_replace( '\]\]\>', ']]&gt;', $text );
316 +
300 317 $text = strip_tags( $text, '<' . esc_html( $settings['highlight_tag'] ) . '>' );
301 318
302 319 // use the defined length, if already applied...
303 320 $excerpt_length = apply_filters( 'excerpt_length', 55 );
@@ -303,11 +320,14 @@
303 320 $excerpt_length = apply_filters( 'excerpt_length', 55 );
304 321
305 322 // use defined excerpt_more filter if it is used
306 323 $excerpt_more = apply_filters( 'excerpt_more', $text );
307 -
308 324 $excerpt_more = $excerpt_more !== $text ? $excerpt_more : '[&hellip;]';
309 325
326 + /**
327 + * WordPress would handle this using `wp_trim_words` but that removes all tags,
328 + * including the one used to highlight the search term.
329 + */
310 330 $words = explode( ' ', $text, $excerpt_length + 1 );
311 331 if ( count( $words ) > $excerpt_length ) {
312 332 array_pop( $words );
313 333 array_push( $words, $excerpt_more );
@@ -344,26 +364,8 @@
344 364 return $tag;
345 365 }
346 366
347 367 /**
348 - * Sanitizes our highlighting settings.
349 - *
350 - * @param array $settings Array of current settings
351 - * @return mixed
352 - */
353 - public function sanitize_highlighting_settings( $settings ) {
354 - if ( ! empty( $settings['search']['highlight_excerpt'] ) ) {
355 - $settings['search']['highlight_excerpt'] = (bool) $settings['search']['highlight_excerpt'];
356 - }
357 -
358 - if ( ! empty( $settings['search']['highlight_enabled'] ) ) {
359 - $settings['search']['highlight_enabled'] = (bool) $settings['search']['highlight_enabled'];
360 - }
361 -
362 - return $settings;
363 - }
364 -
365 - /**
366 368 * Returns searchable post types for the current site
367 369 *
368 370 * @since 1.9
369 371 * @return mixed|void
@@ -422,21 +424,28 @@
422 424
423 425 /**
424 426 * Returns true/false if decaying is/isn't enabled
425 427 *
428 + * @param array $args WP_Query args
429 + *
426 430 * @return bool
427 431 */
428 - public function is_decaying_enabled() {
432 + public function is_decaying_enabled( $args = [] ) {
429 433 $settings = $this->get_settings();
430 434
431 - $settings = wp_parse_args(
432 - $settings,
433 - [
434 - 'decaying_enabled' => true,
435 - ]
436 - );
435 + $is_decaying_enabled = $settings['decaying_enabled'] && '0' !== $settings['decaying_enabled'];
437 436
438 - return (bool) $settings['decaying_enabled'];
437 + /**
438 + * Filter to modify decaying
439 + *
440 + * @hook ep_is_decaying_enabled
441 + * @since 4.6.0
442 + * @param {bool} $is_decaying_enabled Whether decay by date is enabled or not
443 + * @param {array} $settings Settings
444 + * @param {array} $args WP_Query args
445 + * @return {bool} Decaying
446 + */
447 + return apply_filters( 'ep_is_decaying_enabled', $is_decaying_enabled, $settings, $args );
439 448 }
440 449
441 450 /**
442 451 * Weight more recent content in searches
@@ -446,117 +455,121 @@
446 455 * @since 2.1
447 456 * @return array
448 457 */
449 458 public function weight_recent( $formatted_args, $args ) {
450 - if ( ! empty( $args['s'] ) ) {
451 - if ( $this->is_decaying_enabled() ) {
452 - /**
453 - * Filter search date weighting scale
454 - *
455 - * @hook epwr_decay_function
456 - * @param {string} $decay_function Current decay function
457 - * @param {array} $formatted_args Formatted Elasticsearch arguments
458 - * @param {array} $args WP_Query arguments
459 - * @return {string} New decay function
460 - */
461 - $decay_function = apply_filters( 'epwr_decay_function', 'exp', $formatted_args, $args );
462 - $date_score = array(
463 - 'function_score' => array(
464 - 'query' => $formatted_args['query'],
465 - 'functions' => array(
466 - array(
467 - $decay_function => array(
468 - 'post_date_gmt' => array(
469 - /**
470 - * Filter search date weighting scale
471 - *
472 - * @hook epwr_scale
473 - * @param {string} $scale Current scale
474 - * @param {array} $formatted_args Formatted Elasticsearch arguments
475 - * @param {array} $args WP_Query arguments
476 - * @return {string} New scale
477 - */
478 - 'scale' => apply_filters( 'epwr_scale', '14d', $formatted_args, $args ),
479 - /**
480 - * Filter search date weighting decay
481 - *
482 - * @hook epwr_decay
483 - * @param {float} $decay Current decay
484 - * @param {array} $formatted_args Formatted Elasticsearch arguments
485 - * @param {array} $args WP_Query arguments
486 - * @return {float} New decay
487 - */
488 - 'decay' => apply_filters( 'epwr_decay', 0.25, $formatted_args, $args ),
489 - /**
490 - * Filter search date weighting offset
491 - *
492 - * @hook epwr_offset
493 - * @param {string} $offset Current offset
494 - * @param {array} $formatted_args Formatted Elasticsearch arguments
495 - * @param {array} $args WP_Query arguments
496 - * @return {string} New offset
497 - */
498 - 'offset' => apply_filters( 'epwr_offset', '7d', $formatted_args, $args ),
499 - ),
500 - ),
501 - ),
502 - array(
459 + if ( empty( $args['s'] ) ) {
460 + return $formatted_args;
461 + }
462 +
463 + if ( ! $this->is_decaying_enabled( $args ) ) {
464 + return $formatted_args;
465 + }
466 +
467 + /**
468 + * Filter search date weighting scale
469 + *
470 + * @hook epwr_decay_function
471 + * @param {string} $decay_function Current decay function
472 + * @param {array} $formatted_args Formatted Elasticsearch arguments
473 + * @param {array} $args WP_Query arguments
474 + * @return {string} New decay function
475 + */
476 + $decay_function = apply_filters( 'epwr_decay_function', 'exp', $formatted_args, $args );
477 +
478 + /**
479 + * Filter search date weighting field
480 + *
481 + * @hook epwr_decay_field
482 + * @param {string} $field Current decay field
483 + * @param {array} $formatted_args Formatted Elasticsearch arguments
484 + * @param {array} $args WP_Query arguments
485 + * @return {string} New decay field
486 + * @since 4.3.0
487 + */
488 + $field = apply_filters( 'epwr_decay_field', 'post_date_gmt', $formatted_args, $args );
489 + $date_score = array(
490 + 'function_score' => array(
491 + 'query' => $formatted_args['query'],
492 + 'functions' => array(
493 + array(
494 + $decay_function => array(
495 + $field => array(
503 496 /**
504 - * Filter search date weight
497 + * Filter search date weighting scale
505 498 *
506 - * @since 3.5.6
507 - * @hook epwr_weight
508 - * @param {float} $weight Current weight
499 + * @hook epwr_scale
500 + * @param {string} $scale Current scale
509 501 * @param {array} $formatted_args Formatted Elasticsearch arguments
510 502 * @param {array} $args WP_Query arguments
511 - * @return {float} New weight
503 + * @return {string} New scale
512 504 */
513 - 'weight' => apply_filters( 'epwr_weight', 0.001, $formatted_args, $args ),
505 + 'scale' => apply_filters( 'epwr_scale', '14d', $formatted_args, $args ),
506 + /**
507 + * Filter search date weighting decay
508 + *
509 + * @hook epwr_decay
510 + * @param {float} $decay Current decay
511 + * @param {array} $formatted_args Formatted Elasticsearch arguments
512 + * @param {array} $args WP_Query arguments
513 + * @return {float} New decay
514 + */
515 + 'decay' => apply_filters( 'epwr_decay', 0.25, $formatted_args, $args ),
516 + /**
517 + * Filter search date weighting offset
518 + *
519 + * @hook epwr_offset
520 + * @param {string} $offset Current offset
521 + * @param {array} $formatted_args Formatted Elasticsearch arguments
522 + * @param {array} $args WP_Query arguments
523 + * @return {string} New offset
524 + */
525 + 'offset' => apply_filters( 'epwr_offset', '7d', $formatted_args, $args ),
514 526 ),
515 527 ),
528 + ),
529 + array(
516 530 /**
517 - * Filter search date weighting score mode
531 + * Filter search date weight
518 532 *
519 - * @hook epwr_score_mode
520 - * @param {string} $score_mode Current score mode
533 + * @since 3.5.6
534 + * @hook epwr_weight
535 + * @param {float} $weight Current weight
521 536 * @param {array} $formatted_args Formatted Elasticsearch arguments
522 537 * @param {array} $args WP_Query arguments
523 - * @return {string} New score mode
538 + * @return {float} New weight
524 539 */
525 - 'score_mode' => apply_filters( 'epwr_score_mode', 'sum', $formatted_args, $args ),
526 - /**
527 - * Filter search date weighting boost mode
528 - *
529 - * @hook epwr_boost_mode
530 - * @param {string} $boost_mode Current boost mode
531 - * @param {array} $formatted_args Formatted Elasticsearch arguments
532 - * @param {array} $args WP_Query arguments
533 - * @return {string} New boost mode
534 - */
535 - 'boost_mode' => apply_filters( 'epwr_boost_mode', 'multiply', $formatted_args, $args ),
540 + 'weight' => apply_filters( 'epwr_weight', 0.001, $formatted_args, $args ),
536 541 ),
537 - );
542 + ),
543 + /**
544 + * Filter search date weighting score mode
545 + *
546 + * @hook epwr_score_mode
547 + * @param {string} $score_mode Current score mode
548 + * @param {array} $formatted_args Formatted Elasticsearch arguments
549 + * @param {array} $args WP_Query arguments
550 + * @return {string} New score mode
551 + */
552 + 'score_mode' => apply_filters( 'epwr_score_mode', 'sum', $formatted_args, $args ),
553 + /**
554 + * Filter search date weighting boost mode
555 + *
556 + * @hook epwr_boost_mode
557 + * @param {string} $boost_mode Current boost mode
558 + * @param {array} $formatted_args Formatted Elasticsearch arguments
559 + * @param {array} $args WP_Query arguments
560 + * @return {string} New boost mode
561 + */
562 + 'boost_mode' => apply_filters( 'epwr_boost_mode', 'multiply', $formatted_args, $args ),
563 + ),
564 + );
538 565
539 - $formatted_args['query'] = $date_score;
540 - }
541 - }
566 + $formatted_args['query'] = $date_score;
542 567
543 568 return $formatted_args;
544 569 }
545 570
546 571 /**
547 - * Output feature box long text
548 - *
549 - * @since 3.0
550 - */
551 - public function output_feature_box_long() {
552 - ?>
553 - <p><?php esc_html_e( 'Overcome higher-end performance and functional limits posed by the traditional WordPress structured (SQL) database to deliver superior keyword search, instantly. ElasticPress indexes custom fields, tags, and other metadata to improve search results. Fuzzy matching accounts for misspellings and verb tenses.', 'elasticpress' ); ?></p>
554 -
555 - <?php
556 - }
557 -
558 - /**
559 572 * Enable integration on search queries
560 573 *
561 574 * @param bool $enabled Original enabled value
562 575 * @param WP_Query $query WP Query
@@ -577,19 +590,8 @@
577 590 }
578 591
579 592 if ( method_exists( $query, 'is_search' ) && $query->is_search() && ! empty( $query->query_vars['s'] ) ) {
580 593 $enabled = true;
581 -
582 - /**
583 - * WordPress have to be version 4.6 or newer to have "fields" support
584 - * since it requires the "posts_pre_query" filter.
585 - *
586 - * @see WP_Query::get_posts
587 - */
588 - $fields = $query->get( 'fields' );
589 - if ( ! version_compare( get_bloginfo( 'version' ), '4.6', '>=' ) && ! empty( $fields ) ) {
590 - $enabled = false;
591 - }
592 594 }
593 595
594 596 /**
595 597 * Filter whether to enable integration on search queries or not.
@@ -603,64 +605,291 @@
603 605 return apply_filters( 'ep_integrate_search_queries', $enabled, $query );
604 606 }
605 607
606 608 /**
607 - * Display decaying settings on dashboard.
609 + * Registers post meta for exclude from search feature.
610 + */
611 + public function register_meta() {
612 + register_post_meta(
613 + '',
614 + 'ep_exclude_from_search',
615 + [
616 + 'show_in_rest' => true,
617 + 'single' => true,
618 + 'type' => 'boolean',
619 + ]
620 + );
621 + }
622 +
623 + /**
624 + * Add ep_exclude_from_search to the allowed meta fields list.
608 625 *
609 - * @since 2.4
626 + * @since 5.0.0
627 + * @param array $keys List of allowed meta fields
628 + * @return array
610 629 */
611 - public function output_feature_box_settings() {
612 - $settings = $this->get_settings();
630 + public function add_exclude_from_search( $keys ) {
631 + $keys[] = 'ep_exclude_from_search';
632 + return $keys;
633 + }
613 634
614 - if ( ! $settings ) {
615 - $settings = [];
635 + /**
636 + * Enqueue block editor assets.
637 + */
638 + public function enqueue_block_editor_assets() {
639 + global $post;
640 +
641 + if ( ! $post instanceof \WP_Post ) {
642 + return;
616 643 }
617 644
618 - $settings = wp_parse_args( $settings, $this->default_settings );
645 + if ( ! $post->post_type || ! post_type_supports( $post->post_type, 'custom-fields' ) ) {
646 + return;
647 + }
619 648
649 + wp_enqueue_script(
650 + 'ep-search-editor',
651 + EP_URL . 'dist/js/search-editor-script.js',
652 + Utils\get_asset_info( 'search-editor-script', 'dependencies' ),
653 + Utils\get_asset_info( 'search-editor-script', 'version' ),
654 + true
655 + );
656 +
657 + wp_set_script_translations( 'ep-search-editor', 'elasticpress' );
658 + }
659 +
660 + /**
661 + * Exclude posts based on ep_exclude_from_search post meta.
662 + *
663 + * @param array $filters Filters to be applied to the query
664 + * @param array $args WP Query args
665 + * @param WP_Query $query WP Query object
666 + */
667 + public function exclude_posts_from_search( $filters, $args, $query ) {
668 + if ( ! empty( $query->get( 'ep_skip_search_exclusion' ) ) ) {
669 + return $filters;
670 + }
671 +
672 + $bypass_exclusion_from_search = ( is_admin() && ! wp_doing_ajax() ) || ! $query->is_search();
673 +
674 + /**
675 + * Filter whether the exclusion from the "exclude from search" checkbox should be applied
676 + *
677 + * @since 4.4.0
678 + * @hook ep_bypass_exclusion_from_search
679 + * @param {bool} $bypass_exclusion_from_search True means all posts will be returned
680 + * @param {WP_Query} $query WP Query
681 + * @return {bool} New $bypass_exclusion_from_search value
682 + */
683 + if ( apply_filters_deprecated(
684 + 'ep_bypass_exclusion_from_search',
685 + [ $bypass_exclusion_from_search, $query ],
686 + 'ElasticPress 5.3.0',
687 + 'WP_Query->ep_skip_search_exclusion argument'
688 + ) ) {
689 + return $filters;
690 + }
691 +
692 + $filters[] = [
693 + 'bool' => [
694 + 'must_not' => [
695 + [
696 + 'terms' => [
697 + 'meta.ep_exclude_from_search.raw' => [ '1' ],
698 + ],
699 + ],
700 + ],
701 + ],
702 + ];
703 +
704 + return $filters;
705 + }
706 +
707 + /**
708 + * Outputs the checkbox to exclude a post from search.
709 + *
710 + * @param WP_POST $post Post object.
711 + */
712 + public function output_exclude_from_search_setting( $post ) {
713 + $searchable_post_types = $this->get_searchable_post_types();
714 + if ( ! in_array( $post->post_type, $searchable_post_types, true ) ) {
715 + return;
716 + }
620 717 ?>
621 - <div class="field">
622 - <div class="field-name status"><?php esc_html_e( 'Weight results by date', 'elasticpress' ); ?></div>
623 - <div class="input-wrap">
624 - <label><input name="settings[decaying_enabled]" type="radio" <?php checked( (bool) $settings['decaying_enabled'] ); ?> value="1"><?php esc_html_e( 'Enabled', 'elasticpress' ); ?></label><br>
625 - <label><input name="settings[decaying_enabled]" type="radio" <?php checked( ! (bool) $settings['decaying_enabled'] ); ?> value="0"><?php esc_html_e( 'Disabled', 'elasticpress' ); ?></label>
626 - </div>
718 + <div class="misc-pub-section">
719 + <input id="ep_exclude_from_search" name="ep_exclude_from_search" type="checkbox" value="1" <?php checked( get_post_meta( get_the_ID(), 'ep_exclude_from_search', true ) ); ?>>
720 + <label for="ep_exclude_from_search"><?php esc_html_e( 'Exclude from search results', 'elasticpress' ); ?></label>
721 + <p class="howto">
722 + <?php if ( 'attachment' === $post->post_type ) : ?>
723 + <?php esc_html_e( 'Excludes this media from the results of your site\'s search form while ElasticPress is active.', 'elasticpress' ); ?>
724 + <?php else : ?>
725 + <?php esc_html_e( 'Excludes this post from the results of your site\'s search form while ElasticPress is active.', 'elasticpress' ); ?>
726 + <?php endif; ?>
727 + </p>
728 + <?php wp_nonce_field( 'save-exclude-from-search', 'ep-exclude-from-search-nonce' ); ?>
627 729 </div>
628 - <div class="field">
629 - <div class="field-name status"><?php esc_html_e( 'Highlighting status', 'elasticpress' ); ?></div>
630 - <div class="input-wrap">
631 - <label><input name="settings[highlight_enabled]" type="radio" <?php checked( (bool) $settings['highlight_enabled'] ); ?> value="1"><?php esc_html_e( 'Enabled', 'elasticpress' ); ?></label><br>
632 - <label><input name="settings[highlight_enabled]" type="radio" <?php checked( ! (bool) $settings['highlight_enabled'] ); ?> value="0"><?php esc_html_e( 'Disabled', 'elasticpress' ); ?></label>
633 - <p class="field-description"><?php esc_html_e( 'Wrap search terms in HTML tags in results for custom styling. The wrapping HTML tag comes with the "ep-highlight" class for easy styling.' ); ?></p>
634 - </div>
635 - </div>
636 - <div class="field">
637 - <label for="highlight-tag" class="field-name status"><?php echo esc_html_e( 'Highlight tag ', 'elasticpress' ); ?></label>
638 - <div class="input-wrap">
639 - <select id="highlight-tag" name="settings[highlight_tag]">
640 - <?php
641 - foreach ( self::$default_highlight_tags as $option ) :
642 - echo '<option value="' . esc_attr( $option ) . '" ' . selected( $option, $settings['highlight_tag'] ) . '>' . esc_html( $option ) . '</option>';
643 - endforeach;
644 - ?>
645 - </select>
646 - </div>
647 - </div>
730 + <?php
731 + }
648 732
649 - <div class="field">
650 - <div class="field-name status"><?php esc_html_e( 'Excerpt highlighting', 'elasticpress' ); ?></div>
651 - <div class="input-wrap">
652 - <label><input name="settings[highlight_excerpt]" type="radio" <?php checked( (bool) $settings['highlight_excerpt'] ); ?> value="1"><?php esc_html_e( 'Enabled', 'elasticpress' ); ?></label><br>
653 - <label><input name="settings[highlight_excerpt]" type="radio" <?php checked( ! (bool) $settings['highlight_excerpt'] ); ?> value="0"><?php esc_html_e( 'Disabled', 'elasticpress' ); ?></label>
654 - <p class="field-description"><?php esc_html_e( 'By default, WordPress strips HTML from content excerpts. Enable when using the_excerpt() to display search results. ', 'elasticpress' ); ?></p>
655 - </div>
656 - </div>
733 + /**
734 + * Saves exclude from search meta.
735 + *
736 + * @param int $post_id The post ID.
737 + */
738 + public function save_exclude_from_search_meta( $post_id ) {
739 + if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
740 + return;
741 + }
657 742
658 - <?php if ( ! defined( 'EP_IS_NETWORK' ) || ! EP_IS_NETWORK ) : ?>
659 - <br class="clear">
660 - <p><a href="<?php echo esc_url( admin_url( 'admin.php?page=elasticpress-weighting' ) ); ?>"><?php esc_html_e( 'Advanced fields and weighting settings', 'elasticpress' ); ?></a></p>
661 - <p><a href="<?php echo esc_url( admin_url( 'admin.php?page=elasticpress-synonyms' ) ); ?>"><?php esc_html_e( 'Add synonyms to your post searches', 'elasticpress' ); ?></a></p>
662 - <?php endif; ?>
743 + if ( ! isset( $_POST['ep-exclude-from-search-nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['ep-exclude-from-search-nonce'] ), 'save-exclude-from-search' ) ) {
744 + return;
745 + }
663 746
664 - <?php
747 + if ( ! current_user_can( 'edit_post', $post_id ) ) {
748 + return;
749 + }
750 +
751 + if ( isset( $_POST['ep_exclude_from_search'] ) ) {
752 + update_post_meta( $post_id, 'ep_exclude_from_search', true );
753 + } else {
754 + delete_post_meta( $post_id, 'ep_exclude_from_search' );
755 + }
756 + }
757 +
758 + /**
759 + * If WP_Query has unsupported orderby, skip ES query integration and use the WP query instead.
760 + *
761 + * @param bool $skip Whether to skip ES query integration
762 + * @param \WP_Query $query WP_Query object
763 + *
764 + * @since 4.5
765 + * @return bool
766 + */
767 + public function skip_query_integration( $skip, $query ) {
768 + if ( ! $query instanceof \WP_Query ) {
769 + return $skip;
770 + }
771 +
772 + $unsupported_orderby = [
773 + 'post__in',
774 + 'post_name__in',
775 + 'post_parent__in',
776 + 'parent',
777 + ];
778 +
779 + $orderby = is_string( $query->get( 'orderby' ) ) ? explode( ' ', $query->get( 'orderby' ) ) : $query->get( 'orderby', 'date' );
780 +
781 + $parse_orderby = array();
782 + foreach ( $orderby as $key => $value ) {
783 + $parse_orderby[] = is_string( $key ) ? $key : $value;
784 + }
785 +
786 + if ( array_intersect( $parse_orderby, $unsupported_orderby ) ) {
787 + return true;
788 + }
789 +
790 + return $skip;
791 + }
792 +
793 + /**
794 + * Set the `settings_schema` attribute
795 + *
796 + * @since 5.0.0
797 + */
798 + protected function set_settings_schema() {
799 + $this->settings_schema = [
800 + [
801 + 'default' => '1',
802 + 'key' => 'decaying_enabled',
803 + 'label' => __( 'Weighting by date', 'elasticpress' ),
804 + 'options' => [
805 + [
806 + 'label' => __( 'Don\'t weight results by date', 'elasticpress' ),
807 + 'value' => '0',
808 + ],
809 + [
810 + 'label' => __( 'Weight results by date', 'elasticpress' ),
811 + 'value' => '1',
812 + ],
813 + ],
814 + 'type' => 'radio',
815 + ],
816 + [
817 + 'default' => '0',
818 + 'help' => __( 'Enable to wrap search terms in HTML tags in results for custom styling. The wrapping HTML tag comes with the <code>ep-highlight</code> class for easy styling.', 'elasticpress' ),
819 + 'key' => 'highlight_enabled',
820 + 'label' => __( 'Highlight search terms', 'elasticpress' ),
821 + 'type' => 'checkbox',
822 + 'field_group_slug' => 'highlight_group',
823 + ],
824 + [
825 + 'default' => '0',
826 + 'help' => __( 'By default, WordPress strips HTML from content excerpts. Enable when using <code>the_excerpt()</code> to display search results.', 'elasticpress' ),
827 + 'key' => 'highlight_excerpt',
828 + 'label' => __( 'Highlight search terms in excerpts', 'elasticpress' ),
829 + 'type' => 'checkbox',
830 + 'field_group_slug' => 'highlight_group',
831 + ],
832 + [
833 + 'default' => 'mark',
834 + 'help' => __( 'Select the HTML tag used to highlight search terms.', 'elasticpress' ),
835 + 'key' => 'highlight_tag',
836 + 'label' => __( 'Highlight tag', 'elasticpress' ),
837 + 'options' => [
838 + [
839 + 'label' => 'mark',
840 + 'value' => 'mark',
841 + ],
842 + [
843 + 'label' => 'span',
844 + 'value' => 'span',
845 + ],
846 + [
847 + 'label' => 'strong',
848 + 'value' => 'strong',
849 + ],
850 + [
851 + 'label' => 'em',
852 + 'value' => 'em',
853 + ],
854 + [
855 + 'label' => 'i',
856 + 'value' => 'i',
857 + ],
858 + ],
859 + 'type' => 'select',
860 + 'requires_fields' => [
861 + 'relationship' => 'OR',
862 + 'conditions' => [
863 + 'highlight_enabled' => '1',
864 + 'highlight_excerpt' => '1',
865 + ],
866 + ],
867 + 'field_group_slug' => 'highlight_group',
868 + ],
869 + [
870 + 'default' => 'simple',
871 + 'key' => 'synonyms_editor_mode',
872 + 'type' => 'hidden',
873 + ],
874 + ];
875 +
876 + if ( ! defined( 'EP_IS_NETWORK' ) || ! EP_IS_NETWORK ) {
877 + $weighting_url = esc_url( admin_url( 'admin.php?page=elasticpress-weighting' ) );
878 + $synonyms_url = esc_url( admin_url( 'admin.php?page=elasticpress-synonyms' ) );
879 +
880 + $text = sprintf(
881 + '<p><a href="%1$s">%2$s</a></p><p><a href="%3$s">%4$s</a></p>',
882 + $weighting_url,
883 + __( 'Advanced fields and weighting settings', 'elasticpress' ),
884 + $synonyms_url,
885 + __( 'Add synonyms to your post searches', 'elasticpress' ),
886 + );
887 +
888 + $this->settings_schema[] = [
889 + 'key' => 'additional_links',
890 + 'label' => $text,
891 + 'type' => 'markup',
892 + ];
893 + }
665 894 }
666 895 }