WordPress’s built-in search queries the post_title and post_content columns of the wp_posts table using a LIKE operator. This is functional but limited: it does not search custom fields (post meta), it searches all public post types by default, it orders results by date rather than relevance, and it cannot be scoped to a specific category or taxonomy term. All of these behaviours can be customized through pre_get_posts and the posts_search filter. Restricting search to specific post types is the most common requirement, followed by including post meta in the search query. Including meta in the search requires a custom SQL JOIN and WHERE extension via posts_join and posts_search filters, with a DISTINCT fix via posts_distinct to avoid duplicate results from multiple matching meta rows.
Problem: WordPress search returns results from all post types and does not search custom field values — visitors searching for a product SKU, document number, or ACF field value get no results even when the data is in the database.
Solution: Use pre_get_posts to restrict search to specific post types. Extend the search to include post meta with posts_join, posts_search, and posts_distinct filters.
Restrict search to specific post types:
<?php
add_action( 'pre_get_posts', 'restrict_search_post_types' );
function restrict_search_post_types( $query ) {
if ( ! is_admin() && $query->is_search() && $query->is_main_query() ) {
$query->set( 'post_type', [ 'post', 'product', 'resource' ] );
}
}
Extend search to also match a specific post meta key:
<?php
add_filter( 'posts_join', 'search_meta_join', 10, 2 );
add_filter( 'posts_search', 'search_meta_where', 10, 2 );
add_filter( 'posts_distinct', 'search_meta_distinct', 10, 2 );
function search_meta_join( $join, $query ) {
global $wpdb;
if ( ! $query->is_search() || $query->is_admin() ) return $join;
return $join . " LEFT JOIN {$wpdb->postmeta} AS pm_search
ON ({$wpdb->posts}.ID = pm_search.post_id
AND pm_search.meta_key = 'product_sku') ";
}
function search_meta_where( $search, $query ) {
global $wpdb;
if ( ! $query->is_search() || $query->is_admin() || empty( $search ) ) return $search;
$term = $wpdb->esc_like( get_query_var( 's' ) );
return $search . $wpdb->prepare(
" OR (pm_search.meta_value LIKE %s)",
'%' . $term . '%'
);
}
function search_meta_distinct( $distinct, $query ) {
if ( $query->is_search() && ! $query->is_admin() ) {
return 'DISTINCT';
}
return $distinct;
}
NOTE: Searching post meta with LIKE JOINs does not scale well on large databases — a full-table scan of wp_postmeta on a site with millions of meta rows will be very slow. For production sites with significant traffic and large datasets, a dedicated search solution like ElasticSearch with the ElasticPress plugin, or SearchWP, is a better choice than SQL JOINs on meta tables.