Adding meta-field search to regular WordPress search
The basic WordPress search looks for the specified text in the title, content, and excerpt (in the post_title, post_content, post_excerpt fields). Below is how to add a search to these basic search fields and to the meta-field. In other words, we will solve the task of how to add a search to a specified meta-field in the standard post search.
See also: Adding taxonomy term to post search
Task solution using the posts_clauses hook
add_filter( 'posts_clauses', 'km_metadata_search' ); # Adding meta-field search to the basic WordPress search function km_metadata_search( $clauses ){ global $wpdb; if( ! is_search() || ! is_main_query() ) return $clauses; $clauses['join'] .= " LEFT JOIN $wpdb->postmeta kmpm ON (ID = kmpm.post_id)"; $clauses['where'] = preg_replace( "/OR +\( *$wpdb->posts.post_content +LIKE +('[^']+')/", "OR (kmpm.meta_value LIKE $1) $0", $clauses['where'] ); // if searching in a specified meta-field is needed //$clauses['where'] .= $wpdb->prepare(' AND kmpm.meta_key = %s', 'my_meta_key' ); $clauses['distinct'] = 'DISTINCT'; // debugging the final query 0 && add_filter( 'posts_request', function( $sql ){ die( $sql ); } ); return $clauses; }
What the code does:
Step 1: Adding metadata table to the query (JOIN)
Extend the basic posts table by adding the metadata table to it. This is necessary in order to specify the field in the metadata table to search. The field is specified in the second step.
Step 2: Modifying the query selection (WHERE)
Add to the WHERE part of the query so that the "standard search" also searches in all post meta-fields.
Step 3: Modifying the query selection (DISTINCT)
Due to the LEFT JOIN in step 1, duplicates may appear. Let's get rid of them.
Task solution using hooks: posts_join, posts_where, posts_distinct
add_filter( 'posts_join', 'cf_search_join' ); add_filter( 'posts_where', 'cf_search_where' ); add_filter( 'posts_distinct', 'cf_search_distinct' ); # Joins the posts and metadata tables. function cf_search_join( $join ){ global $wpdb; if( is_search() ) $join .= " LEFT JOIN $wpdb->postmeta ON ID = $wpdb->postmeta.post_id "; return $join; } # Specifies which meta-fields and values to search for in the WHERE section. function cf_search_where( $where ){ global $wpdb; if ( is_search() ) { $where = preg_replace( "/\(\s*$wpdb->posts.post_title\s+LIKE\s*(\'[^\']+\')\s*\)/", "($wpdb->posts.post_title LIKE $1) OR ($wpdb->postmeta.meta_value LIKE $1)", $where ); } return $where; } # Prevents duplicates in the selection. function cf_search_distinct( $where ){ return is_search() ? 'DISTINCT' : $where; }
Filters will not work if the suppress_filters parameter is enabled for the query.
The filter will not work for the get_posts() query - this parameter is enabled by default there!
-
The code was created based on the article: adambalee.com