Opened 4 years ago
Last modified 4 years ago
#54853 new defect (bug)
Search only searching phrases and not searching individual terms
| Reported by: | jchang | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | Query | Version: | 5.8.3 |
| Severity: | normal | Keywords: | needs-patch |
| Cc: | Focuses: |
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
@
4 years ago
#2
follow-up:
↓ 4
@
4 years ago
- Severity blocker → 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.
#3
@
4 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
@
4 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_searchorposts_search_orderbyfilters.
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).
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
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; }