6

EDIT 2: Rather than figuring out the real solution I've decided to use a workaround, and am simply setting the default value for book_in_series to '0'. Thanks to @eddiemoya for all his the time he spent looking at this with me!

EDIT: I had a different question with required posting the full code for this archive page / query, if you'd like to see that it's here.

This query is working great, but doesn't include any posts which don't have the meta_key 'book_in_series' (which determines the sort value). What I'd like to have happen is for the books to be sorted by this value if it exists, otherwise come back unordered. Is that possible?

$args = array( 
       'post_type' => 'books', 
       'posts_per_page' => -1,
       'nopaging' => true,
       'surpress_filters' => true,
       'orderby' => 'meta_value',
       'meta_key' => 'book_in_series',
       'order' => 'ASC',
       'post_parent' => $current_series_id,
 );

 $books = new WP_Query( $args);

It seems like this answer from Rarst comes close, but I'm not sure how to adapt it for my circumstances. Custom query with query_posts doesn't show post without certain meta_key

Thanks in advance for your help!

4 Answers 4

5

To be clear, you mean to say that any items that don't have book_in_series key will just be at the bottom and unordered, but the ones that do have it will be at the top and ordered ASC by that key. Right?

meta_query is used to specify what items you want to be returned, orderby is used to specify what to sort those items by. However, meta_key (which is deprecated as a means to specify which posts to get) is needed if you want to use orderby.

You need to add to that query, meta_query that specifies the posts you want. I suggest removing the meta_key while testing it, so that you know meta_key is not reverting to its old behavior. Once you know you have the posts you want, put the meta_key and orderby back in, and it should sort those posts accordingly.

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

http://scribu.net/wordpress/advanced-metadata-queries.html

can I orderby one custom field and meta_query another in the same query

EDIT: A rough attempt at what your query should look like, read comments of explanation.

 $meta_query = array(
    'relation' => 'OR',
    array(
        'key' => 'book_in_series',
        'compare' => 'IN'
    ),
    array(
        'key' => 'book_in_series',
        'compare' => 'NOT IN'
    )
);

$args = array(
    'post_type'        => 'books',
    'posts_per_page'   => -1,
    'nopaging'         => true,
    'subpress_filters' => true,
    'meta_query'       => $meta_query,
    //'orderby'        => 'meta_value',
    //'meta_key'       => 'book_in_series',
    //'order'          => 'ASC',
    'post_parent'      => $current_series_id
);
 $query = new WP_Query( $args );

I've commented out the items related to sorting - if with this query, you get the posts you want, then try to remove the comments and see if it sorts without overriding the meta_query

6
  • Thanks @eddiemoya! I'd looked at a most of those already but I'm still unclear on how to actually code this. The query currently pulls back all the posts I want except the ones that have no book-in-series meta value. The question is how would I get both the ones with the value (sorted) and the ones without? If you want to see the full context of my archive I had to post it in a separate question here: wordpress.stackexchange.com/questions/28424/… Thank you so much for your time!
    – Michelle
    Commented Sep 13, 2011 at 19:43
  • To test this, remove the meta_key from the query all together.That way you wont filter by that meta_key.This should bring you back to everything you want. Now, you need to use meta_query to get that same result (seems silly, i know).So I think you should use multiple meta_queries, both the same except that 'compare' will be 'IN' on one, and 'NOT IN' on the other. I'm not sure how this works pre-3.2, but in 3.2 you can use 'relation' the same way you can in tax_query.So if your on 3.2, your relation should be OR. So you will get any posts that are IN your meta_key OR are NOT IN your meta_key
    – eddiemoya
    Commented Sep 13, 2011 at 22:07
  • I've tried it, but it seems that orderby only works when you explicitly include meta_key (wordpress.stackexchange.com/questions/10941/…). And my understanding is once meta_key is explicitly named, it automatically screens out any posts without that meta_key. Am I missing something?
    – Michelle
    Commented Sep 13, 2011 at 22:40
  • So first of all, I'll presume the meta_query worked correctly and retrieved the posts you wanted. My understanding was the meta_query should override meta_key in terms of filtering posts. The link you posted seems to actually confirm what I am saying. "but you can still use the old method of [meta_key] in addition to the meta_query, as these lines indicate how to sort the resulting query. So yes, you might indicate the same meta_key twice."
    – eddiemoya
    Commented Sep 13, 2011 at 23:04
  • From my understanding (and tests) you actually must use the old meta_key=value or orderby won't work at all (codex.wordpress.org/Class_Reference/…). Luckily I think I've found a way around this altogether - by setting that particular custom field to have a default value of 0. That way the key is always present, and the results come back effectively unsorted. Thanks again for your help!! :)
    – Michelle
    Commented Sep 14, 2011 at 0:01
1

After searching for a while I found a seemingly better solution than needing a default value, which I was about to resort to. I would love to know your thoughts. I ran two queries. One to build an array of posts IDs to exclude and another to display the posts. Based it on info I found here: http://wordpress.org/support/topic/remove-single-post-from-query

$posts_to_exclude_args = array(
            'cat' => '3772', 
            'post_status' => 'publish',
            'orderby' => 'date',
            'meta_value' => 'yes_exclude_this_post',
        );
$posts_to_exclude = new WP_Query( $posts_to_exclude_args );
$to_exclude = array();
while ( $posts_to_exclude->have_posts() ) : $posts_to_exclude->the_post(); 
$to_exclude[] = $post->ID;
endwhile;

$posts_args = array(
         'post__not_in' => $to_exclude,
        'cat' => '-3772', //Exclude slideshow, video
        'post_status' => 'publish',
        'paged'=>$page,
        'posts_per_page' => 10,
        'orderby' => 'date',
    );

$posts = new WP_Query( $posts_args );
2
  • 1
    Just for the record: the commas at the last key-value-pair in $post_args & $posts_to_exclude_args are syntax errors. I'm just saying. (didnt test) Commented Mar 6, 2013 at 23:00
  • This is not a scalable solution. If you have a large quantity of posts these two queries will be very slow.
    – forsvunnet
    Commented Feb 13, 2015 at 10:09
1

Like many others, I was having the same problem, where setting the meta_key for sorting purposes was not returning those without a value.

I needed to sort by a custom (sortable) drag and drop order, which was saved to a custom sort field, and I needed all of the unsorted to go to the bottom of the list.

Since I stored a number, it was important to use meta_value_num for natural sorting 1,2,10,12,20 instead of 1,10,12,2,20.

$args = array( 
    'posts_per_page' => -1, 
    'post_status' => 'publish',
    'meta_query' => array(
        'relation' => 'OR',
        array(
            'key' => 'custom_sort',
            'compare' => 'EXISTS'
        ),
        array(
            'key' => 'custom_sort',
            'compare' => 'NOT EXISTS'
        )
    ),
    'orderby' => 'meta_value_num title',
    'order' => 'ASC',
));

$query = new WP_Query($args);

Note: You can nest the entire meta_query and query for more stuff while still pulling all fields.

$args = array( 
    'posts_per_page' => -1, 
    'post_status' => 'publish',
    'meta_query' => array(
        'relation' => 'AND',
        array(
            'key' => 'color',
            'compare' => ='',
            'value' => 'red'            
        )
        array(
            'relation' => 'OR',
            array(
                'key' => 'custom_field',
                'compare' => 'EXISTS'
            ),
            array(
                'key' => 'custom_field',
                'compare' => 'NOT EXISTS'
            )
        )
    ),
    'orderby' => 'meta_value_num title',
    'order' => 'ASC',
));

$query = new WP_Query($args);

I believe that as of Wordpress 4.1, you no longer need to add meta_key when sorting by a custom field. (it adds a left join for that field in the sql).

I was lead to my solution by the comments on this answer. https://wordpress.stackexchange.com/a/126928/15209

0

Rather than figuring out the real solution I decided to use a workaround, and am simply setting the default value for book_in_series to '0'.

Your Answer

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

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