diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index 226170ee7d..9e7883f6c5 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -721,7 +721,9 @@ class WP_Query { * @type array $post_name__in An array of post slugs that results must match. * @type string $s Search keyword(s). Prepending a term with a hyphen will * exclude posts matching that term. Eg, 'pillow -sofa' will - * return posts containing 'pillow' but not 'sofa'. + * return posts containing 'pillow' but not 'sofa'. This feature + * can be disabled using the + * 'wp_query_use_hyphen_for_exclusion' filter. * @type int $second Second of the minute. Default empty. Accepts numbers 0-60. * @type bool $sentence Whether to search by phrase. Default false. * @type bool $suppress_filters Whether to suppress filters. Default false. @@ -1318,10 +1320,20 @@ class WP_Query { $n = ! empty( $q['exact'] ) ? '' : '%'; $searchand = ''; $q['search_orderby_title'] = array(); + + /** + * Filters whether search terms preceded by hyphens should excluded from results. + * + * @since 4.7.0 + * + * @param bool Whether the query should exclude terms preceded with a hyphen. + */ + $hyphen_exclusion = apply_filters( 'wp_query_use_hyphen_for_exclusion', true ); + foreach ( $q['search_terms'] as $term ) { // Terms prefixed with '-' should be excluded. $include = '-' !== substr( $term, 0, 1 ); - if ( $include ) { + if ( $include || ! $hyphen_exclusion ) { $like_op = 'LIKE'; $andor_op = 'OR'; } else { diff --git a/tests/phpunit/tests/query/search.php b/tests/phpunit/tests/query/search.php index 2931a1a731..43c5da4caa 100644 --- a/tests/phpunit/tests/query/search.php +++ b/tests/phpunit/tests/query/search.php @@ -59,6 +59,28 @@ class Tests_Query_Search extends WP_UnitTestCase { return array(); } + /** + * @ticket 38099 + */ + function test_filter_wp_query_use_hyphen_for_exclusion() { + $title = '-HYPHENATION_TEST'; + + // Create a post with a title which starts with a hyphen + $post_id = self::factory()->post->create( array( + 'post_content' => $title, 'post_type' => $this->post_type + ) ); + + // By default, we can use the hyphen prefix to exclude results + $this->assertEquals( array(), $this->get_search_results( $title ) ); + + // After we disable the feature using the filter, we should get the result + add_filter( 'wp_query_use_hyphen_for_exclusion', '__return_false' ); + $result = $this->get_search_results( $title ); + $post = array_pop( $result ); + $this->assertEquals( $post->ID, $post_id ); + remove_filter( 'wp_query_use_hyphen_for_exclusion', '__return_false' ); + } + /** * @ticket 33988 */