31

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

31

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.

17

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
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

Your Answer

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

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