WordPress doesn’t order categories or terms by the ids you provide out of the box. You have probably seen, while doing a post query ( get_posts(), WP_Query() ), if we set the post__in argument with an array of post ids, the query orders the results exactly by the given ids. But when using get_terms(), if we pass the include argument, the results don’t come back in the order the term ids were passed. So I figured out a solution digging the core code in the file wp-includes/taxonomy.php.
Update: since WordPress 4.7, core supports this natively. You can simply pass 'orderby' => 'include' to get_terms() and skip the custom hooks entirely:
$tags = get_terms( array(
'taxonomy' => 'post_tag',
'include' => array( 21, 11, 31 ),
'orderby' => 'include',
'hide_empty' => false
));
If you need a different custom order, or you want to understand how the ordering can be filtered, we can use either of two available hooks, get_terms_orderby or terms_clauses.
Terms Order by provided ids using terms_clauses hook
function w4dev_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 );
The above code extends the get_terms() functionality to order by the passed ids. To use this in your query, you will need to set an additional argument orderby_include => true. We can not use the default orderby argument for this, as an invalid orderby value is automatically removed before any useful hook is available.
Terms Order by provided ids using get_terms_orderby hook
Processing with this hook is the same as the previous one. But here I tried to use a fixed condition – “If the include argument is defined, and orderby is left empty, we will order by the included 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 between these two hooks, neither with performance nor with compatibility.
Example Usage
$tags = get_terms( array(
'taxonomy' => 'post_tag',
'include' => array( 21, 11, 31 ),
'orderby_include' => true,
'hide_empty' => false
));

Leave a Reply