webguy
webguy

Reputation: 692

wordpress meta_query sorting on two meta values and title

Trying to sort a CPT named 'products' using the meta values 'products_categories' and 'products_item_order' and the standard WP 'title' value.

Here's my code

  $args = array(
    'post_type' => array('products'),
    'posts_per_page' => "12",
    'paged' => $paged,
    'meta_query' => array(
        'relation' => 'OR',
        'item_cat' =>array(
                'key'     => 'products_categories',
                'value'   => serialize( strval( $cat ) ),
                'compare' => 'LIKE'
            ),
        'item_order' => array(
            'key' => 'products_item_order',
            'compare' => 'EXISTS',
            )
    ),
    'orderby' => 'item_order title',
    'order'   => 'ASC',
);

I want to sort the posts that have a 'products_item_order' first, and then list the remaining, unnumbered ones alphabetically.

The problem is the 'item_order' clause is not limiting my query to the category. If a post in category 'dog' has a 'products_item_order' value, the 'dog' post is appearing in queries for 'cat' and any other animal. What I need is a way to limit the 'item_order' clause so it only applies to posts in 'item_cat'.

Meta_query orderby changed significantly in WP 4.2+ and I can't find any examples or documentation that fill in specifically what I'm missing.

Any help most appreciated!

Upvotes: 0

Views: 1110

Answers (1)

Boone Gorges
Boone Gorges

Reputation: 181

The problem is the 'item_order' clause is not limiting my query to the category.

This is because your meta_query clauses are joined by OR. A post with 'dog' and 'products_item_order' will match even when $cat = 'cat' because the post will match the second disjunct.

I think you need a more complex query that spells out all the possible cases. Probably something like:

'meta_query' => array(
    'relation' => 'OR',
    'item_cat_with_order' => array(
        'relation' => 'AND',
        'item_cat_1' => array(
            'key' => 'products_categories',
            // etc
        ),
        'item_with_order' => array(
            'key' => 'products_item_order',
            'compare' => 'EXISTS',
        ),
    ),
    'item_cat_without_order' => array(
        'relation' => 'AND',
        'item_cat_2' => array(
            'key' => 'products_categories',
            // etc
        ),
        'item_without_order' => array(
            'key' => 'products_item_order',
            'compare' => 'NOT EXISTS',
        ),
    ),
),
'orderby' => 'item_with_order title',

This logic should suffice to ensure that you're only getting the posts you want. I don't know that the 'orderby' clause is going to work exactly as you expect it to; if not, I'm guessing that WP_Query doesn't support this kind of logic (it's hard without doing an OUTER JOIN and then running some deduplication). To get the order right, you might need to run two separate queries and then thread the results together, or write your own SQL.

Upvotes: 1

Related Questions