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.


  1. If you want to get results like WP search does. I’d recommend you break search terms into words, for example:

    “Hello World” will becomes “%Hello%World%” instead of “%Hello World%” (“%” between each word)

    The “%Hello World%” option, only match with text contains “Hello World”, for example: “Hello World, this is my Justin Bieber”, “Justin Bieber, Hello World” or “Justin Bieber hello world from US”

    The “%Hello%World%” option will match with text contains both “Hello” and “World”, and “World” should after “Hello”, so it matches with three example above and for example, “When I was born, I said ‘Hello’ to this ‘World'”

  2. Thank you – great code!

    I also had the problem:
    When the search term ($keyword) is not found,
    the code outputs all posts as found (I still do not know why!?).

    I wanted to check if results are found or not.
    If results are found: Output the results.
    If no results are found: Output “Sorry, no results found”

    My solution:
    Look if there are entries in the array &args in the field ‘post__in’

    if (!empty($args[‘post__in’]) )
    { // query, output }
    else {echo ‘Sorry, no results found.’;}

    -) What do you think?
    -) Why outputs the original code all posts as found if there are no posts found?
    -) How to implement a “exact phrase search” – like “sentence=1” in WP search?

  3. Hi! Thank you for share it, is a very usefull script. Works fine.
    But I have a issue: I did a custom search form, with my taxonomy through ‘select’, part of the code:
    Seleccionar Colecciones
    $theterms = get_terms('coleccion', 'orderby=name');
    foreach ($theterms as $term) :
    echo "slug.”‘”.($_GET[‘coleccion’] == $term->slug ? ‘ selected=”selected”‘ : ”).”>”.$term->name.”\n”;

    I tried deleting the part of $_GET and changing it, but doesn’t work if I use my select for filter the search, instead only works as a normal search (input text, etc)
    How I can do for to use the select filter properly?

    Thanks for any help!

  4. This has been a great help allowing me to extend the functionality of something I’ve been working on.

    With that said, I’ve hit a snag that I can’t seem to resolved.

    The problem:

    If someone searches:

    – a blank search, or
    – a search that has no possible results (something stupid, like ‘skjdhfksdhasighudfglkjsdflkjgsdfg’)

    The results return my home page.

    This wouldn’t be a problem if I could tell it to return something different but for the life of me I can’t figure it out.

    I believe this is because of the way the query is being determined, straying from the core WordPress functionality (which is understandable given the functionality this code is providing).

    What I’d like:

    At the very basic I just need a way to determine if the user search something that was a) blank, or b) no matches were returned. From here I can do what I need to do. I’m OK with it showing my home page, I just need to be able to return a message letting the user know that the search was blank or unmatched.

    What I’m working on can be found here: (although it is slow at the moment as it isn’t optimized yet).

    Not sure if anyone has run into any similar issues.

  5. Hi, I’ve been looking for ages for a good way to do this but I’m a bit of a beginner when it comes to wordpress and php in general so I was wondering if you could tell me where this needs to go in search.php? Probably a really stupid question but I just can’t work it out!


  6. Hey, this is really brilliant but it only works while searching for 1 word. If i search for 2 or more words no results are found.

    Any Ideas why?

  7. Amazing! cheers :)

  8. Thanks a lot of this. I couldn’t get it to work at first but that was because I was expecting to find results from within my custom posts types – the code above only searches posts. Just had to change the first line in the $args array to something like this:

    'post_type' => array('page', 'post', 'solution'),

    Thanks again!

  9. How would you search all the post meta but not search one specific meta_key value?

    For example, you have 20 custom fields – you only want to search 19 of the values of those custom fields.

  10. This is really helpful, thank you. I’ve got this working perfectly except that I can’t get pagination to work with this. No matter do, anything beyond page 1 give pulls up no posts even though there are some. I am using kriesi_pagination but even if I swap that out with the default WP pagination, it doesn’t pull up anything. Any thoughts on how I might get this to work? Thanks again for a great post.

    • I’m having exactly the same problem. I can’t get pagination to work. Even if the number of pages are displayed correctly, posts_nav_link are not showing.

      Thanks for this post, it has been really helpful :)

      • HI.

        Did anyone manage to get the pagination to work? If yes, please share how.



        • The reason I was having a problem is because I was using this in the WordPress search page and the search parameter was causing the issue. I created a new custom search page and used this query as my custom search and the pagination issue was resolved. It’s been a while, so I don’t remember all the details, but that was the basic issue.

          I hope it helps.

  11. Hi !!
    That solution is what I was looking for since 2 weeks.
    I need to create a custom fields hand made query to check in 28 fields.
    Is not for a real state site but something with a similar custom search in fields form.
    I understand that this way is best than wp meta_query because it can’t solve my problem due mysql dead each time i launch the multiple custom fields query using meta_query.

    I’m not using WordPress search form. I’m using a custom form and the search page recibe values to ask for.
    But I have a problem with that query:

    $post_ids_meta = $wpdb->get_col( $wpdb->prepare( "
    SELECT DISTINCT post_id FROM {$wpdb->postmeta}
    WHERE 1 = 1 // optional
    AND (meta_key = 'type' AND meta_value LIKE '$f_type')
    AND (meta_key = 'morphology' AND meta_value LIKE '$f_morphology')
    " ) );

    Work’s fine if I only ask for one meta, no matter what meta but if I ask for more than one meta it isn’t works.

    Any help please? :(

    Sincerely thanks for show me the way :)

    • rilwis

      December 12, 2012 at 10:32 PM

      Looks like your SQL statement is not correct. You should use LIKE ‘%something%’ instead of LIKE ‘something’.

      You can look at my code to see how I implemented it:

      $f_type= '%' . like_escape( $f_type ) . '%';

      • Hi rilwis!

        Sorry, I didn’t explain that before that code I prepare the vars ($) to use in Like forms :P

        $f_type = “%”.like_escape( $f_type ).”%”;

        Even try with directly values like :

        AND (meta_key = 'type' AND meta_value LIKE '%Normal%')

        but with same results :(

        Thanks rilwis!

        • rilwis

          December 12, 2012 at 11:21 PM

          Just looked at that again and found that the conditions are not correct. You use AND but it actually OR, like this:

          WHERE 1=1 AND ( (condition_for_meta1) OR (condition_for_meta2) )

          Or you better remove 1=1 to make the conditions clearer and you’ll see how it works.

  12. You may need to use the like_escape function to sanitize your keyword. Can never be too careful:

    $keyword = “%”.like_escape( $keyword ).”%”;

  13. In fact, there is a workaround that doesn’t require any plugins or scripting. If you copy the content of your Custom Fields at the end of the Post text and COMMENT it (), WordPress standard Search function will sill find it! ;-)

  14. I copied and pasted your 2nd code into deafault template twentyeleven search.php file but it wont work. Can you explain please?

  15. You should escape your query with $wpdb->prepare.

    Great tip. Searching “all” is often usefull.

    • Tran Ngoc Tuan Anh

      April 11, 2012 at 9:00 AM

      Thanks for pointing that out! Actually, I wanted to use prepare method, too. But it was confused when putting %d in the LIKE statement.

      • Yeah. Try $keyword = ‘%’ . $keyword . ‘%’; on line 8

        prepare() add ” so your % must be inserted before.

Leave a Reply