query_posts sort in multiple directions

OrderBy

The query functions, like get_posts(), query_posts() call a new WP_Query inside – they’re just wrappers.

The more important thing is what goes on in the class WP_Query. Specifically inside WP_Query -> get_posts(). When you add an orderby argument, then the following happens:

  1. WP checks if it set. If not, then it uses the $wpdb->posts.post_date and appends the `order value to it.
  2. If you set it to 'none', then there’s no order applied.
  3. In every other case, the order will be used.

But… there’re “allowed orderby” values:

$allowed_keys = array('name', 'author', 'date', 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand', 'comment_count');

For meta key/value pairs, there’s a special case: If the meta key isn’t empty, the meta_key value is added to the allowed keys, as well as meta_value and meta_value_num.

The function than explodes the orderby string to an array and loops through. Everything that matches gets added to a new array, which is then imploded (separated by a comma) after the loop and added to the SQL query string. If the resulting array was empty, then – again – the "$wpdb->posts.post_date" followed by the order will be taken. If that is empty too, then you’ll see the same result as with none.

So if you’re adding anything like a meta key and a meta value, then you should get the following added to your query:

"$wpdb->postmeta.meta_value,$wpdb->postmeta.meta_value,$wpdb->posts.post_title"

Post Type(s)

Your post type arg gets added to the WHERE clause like this:

 AND $wpdb->posts.post_type="portfolio-item"

What I think is wrong in here:

  1. You can’t add asc desc as order statement. The order must be either ASC or DESC (upper-/lowercase doesn’t matter). This won’t work and will likely break.
  2. I’m pretty sure, that 'portfolio-item' isn’t the actual post type name. I guess it’s just portfolio. Be sure to call whatever the post type is named inside

    var_dump( array_keys( (array) $GLOBALS['wp_post_types'] ) );
    
  3. caller_get_posts is a pre 3.1 argument. You should already get a note at the top/beginning of your code, as the following _deprecated_argument() is called before any query string is even built:

    "caller_get_posts" is deprecated. Use "ignore_sticky_posts" instead.
    

Leave a Comment