Make WordPress Core

Opened 3 years ago

Last modified 3 years ago

#54853 new defect (bug)

Search only searching phrases and not searching individual terms

Reported by: jchang's profile jchang Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 5.8.3
Component: Query Keywords: needs-patch
Focuses: Cc:

Description

get_posts(array(
  "post_type" => "fruit",
  "s" => "apple orange banana"
));

should search for each term separately, but it does not. It searches the entire string as a phrase.

Issue is within /wp-includes/class-wp-query.php line 1398. It's a simple change:

$searchand = ' AND ';
to
$searchand = ' OR ';

Change History (4)

#1 in reply to: ↑ description @parinpanjari
3 years ago

The function we check that we are NOT viewing the admin area, that we ARE constructing the main query and that we ARE making a search.

add_filter('posts_search', 'my_search_is_exact', 20, 2);
function my_search_is_exact($search, $wp_query){

    global $wpdb;

    if(empty($search))
        return $search;

    $q = $wp_query->query_vars;
    $n = !empty($q['exact']) ? '' : '%';

    $search = $searchand = '';

    foreach((array)$q['search_terms'] as $term) :

        $term = esc_sql(like_escape($term));

        $search.= "{$searchand}($wpdb->posts.post_title REGEXP '[[:<:]]{$term}[[:>:]]') OR ($wpdb->posts.post_content REGEXP '[[:<:]]{$term}[[:>:]]')";

        $searchand = ' AND ';

    endforeach;

    if(!empty($search)) :
        $search = " AND ({$search}) ";
        if(!is_user_logged_in())
            $search .= " AND ($wpdb->posts.post_password = '') ";
    endif;

    return $search;

}
Last edited 3 years ago by SergeyBiryukov (previous) (diff)

#2 follow-up: @SergeyBiryukov
3 years ago

  • Severity changed from blocker to normal

Hi there, welcome to WordPress Trac! Thanks for the ticket.

get_posts(array(
  "post_type" => "fruit",
  "s" => "apple orange banana"
));

should search for each term separately, but it does not. It searches the entire string as a phrase.

Just noting that the search ordering logic is slightly more advanced.

Some history here:

  • [4426] / #3177 (WordPress 2.1+) allowed "quoted strings" to be used in searches for exact matches.
  • [25632] / #7394 (WordPress 3.7+) orders search results by relevance, rather than by date.

The ordering logic is as follows:

  • Full sentence matches in post titles.
  • All search terms in post titles.
  • Any search terms in post titles.
  • Full sentence matches in post content.

Each section and any remaining posts are then sorted by date.

Additionally, WP_Query::parse_query() has a 'sentence' argument that controls whether to search by phrase.

So it seems to me that the default search behavior works as intended and documented, I don't see a bug here. As noted above, this can be customized using the posts_search or posts_search_orderby filters.

Last edited 3 years ago by SergeyBiryukov (previous) (diff)

#3 @thelovekesh
3 years ago

Implemented logic seems nice to me. If you keep $searchand = ' OR ' then it will lookup according to the words for each search statement. In many scenarios, a post title can be passed to search, and you don't want to see results based on words at that time.

#4 in reply to: ↑ 2 @jchang
3 years ago

Replying to SergeyBiryukov:

Hi there, welcome to WordPress Trac! Thanks for the ticket.

get_posts(array(
  "post_type" => "fruit",
  "s" => "apple orange banana"
));

should search for each term separately, but it does not. It searches the entire string as a phrase.

Just noting that the search ordering logic is slightly more advanced.

Some history here:

  • [4426] / #3177 (WordPress 2.1+) allowed "quoted strings" to be used in searches for exact matches.
  • [25632] / #7394 (WordPress 3.7+) orders search results by relevance, rather than by date.

The ordering logic is as follows:

  • Full sentence matches in post titles.
  • All search terms in post titles.
  • Any search terms in post titles.
  • Full sentence matches in post content.

Each section and any remaining posts are then sorted by date.

Additionally, WP_Query::parse_query() has a 'sentence' argument that controls whether to search by phrase.

So it seems to me that the default search behavior works as intended and documented, I don't see a bug here. As noted above, this can be customized using the posts_search or posts_search_orderby filters.

If left as it is, the "sentence" argument would have no effect on the outcome of a search. The documented behavior says it should search each term individually unless "sentence" is set to true (defaults to false).

Note: See TracTickets for help on using tickets.