I have 2 custom fields that I would like to do a meta query on for a custom post type:


The outcome that I am looking for is

(start_date >= 1332115200 AND status = 1) OR (status = 2)

Is this possible to do with WP_Query?

2 Answers 2


No, meta_query does not support these sorts of complex clauses in a sequence.

There are a couple of ways to work around this limitation.

  • One is to filter posts_where_paged and modify the SQL manually. I just spent a couple minutes playing with this option, and it's not very straightforward - you'll have to write a pretty sophisticated preg_replace() to get the parentheses grouped right, etc.

  • A more promising option is to get a whitelist of post ids manually, and then feed the results to the post__in parameter of WP_Query:

    global $wpdb;
    $post_ids = $wpdb->get_col( $wpdb->prepare( "
        SELECT post_id 
        FROM $wpdb->postmeta.pm 
        INNER JOIN $wpdb->postmeta.pm2 ON (pm.post_id = pm2.post_id)
            (pm.meta_key = 'status' AND pm.meta_value = '1' 
            AND pm2.meta_key = 'start_date' AND pm2.meta_value >= '1332115200')
            (pm.meta_key = 'status' AND pm.meta_value = '2')
    " ) );
    $query_args = array( 'post__in' => $post_ids ); // plus whatever else you want
    $my_query = new WP_Query( $query_args );

    When WP_Query assembles the SQL, your $post_ids get turned into a clause like: AND ID IN (1,2,3), which acts like a whitelist for whatever other parameters you pass to WP_Query.

Note that either way, this query is not going to be all that fast, since it requires some loose type casting on unindexed meta_value. Cache wisely :)

  • Thanks Boone. I will implement the second solution. Curious, how do you cache queries? Mar 20, 2012 at 0:52
  • 1
    WP's Transients API is a nice way to do it, and it only takes a couple extra lines of code. wpbeginner.com/wp-tutorials/… is a decent introduction. The important part is to be sure that, in addition to setting a reasonable expiry date, you are sure to bust the cache (delete_transient()) when a new post is published with a 'start_date' or 'status' that needs to be counted in your query. Mar 20, 2012 at 1:22
  • That's exactly what I had in mind. Thanks so much!!! Mar 20, 2012 at 2:07

I think your answer is on this page, read the section, Order & Order By Paramaters.

In simple terms, ordering by meta_value means your query will have something like this in it

'orderby' => 'meta_value', 'meta_key' => 'your_meta_key'

... but to do something like the example you gave is a bit more tricky though I think you'll find it's actually explained under the heading "Multiple Custom Field Handling:". Read that in conjunction with the second part of "Custom Field Parameters" and you should eventually get it.

Pay attention to the arrays. I think you should end up with 3 nested arrays in your case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.