WordPress.org

Make WordPress Core

Opened 2 months ago

Last modified 2 months ago

#43867 new feature request

Introduce the ability to control which fields are searched in a search query

Reported by: johnbillion Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version:
Component: Query Keywords: has-patch has-unit-tests
Focuses: Cc:

Description

The s argument of the WP_Query::parse_query() method always searches the post_title, post_excerpt, and post_content fields, with no way of controlling this apart from using the posts_search filter and adjusting the SQL manually.

It would be good if it was possible to specify which fields are searched when performing a query, for example via a search_fields argument or similar.

My use case is for a REST API driven autocomplete field which allows a user to search post titles without a large number of less relevant results appearing due to the search spanning post content too.

Attachments (1)

43867.diff (15.2 KB) - added by birgire 2 months ago.

Download all attachments as: .zip

Change History (5)

#1 @birgire
2 months ago

That sounds like a useful feature.

For comparison, the way it's done in WP_User_Query is with the search_columns query argument:

https://core.trac.wordpress.org/browser/tags/4.9.5/src/wp-includes/class-wp-user-query.php#L163

and also the user_search_columns filter:

https://core.trac.wordpress.org/browser/tags/4.9.5/src/wp-includes/class-wp-user-query.php#L532

where the default search fields are (marked with x):

x ID
x user_login
  user_pass
x user_nicename
x user_email
x user_url
  user_registered
  user_activation_key
  user_status
x display_name

Similar the WP_Site_Query uses the search_columns query argument:

https://core.trac.wordpress.org/browser/tags/4.9.5/src/wp-includes/class-wp-site-query.php#L137

and the site_search_columns filter, with the default search columns:

x domain
x path 
  ... 

https://core.trac.wordpress.org/browser/tags/4.9.5/src/wp-includes/class-wp-site-query.php#L502

So taking a similar approach as above, we could support:

  • the search_columns query argument
  • and the post_search_columns or search_columns filter.

with the default columns as:

x post_title
x post_excerpt
x post_content
  ...
Last edited 2 months ago by birgire (previous) (diff)

#2 @birgire
2 months ago

The parse_search() seems like a good place for the filter:

$search_columns = apply_filters( 'post_search_columns', $search_columns, $q['s'], $this );

where we can loop over the columns with e.g.:

$searches = array(); 
foreach( (array) $search_columns as $search_column ) {
	$searches[] = $wpdb->prepare( "({$wpdb->posts}.{$search_column} $like_op %s)", $like ); 
}

if( $searches ) {
	$search .= "{$searchand}(" . join( " $andor_op", $searches ) . ')';
}

within the search terms loop.

I will look into this further with unit tests.

@birgire
2 months ago

#3 @birgire
2 months ago

43867.diff is a first iteration with unit tests in tests/query/searchColumns.php.

Some notes on this first iteration:

  • It uses the default search columns: post_title, post_excerpt and post_content.
  • It uses the supported search columns: post_title, post_excerpt and post_content. We could consider expanding this further.
  • It uses the default search columns as a fallback for empty input: 'search_columns' => array().
  • It uses the default search columns as a fallback for an existing but not supported search field, e.g. 'search_columns' => array( 'post_name' ).
  • It ignores non-existing or non supported search column(s) together with supported search column(s), e.g. 'search_columns' => array( 'post_title', 'post_name' ) is the same as 'search_columns' => array( 'post_title' ).
  • Introduces the post_search_columns filter. We restrict it to the supported search columns, to avoid any kind of column names in the SQL query.

#4 @birgire
2 months ago

  • Keywords has-patch has-unit-tests added; needs-patch needs-unit-tests removed
Note: See TracTickets for help on using tickets.