Categories, Tags, Terms Custom Order

WordPress doesn’t allow to fetching categories or terms order by their id. You have probably seen, while doing a post query ( get_post(), WP_Query() ), if we set post__in argument with an array of post id, the query exactly order the results by given ids order. But, when using get_terms(), if we pass include argument, the returning result doesn’t not come at the order term ids was passed. So, i figured a solution digging the core codes on the file wp-includes/taxonomy.php.

We can use any of two available hooks, get_terms_orderby or terms_clauses.

Terms Order by provided ids using terms_clauses hook

function terms_clauses( $clauses, $taxonomies, $args ) {
    if ( ! empty( $args['include'] ) && ! empty( $args['orderby_include'] ) ) {
        $ids                = implode( ',', array_map( 'absint', $args['include'] ) );
        $clauses['orderby'] = "ORDER BY FIELD( t.term_id, $ids )";
    return $clauses;
add_filter( 'terms_clauses', 'w4dev_terms_clauses', 10, 3 );

Now, the above code just extends the get_terms() functionality to order by passed ids. To use this on your query, you will need to set an additional argument orderby_include => true. We can not define the default orderby argument as invalid orderby argument will automatically be remove before any useful hook is available.

Terms Order by provided ids using get_terms_orderby hook

Processing using this hook is the same as previous. But here i tried to use an fixed condition – “If include argument is defined, and orderby is left empty, we will order by include ids automatically”.

function w4dev_get_terms_orderby( $orderby, $args ) {
    if ( ! empty( $args['include'] ) && empty( $orderby ) ) {
        $ids = implode(',', array_map('absint', $args['include']) );
        $orderby = "FIELD( t.term_id, $ids )";
    return $orderby;
add_filter( 'get_terms_orderby', 'w4dev_get_terms_orderby', 10, 2 );

I haven’t noticed any difference using any of these two hooks, none with performance or with compatibility.

Example Usage

$tags = get_terms( 'post_tag', array( 
    'include'         => array( 21, 11, 31 ), 
    'orderby_include' => true, 
    'hide_empty'      => false