WordPress wp-query: Order posts by taxonomy

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

More specifically, i had a list of taxonomies (in my case a ‘Projects Category’) and a list of custom post types assigned to each taxonomy (in my case a list of projects).

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.
For this you may use a plugin such as “Simple Taxonomy ordering”.

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

$timeline = new WP_Query(array(
    'post_type' => 'project',
    'post_status' => 'publish',
    'orderby' => array('menu_order' => 'ASC', 'date' => 'DESC'),   //keeps the order from the drag & drop and also orders by the newest
    '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.

So in the page i am working on i use:

First, get a list of my custom taxonomies – but only their IDs

$project_categories = get_terms(array(
    'taxonomy' => 'project_category',
    'fields' => 'ids',   //get the IDs only
    'meta_key' => 'tax_position',
    'orderby' => 'tax_position',
    'hide_empty'   => true,

//Tip: at this point you can use print_r to see if the $project_categories results are in the correct order

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

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

$projects = new WP_Query(array(
    'post_type' => 'project',
    '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(
            'taxonomy'  => 'project_category',
            'field'     => 'term_id',
            'terms'     => $project_categories

//after i am done, i remove the filter to keep all other queries in the page function properly:
remove_filter('posts_orderby', 'my_query_orderby');

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

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

Hope this helps!