19

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:

21

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

http://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters

So, that query should work on the current Wordpress version.

9

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.

1

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

https://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_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,
            'compare' => '<=',
            'type' => 'DECIMAL',
        ),
    )
),

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.