I’m currently running WordPress on version 4.6.1 and I’m attempting to search for posts that contains the character - (hyphen). However, the search parameter is taking my hyphen for a negation.

From the WP_Query documentation:

Prepending a term with a hyphen will exclude posts matching that term. Eg, ‘pillow -sofa’ will return posts containing ‘pillow’ but not ‘sofa’ (available since Version 4.4).

Here’s my query:

$query = new WP_Query(array(
    'post_type' => array('product', 'product_variation'),
    's' => '-',
    'posts_per_page' => 36
));

I’ve tried to escape the hyphen by doing:

's' => '\-'

However, the result stays the same (var_dump($query->request)):

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
WHERE
    1=1
    AND (((wp_posts.post_title NOT LIKE '%%')
    AND (wp_posts.post_excerpt NOT LIKE '%%')
    AND (wp_posts.post_content NOT LIKE '%%')))
    AND (wp_posts.post_password = '')
    AND wp_posts.post_type IN ('product', 'product_variation')
    AND (wp_posts.post_status="publish" OR wp_posts.post_status="acf-disabled")
ORDER BY
    wp_posts.post_date DESC
LIMIT 0, 36

2 s
2

One approach is to modify the exclusion prefix through the wp_query_search_exclusion_prefix filter that’s supported in WP 4.7+.
See ticket #38099.

Here’s an example how we can change it from - to e.g. !:

add_filter( 'wp_query_search_exclusion_prefix', function( $prefix )
{
    return '!'; // adjust to your needs (default is -)
} );

where we would use !apple instead of -apple to exclude apple from the search results. Then you can search by -.

It looks like the exclusion prefix must be a single character (or empty to disable this feature), because of this check in the core:

// If there is an $exclusion_prefix, terms prefixed with it should be excluded.
$exclude = $exclusion_prefix && ( $exclusion_prefix === substr( $term, 0, 1 ) );
if ( $exclude ) {
    $like_op  = 'NOT LIKE';
    $andor_op = 'AND';
    $term     = substr( $term, 1 );
} else {
    $like_op  = 'LIKE';
    $andor_op = 'OR';
}

Otherwise it sounds like a bug, not to be able to search only for the term exclusion prefix.

I wonder if it would be better to add an extra $exclusion_prefix !== $term check to support that:

$exclude = $exclusion_prefix 
    && $exclusion_prefix !== $term 
    && ( $exclusion_prefix === mb_substr( $term, 0, 1 ) );
if ( $exclude ) {
    $like_op  = 'NOT LIKE';
    $andor_op = 'AND';
    $term     = mb_substr( $term, 1 );
} else {
    $like_op  = 'LIKE';
    $andor_op = 'OR';
}

where we would also use mb_substr() instead of substr() for a wider char support for the exclusion prefix.

I guess I should just create ticket for this …

Leave a Reply

Your email address will not be published. Required fields are marked *