WordPress doesn’t allow to retrieve categories or terms order by 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 hooks available, get_terms_orderby
or terms_clauses
.
Terms Order by provided ids using terms_clauses hook
add_filter( 'terms_clauses', 'w4dev_terms_clauses', 10, 3 ); function terms_clauses( $clauses, $taxonomies, $args ) { if( isset($args['include']) && !empty($args['include']) && isset($args['orderby_include']) && $args['orderby_include'] ) { $ids = implode(',', array_map('absint', $args['include']) ); $clauses['orderby'] = "ORDER BY FIELD( t.term_id, $ids )"; } return $clauses; } }
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”.
add_filter( 'get_terms_orderby', 'w4dev_get_terms_orderby', 10, 2 ); function w4dev_get_terms_orderby( $orderby, $args ) { if( isset($args['include']) && !empty($args['include']) && empty($orderby) { $ids = implode(',', array_map('absint', $args['include']) ); $orderby = "FIELD( t.term_id, $ids )"; } return $orderby; } }
I haven’t noticed any difference using any of these two hooks, none with performance or with compatibility.
An Example
$get_tags = get_terms( 'post_tag', array( 'include' => array(21,11,31), 'orderby_include' => true, 'hide_empty' => false )); // this should return tags at the order 0 - 21, 1 - 11, 2 - 31.