| Posted under Development

WordPress wp-query: Order posts by taxonomy

A few days ago as i was working on a project, i needed to query some custom post types and order them by a custom taxonomy.

More specifically, i had a list of taxonomies (in my case a Timeline Group that categorizes the posts) and a list of posts assigned to each taxonomy (in my case a list of Timeline entries).

The first solution was to query for all taxonomies and then inside a loop, query all posts assigned to each taxonomy.

However, i did not want to make 6 queries (as many as my taxonomies) in the database.

I am using the “Post Types Order” plugin that i find very useful, as my client can easily drag & drop the posts in the order that he likes.
However, in the settings i have disabled the “Auto-sort” option as i prefer to make my own queries.

Before continuing, you need to make sure that you put the taxonomy entries in the correct order. Otherwise the script below will not work.

Normally, to get a list of all of my posts (custom post type named “timeline”) i would type:

$timeline = new WP_Query(array(
    'post_type' => 'timeline',
    'post_status' => 'publish',
    'orderby' => array('menu_order' => 'ASC', 'date' => 'DESC'),   //keeps the order from the drag & drop and also orders by the newest first
    'update_post_meta_cache' => false,
    'update_post_term_cache' => false,
    'ignore_sticky_posts' => true,
    'posts_per_page' => -1,  //get all posts matching the above criteria
    'no_found_rows' => true,
));

Now, i want to force WP_QUERY to use the taxonomy table and change the orderby.

So first i am going to query all taxonomies and get their IDs and then i will call my own filters to change the order by of the query.

$timeline_taxonomies = get_terms(array(
    'fields' => 'ids',   //get the IDs
    'taxonomy'     => 'taxonomy_name',
    'orderby'      => 'term_order',
    'hide_empty'   => true,
));

//add my filter to change the order by of the query done by WP_QUERY:
add_filter('posts_orderby', 'my_timeline_orderby');

function my_timeline_orderby($orderby_statement) {
    $orderby_statement = " term_order ASC, ".$orderby_statement; //keeps the current orderby, but also adds the term_order in front
    return $orderby_statement;
}

$timeline = new WP_Query(array(
    'post_type' => 'timeline',
    'post_status' => 'publish',
    'orderby' => array('menu_order' => 'ASC', 'date' => 'DESC'),
    'update_post_meta_cache' => false,
    'update_post_term_cache' => false,
    'ignore_sticky_posts' => true,
    'posts_per_page' => -1,
    'no_found_rows' => true,
    //same as the initial query, only now i am adding 'tax_query' just to force an inner join to the taxonomies table
    'tax_query' => array(
        array(
            'taxonomy'  => 'taxonomy_name',
            'field'     => 'term_id',
            'terms'     => $timeline_taxonomies
        )
    ),
));

//after i am done, i remove the filter:
remove_filter('posts_orderby', 'my_timeline_orderby');

//now i can loop though the results as i would normally do:

foreach ($timeline->posts as $post){
   //code here
}

Hope this helps!

Thanks for your likes, this will motivate me to write posts more often!