Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Referencing @Otto's response to a question I also had about ordering by multiple fields, here is what he said:

Can't do it with a naive WP_Query. Use the posts_orderby filter to add your own ordering string.

function my_order($orderby) { 
    global $wpdb; 
    return "{$wpdb->posts.post_author} ASC, {$wpdb->posts.post_date} DESC"; 
} 
add_filter( 'posts_orderby', 'my_order' ); 

$blah = new WP_Query(...); 

remove_filter( 'posts_orderby', 'my_order' ); 

-Otto

This appears to be the way it would be done in a new call to WP_Query --> how would I go about this same thing in a pre_get_posts() action with two meta fields, with a default sort to?:

function mouldings_sort($query) {
    if ($query->is_main_query() && is_tax(array('wood_types','profile_categories','combination_categories'))) {

        $query->set('meta_key', '_mouldings_dimensions_height');
        $query->set('order', 'DESC');
        $query->set('orderby','meta_value_num');
    }

}
add_action('pre_get_posts','mouldings_sort');

I had previously tried simply adding in another meta field like so:

$query->set('meta_key', array('_mouldings_dimensions_height', '_mouldings_dimension_width'));
$query->set('orderby','meta_value_num');

with a default sortback of title as so:

 $query->set('orderby','meta_value_num title');

but it doesn't look like meta_key can accept arrays and my title fallback goes back to Otto's original response on the matter. Any help would be a greatly appreciated. Thanks!

share|improve this question
    
take a look at this approach wordpress.stackexchange.com/a/67391/2487 –  Bainternet Oct 23 '12 at 16:47
    
Any progress on that one? –  kaiser Sep 27 '13 at 0:58

2 Answers 2

Yes like Otto said you can't have a secondary ORDER BY clause without a a custom posts_orderby filter. If you need to know what query your on a la "pre_get_posts" you can create a function that adds the orderby filter to posts_orderby and call it from pre_get_posts.

/**
 * Posts orderby filter.  The filter will be added using pre_get_posts outside the class
 *  using the pre_get_posts action allows us to do checks for what page etc...
 * @return string, new MySQL ORDER BY clause
 */
function wpse_order_by() {
    global $wpdb;
    return $wpdb->prepare( "$wpdb->postmeta.meta_value+0 DESC, post_title DESC" );
}

/**
 * Pre get posts filter for adding secondary fall back ORDER BY clause to MySql query
 * @uses remove_filter(), This filter removes itself after it runs to prevent it from affecting  other queries on the same page.
 * @uses add_filter()
 * @param object|array $query the current $query object
 */
function wpse_post_order_pre( $query ) {
    if ($query->is_main_query() && is_tax(array('wood_types','profile_categories','combination_categories'))) {

    /** remove_filter() is used to prevent this affecting additional queries on the page */
    remove_filter( current_filter(), __FUNCTION__ );

    add_filter( 'posts_orderby', 'wpse_order_by' );
    }
}

add_action( 'pre_get_posts', 'wpse_post_order_pre' );
share|improve this answer
    
Hi Chris - I really appreciate the reply. Here is the entire pre_get_posts() filter I am current using. Did I add that in correctly? Currently getting the following DB error on an unrelated WP_Query (which is odd since I'm running a check to make sure we're only effecting the main query). Any thoughts on that? In addition, does this address being able to add-in a secondary order as another meta field, _mouldings_dimensions_width and THEN eventually fall-back to the title? Thanks again for all the help. –  Zach Oct 23 '12 at 18:57
    
It needs to be in its' own function instead of mixed with your current pre_get_posts. If the remove_filter doesn't run the action will get added to every query on the page. You will get an unknown column postmeta.meta_value MySql error if it runs on any query that is NOT a meta_query because it needs the INNER join on postmeta to work. Use debug bar so you can see what the MySql looks like to debug this. –  Chris_O Oct 23 '12 at 19:31
    
Thanks Chris - SQL error on the page is SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'galleries' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') ORDER BY wp_postmeta.meta_value+0 DESC, post_title DESC LIMIT 0, 2 which means it's still reaching outside of the main query. Would this be more the plugin adding the galleries post type not resetting the query correctly? Any docs on what meta_value+0 is, I'll obviously take the answer ;) but would love to know what that is as well. Thanks. –  Zach Oct 23 '12 at 19:49
    
That query, shown here does appear to reset the query properly (generating from a widget). –  Zach Oct 23 '12 at 19:51
    
Those errors are because remove_filter( current_filter(), FUNCTION ); is not working or is being fired to early. You can try setting the priority to 99999 to make sure it fires last. –  Chris_O Oct 23 '12 at 20:37

Never forget that there're actually two filters

// Add additional query args that are allowed by the API by default
pre_get_posts
// Modify the query herself
posts_clauses
// Inspect the resulting string - test this one in for e.g. phpMyAdmin
posts_request

So everything you can achieve using the pre_get_posts filter should be done there. The rest should be modified using the posts_clauses (or one of the more specific filters before).

// Modify the original query parts
function wpse70214_pre_get_posts( $query )
{
    var_dump( $query );
    return $query;
}
add_filter( 'pre_get_posts', 'wpse70214_pre_get_posts' );

// Modify the resulting query string parts
function wpse70214_posts_clauses( $pieces )
{
    var_dump( $pieces );
    return $pieces;
}
add_filter( 'posts_clauses', 'wpse70214_posts_clauses' );

// Then check the result
function wpse70214_posts_request( $query_string )
{
    var_dump( $query_string );
    return $query_string;
}
add_action( 'posts_request', 'wpse70214_posts_request' );
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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