A more powerful ORDER BY in WordPress 4.0

orderby is the argument passed to WP_Query to tell it what column to sort on when it is creating the ORDER BY clause for its generated SQL. The default value for orderby is post_date.

The default sort order for a column in MySQL is ASC (ascending), with smallest values first. For the reverse, DESC is used. You can sort on multiple columns, and each column can have its own sort order.

The default value for the order argument inside WP_Query is DESC. ~23% of the internet automatically queries posts in reverse chronological order because of this. order can only be one of 2 values: DESC or ASC.

orderby accepts a string, representing a column on which to sort:

$q = new WP_Query( array( 'orderby' => 'post_title' ) );

// or an alias
$q = new WP_Query( array( 'orderby' => 'title' ) );

Both will produce an ORDER BY clause like:

ORDER BY post_title DESC

orderby will also parse a space-delimited set of columns:

$q = new WP_Query( array( 'orderby' => 'title author' ) );

Prior to 4.0, there was a problem: the value for order would only be applied to the last value that you passed in that space-delimited list, producing an ORDER BY clause like:

ORDER BY post_title, post_author DESC

Remember that the default sort order for a column in MySQL is ASC, so queries like that can get weird real fast and produce unexpected/unpredictable results. If no value is passed for order for a column in the generated SQL, the column will be sorted in ASC order. This was not so clear to all developers. #26042 was a joy to debug.

In 4.0, when you pass a space-delimited set of values, your sole value for order will be applied to all of your values that are parsed for orderby. This was fixed in [28541].

So that’s pretty good, but it doesn’t allow you granular control over the sort order for each column. The syntax doesn’t allow itself much room for extending.

Enter [29027].

In 4.0, you can now pass an array to WP_Query as the value for orderby. The syntax looks like:

$q = new WP_Query( array( 'orderby' => array( 'title' => 'DESC', 'menu_order' => 'ASC' ) ) );

This allows you to control the generation of the ORDER BY clause with more specificity:

ORDER BY post_title DESC, menu_order ASC

Pre-4.0, you would have had to use some gnarly filters on the SQL statement or a specific clause. No bueno.

To see the internals, check out the new protected methods in WP_Query: ->parse_order() and ->parse_orderby.

Happy WP_Querying!