WordPress get_the_terms by term order [bug fix]

WordPress 4.7 introduced a change to the default term order for get_the_terms()

In earlier versions of WordPress, get_the_terms( $post_id, $taxonomy_name) returned the terms in the same order in which the terms were added to the post.  But, starting with WordPress 4.7, the terms are being returned in alphabetical order by term slug.  (Note:  This is for non-hierarchical terms.  I’m not sure if this is true for hierarchical  terms.)

As you may know, get_the_terms is a convenient function for getting the terms for a specific post ID.  It is used by many plugins, and can be used for built in taxonomies like categories and post_tag or for custom taxonomies.

get_the_terms is a cached function, meaning that WordPress caches the results, so that if it’s called repeatedly, it doesn’t have to do a database query each time.  So it’s a good function to use for performance reasons.  It’s unlikely to slow your site down.  However, it doesn’t accept an orderby argument to specify how to order the results.

So, there are 3 ways to fix this problem.

Option #1: get_terms_orderby Filter

You can add a filter on get_terms_orderby

This filter allows you to alter the $orderby part of the SQL query that WordPress uses to get the terms from the database.

Assuming that author is the name of your custom taxonomy, you can use this function:

function wpcf_author_filter_terms_order( $orderby, $query_vars, $taxonomies ) {
    if ( ! empty( $query_vars['object_ids'] )
        && ! empty( $taxonomies[0] )
        && ( 1 === count( $taxonomies ) )
        && 'author' === $taxonomies[0] )
        {
            $orderby = 'tr.term_order';
        }
    return $orderby;
}

add_filter( 'get_terms_orderby', 'wpcf_author_filter_terms_order', 10, 3 );

By the way, the above code will fix this Co-Authors Plus plugin ordering issue. The Co-Authors Plus plugin creates a taxonomy named author and uses get_the_terms. This is actually where I first saw this bug, but since it is a result of a WordPress core change, I’m sure that there are many other WordPress themes and plugins in the wild with this same issue.

Keep reading if you’re curious, as this is a solution, but not the only solution.

Option #2: use wp_get_post_terms()

Alternatively, you can simply not use get_the_terms() but instead use wp_get_post_terms() which accepts a list of overrides, which means that you can specify the orderby in the third parameter.

For example,

Instead of this:

$terms = get_the_terms( $post_id, $taxonomy );

Write this:

$terms = wp_get_post_terms( $post_id, $taxonomy, array( 'orderby' => 'term_order' ) );

The reason I prefer option #1, even though it’s more complicated, is that wp_get_post_terms is an uncached function.  On a low traffic site that’s using full page caching, it may make no difference.  But if you have a site with a lot of logged in users where caching isn’t happening, I’d recommend using a more performant method.

Option #3: use wp_get_object_terms

Similar to option #2, with the same warning about it being an uncached function.

I’m running out of steam to elaborate, and I think that the codex entry on wp_get_object_terms does a pretty good just of explaining how to use this function.

Just remember my warning about no caching.  If you’d like to see how to implement some DIY caching, here’s an example I wrote.  Adding your own caching is something you can do anywhere you want in theme and plugin development.  It’s not really hard to do once you figure out the pattern.  The tricky part is to remember to delete the transients when needed — for this case, you’ll want to delete them on save_post and delete_post, which you can see how to do in my example.  If you don’t want to worry about when to delete them, you could just create short transients — like one minute or fifteen minute ones.  Having the query run every minute is way better than having it run for every page load, which could be many times per second.   For more info, check out the WordPress Transients API.  It goes into quite some detail about how to use them for caching data.

Leave a Reply

Your email address will not be published. Required fields are marked *

*