Deluxe Blog Tips About Projects

Search ALL Custom Fields in WordPress

By default, WordPress searches only in post title and post content, and it's not enough when you have many additional data in custom fields (post meta) and you want that data is searchable as well. This post will show you how to search in all custom fields to get more results.

If you want to search only for ONE or TWO custom fields, you should use built in WordPress meta_query variable.

Search For Few Custom Fields

// Query arguments
$args = array(
    'post_type' => 'post',
    'post_status' => 'publish',
);

$args['meta_query'][] = array(
    'key' => 'city',
    'value' => $city,
    'compare' => 'LIKE',
);
$args['meta_query'][] = array(
    'key' => 'state',
    'value' => $state,
    'compare' => 'LIKE',
);

$query = new WP_Query( $args );

if ( $query->have_posts() ): while ( $query->have_posts() ) : $query->the_post();

// Do loop here

endwhile; endif;

But that method is not suitable if you want to search ALL custom fields. Because if you have many custom fields, the query will be huge, and thus WordPress takes a very very long time to execute the query. In my test with about 10 custom fields, it takes more than 1 minutes without any results!

Search All Custom Fields

So, here's my solution for search all custom fields. Instead of using meta_query to build complex query, I'll use a simple SQL query to get all the needed post_id, and then everything is straight forward:

global $wpdb;

// If you use a custom search form
// $keyword = sanitize_text_field( $_POST['keyword'] );

// If you use default WordPress search form
$keyword = get_search_query();
$keyword = '%' . $wpdb->esc_like( $keyword ) . '%'; // Thanks Manny Fleurmond

// Search in all custom fields
$post_ids_meta = $wpdb->get_col( $wpdb->prepare( "
    SELECT DISTINCT post_id FROM {$wpdb->postmeta}
    WHERE meta_value LIKE '%s'
", $keyword ) );

// Search in post_title and post_content
$post_ids_post = $wpdb->get_col( $wpdb->prepare( "
    SELECT DISTINCT ID FROM {$wpdb->posts}
    WHERE post_title LIKE '%s'
    OR post_content LIKE '%s'
", $keyword, $keyword ) );

$post_ids = array_merge( $post_ids_meta, $post_ids_post );

// Query arguments
$args = array(
    'post_type'   => 'post',
    'post_status' => 'publish',
    'post__in'    => $post_ids,
);

$query = new WP_Query( $args );

if ( $query->have_posts() ): while ( $query->have_posts() ) : $query->the_post();

// Do loop here

endwhile; endif;

In the code above, I show the code to get search query for custom search form or default WordPress search form, just comment/uncomment them to fit your requirements.

The code above search for the presence of the keyword in ALL custom fields and in the post title, post content. The results are arrays of post IDs. Then we built the custom query, using the built-in WP_Query class, this way we can use template tags for easy display post information.

You can paste this code into the search.php of your theme to replace the built-in search functionality. Or you can paste into the custom search page.

The code runs quite quickly. The extra 2 simple query doesn't hurt your website performance much. And we don't need to worry about it. But if you find any optimization for this method or a better solution, please let me know in the comments!

Update 1: Add like_escape for $keyword. Thanks Manny.

Update 2 (Feb 1st, 2013): To make the code works with pagination, add this line to the code above:

$args['paged'] = max( get_query_var( 'paged' ), 1 );
$query = new WP_Query( $args );

Update 3 (July 24th, 2015): like_escape is deprecated. Use $wpdb->esc_like instead.