Use get_the_terms() instead of wp_get_object_terms()

I was recently debugging the front page of a WordPress site and found a lot of queries to the terms and term relationships database tables.

Digging a little deeper, I found that the culprit were a set of functions that were calling wp_get_object_terms() to get the terms from a set of looped posts… and then I thought… “wait a minute, doesn’t WordPress should be using the object cache for this?”

Well, it turns out that wp_get_object_terms() always queries the database.

If you’re looping over WP_Query results, you should prefer get_the_terms() instead. It’s pretty much the same for most use cases, but it uses the object cache, which by default gets populated with the terms for the posts matching your query — unless you specifically set update_post_term_cache as false when instantiating WP_Query.

The are several differences, though: wp_get_object_terms() can take arrays as the first and second argument, while get_the_terms() can only take the post ID (or object) as first argument (so you can’t get the terms for a bunch of posts on one function call) and a string for taxonomy (so you can’t get the terms for several taxonomies); and you can use a third argument on the former, which the latter doesn’t have.

You could still emulate some of this, and still benefit from using the object cache; for instance, let’s see how you would get the names of the my_custom_tax terms for the current post, ordered by use on a descending way.

// using wp_get_object_terms()
$popular_terms = wp_get_object_terms( $post->ID, 'my_custom_tax', array( 
    'orderby' => 'count',
    'order'   => 'DESC',
    'fields'  => 'names'
) );

// using get_the_terms()
$popular_terms = get_the_terms( $post->ID, 'my_custom_tax' );
// $popular_terms will be ordered alphabetically, so let's order by count
$popular_terms = usort( $popular_terms, function( $a, $b ){
    if ( $a->count < $b->count ) {
        return 1;
    }
    if ( $a->count > $b->count ) {
        return -1;
    }
    return 0;
} );  
// we only need slugs, so...
$popular_terms = wp_list_pluck( $popular_terms, 'name' );

Even if it’s somewhat troublesome, it’s probably worth the effort if you’re trying to maximize for performance.