1

Querying either of the 2 fields individually gives the expected result (posts are displayed).

But, when both fields are included in the query (ex = 'foo' and 'bar' shown in below example), then no posts are displayed.

function do_stuff( ) {
    global $wpdb;
    return "
    AND ($wpdb->postmeta.meta_key = 'foo' 
    AND $wpdb->postmeta.meta_value = '1') 
    AND ($wpdb->postmeta.meta_key = 'bar' 
    AND $wpdb->postmeta.meta_value = '1')";
}

add_filter( 'posts_where', 'do_stuff' );

Here is a print_r of the WP_Query:

[query] => Array
    (
        [post_type] => testPostType
        [pagination] => 1
        [posts_per_page] => 10
        [paged] => 1
    )

[request] => SELECT SQL_CALC_FOUND_ROWS  wp_posts.ID FROM wp_posts  LEFT JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id  WHERE 1=1 
AND (wp_postmeta.meta_key = 'foo'
AND wp_postmeta.meta_value = '1')
AND (wp_postmeta.meta_key = 'bar'
AND wp_postmeta.meta_value = '1')  ORDER BY wp_posts.post_date DESC LIMIT 0, 10
[posts] => Array
    (
    )

)

Have I made a logic error in the sql? How can I get the posts to display as expected?

  • Can you add the SQL generated after your filter has been added? – Chris_O Aug 24 '13 at 7:09
  • Thanks Chris_O, I added the results of doing a print_r to the question. Please let me know if there is more I can provide. – edt Aug 24 '13 at 7:40
  • If you use OR in the where condition instead of AND for meta fields then is the result getting displayed? – Vinod Dalvi Aug 24 '13 at 8:28
2

Think about your query. You are asking that $wpdb->postmeta.meta_key be both "foo" and "bar". That will never happen. If you ran this in a context where you'd get to read MySQL debugging data (PhpMyAdmin's SQL console will do this) you would probably see a warning about an "impossible where clause". You need to JOIN on the post meta table for one of the values, but as near as I can tell WP_Query will do this too.

$args = array(
  'post_type' => 'post',
  'meta_query' => array(
    array(
      'key' => 'foo',
      'value' => '1',
    ),
    array(
      'key' => 'bar',
      'value' => '1',
    )
  )
);
$query = new WP_Query( $args );

If you look at the SQL for that query-- var_dump($qry->request);-- you will see the JOIN I am talking about.

You can do the same with a filter on pre_get_posts.

function set_post_meta_wpse_111456($qry) {
  $qry->set(
    'meta_query',
    array(
      array(
        'key' => 'foo',
        'value' => '1',
     ),
     array(
       'key' => 'bar',
       'value' => '1',
     )
  );
}
add_action('pre_get_posts','set_post_meta_wpse_111456');

WARNING: As written above, that will effect every query on the site so you do need to add conditions to limit where that runs.

| improve this answer | |
  • Thanks s_ha_dum, I thought something was off with my query. Could your solution also work with more complex queries, such as: Find all posts where foo equals 1 OR 2, AND bar equals 3 OR 4 AND baz is any value between 10 to 20? – edt Aug 24 '13 at 16:06
  • Yes, WP_Query will support more complicated queries. Take a look at the docs. If I understand you, it will support the conditions you want though it does not support all of the very complicated queries that people sometimes request. – s_ha_dum Aug 24 '13 at 16:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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