33

I am curious whether Wordpress is able to run nested meta_query, with each having different relation keys? As of Wordpress 3.0, tax_query is able to perform this function; I'm wondering whether this has an equivalent with meta_query.

$results = query_posts( array(
    'post_type' => 'event_id',
    'meta_query' => array(
        'relation' => 'AND',
        array(
            'relation' => 'OR',
            array(
                'key' => 'primary_user_id',
                'value' => $user_id
            ),
            array(
                'key' => 'secondary_user_id',
                'value' => $user_id
            )
        ),
        array(
            'key' => 'date',
            'value' => array( $start_date, $end_date ),
            'type' => 'DATETIME',
            'compare' => 'BETWEEN'
        )
    )
) );

References:

3 Answers 3

34

The question was for Wordpress 3.0, but just in case someone has the same question for a more recent version, from Wordpress Codex:

"Starting with version 4.1, meta_query clauses can be nested in order to construct complex queries."

https://developer.wordpress.org/reference/classes/wp_query/#custom-field-post-meta-parameters So, that query should work on the current Wordpress version.

19

Meanwhile this is possible, see documentation with example and explanation:

Old link: https://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters Update: 2021, new link: https://developer.wordpress.org/reference/classes/wp_query/#custom-field-post-meta-parameters

and another example https://wordpress.org/support/topic/wp_query-with-multiple-meta_query/#post-9410992

'meta_query'  => array(
    'relation' => 'OR',
    array(
        'relation' => 'AND',
        array(
            'key'     => '_price',
            'value'   => 1,
            'compare' => '>=',
            'type' => 'DECIMAL',
        ),
        array(
            'key'     => '_price',
            'value' => 3000,
            'compare' => '<=',
            'type' => 'DECIMAL',
        ),
    ),
    array(
        'relation' => 'AND',
        array(
            'key'     => '_price',
            'value'   => 3001,
            'compare' => '>=',
            'type' => 'DECIMAL',
        ),
        array(
            'key'     => '_price',
            'value' => 6000, //fixed <= to =>
            'compare' => '<=',
            'type' => 'DECIMAL',
        ),
    )
),
4
  • This is also a good reference but I apprecaite the full description here too developer.wordpress.org/reference/classes/wp_query/… Commented Jun 11, 2021 at 13:59
  • The codex.wp is beeing moved to developer.wp so yes I did add the correct reference at the time. At this moment in time is is indeed developer.wordpress.org/reference/classes/wp_query/… i Commented Jun 15, 2021 at 12:11
  • How do I add three conditions with an "AND"? Commented Dec 21, 2021 at 0:21
  • @Si8 one AND would suffice for adding A AND B AND C . the AND is one level higher then the others Commented Nov 10, 2023 at 14:26
10

That seems to be impossible. Please someone correct me if I'm wrong.

The meta_query parameter will actually be transformed into a WP_Meta_Query object, and the relation verification won't go deeper in wp-includes/meta.php, and occurs just once in the top level:

if ( isset( $meta_query['relation'] ) && strtoupper( $meta_query['relation'] ) == 'OR' ) {
    $this->relation = 'OR';
} else {
    $this->relation = 'AND';
}

A possible solution for this is to build your own JOIN for this query.

$query = new WP_Query( array(
    ...
    'my_meta_query' => true,
    'suppress_filters' => false
) );

add_filter( 'posts_join', 'my_meta_query_posts_join', 10, 2 );
function my_meta_query_posts_join( $join, $query ) {

    if ( empty( $query->query_vars['my_meta_query'] ) )
        return $join;

    global $wpdb;

    $new_join = "
        INNER JOIN {$wpdb->postmeta} pm1 ON 1=1
            AND pm1.post_id = {$wpdb->posts}.ID
            AND pm1.meta_key = '_some_meta_key'
            AND pm1.meta_value = 'some_value'
    ";

    return $join . ' ' . $new_join;
}

And if you need further verifications and rules, you can also use the posts_where filter.

2
  • 3
    Seems to be the same approach @scribu recommends on Core Trac: core.trac.wordpress.org/ticket/20312 Commented May 29, 2014 at 19:49
  • @AndrewOdri it's the same but it's not =) Commented Oct 6, 2015 at 17:14

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.