Skip to content

Disable WordPress core’s term cache priming

A feature of WordPress core that primes the term and/or meta caches after certain queries can result in performance issues and much longer than normal transaction times.

Note

This feature was deprecated in the release of WordPress versions 6.3.

If you notice slow traces (in New Relic, for example) that have a fairly long-running update_term_cache, update_termmeta_cache, or wp_queue_posts_for_term_meta_lazyload function call, there may be an opportunity to optimize the related query. These issues may also become noticeable when using Query Monitor – you may see a lot of wp_cache_add or wp_cache_set calls.

How term cache priming works

Within the WordPress classes WP_Query and WP_Term_Query, there is a post-query step that iterates through the results and adds data to certain caches. The purpose is to save that query data for use in the loop, or in later function calls to get the terms or post metadata, in an effort to reduce database requests.

However, this cache priming is sometimes unnecessary, and if there are a lot of terms, the overhead from updating Memcached can add up.

WP_Term_Query cache priming

For WP_Term_Query, you may see a call to update_term_cache or update_termmeta_cache take several seconds. Here’s a New Relic trace:

The significant problem with that trace is the number of calls to Memcached, most of which may not be necessary for the task at hand.

WP_Query cache priming

For WP_Query, you may see similar traces, with the function wp_queue_posts_for_term_meta_lazyload instead.

Any or all of these may be unnecessary, depending on what the code is doing with the terms that were fetched. Sometimes you may not be using the post meta or terms following a query. If you review the related code that runs after the query, and find the cache priming to be unnecessary, or to be slowing down the request, it’s possible to disable these behaviors on an individual query basis.

Typically, these cache priming actions are not needed for most API requests.

How to disable cache priming selectively

The cache priming is a default setting that can be controlled by query arguments. The source code and documentation for these classes is helpful in understanding where and how these priming activities happen.

Resolving WP_Query priming

For WP_Query, there are two query arguments that default to true, and can be set to false:

  • update_post_meta_cache caches the post metadata
  • update_post_term_cache caches the post terms

Here’s a portion of the source code for WP_Query::get_posts:

    if ( $q['lazy_load_term_meta'] ) {
        wp_queue_posts_for_term_meta_lazyload( $this->posts );
    }

lazy_load_term_meta is set by the argument update_post_term_cache earlier in the same method:

   if ( ! isset( $q['update_post_term_cache'] ) ) {
        $q['update_post_term_cache'] = true;
    }
 
    if ( ! isset( $q['lazy_load_term_meta'] ) ) {
        $q['lazy_load_term_meta'] = $q['update_post_term_cache'];
    }
 
    if ( ! isset( $q['update_post_meta_cache'] ) ) {
        $q['update_post_meta_cache'] = true;
    }

When using WP_Query, this can be set directly in the argument list or via pre_get_posts actions.

$args = array(
    'posts_per_page'         => 10,
    'update_post_meta_cache' => false,
	'update_post_term_cache' => false,
);
$query = new WP_Query( $args );

Resolving WP_Term_Query priming

For WP_Term_Query, there’s one argument that defaults to true and can be set to false:

  • update_term_meta_cache caches the term meta (via update_termmeta_cache)

Also for WP_Term_Query, the update_term_cache function can be avoided when the fields query attribute is not set to all or all_with_object_id. If only the id and/or slug is needed, then specifying that in the arguments will avoid caching the terms.

Here’s a portion of the source code for WP_Term_Query::get_terms:

    $terms = $wpdb->get_results( $this->request );
 
    if ( 'all' === $_fields || 'all_with_object_id' === $_fields ) {
        update_term_cache( $terms );
    }
 
    // Prime termmeta cache.
    if ( $args['update_term_meta_cache'] ) {
        $term_ids = wp_list_pluck( $terms, 'term_id' );
        update_termmeta_cache( $term_ids );
    }

To resolve any update_term_cache issues, review the list of possible fields parameters and determine if only term slugs or ids are needed instead of the default all. For example, per the documentation, ‘id=>name’ Returns an associative array of term names, keyed by term ID.

To resolve excessive time spent in update_termmeta_cache, disable it by setting update_term_meta_cache to false.

For example:

// get a list of category names (and their IDs)
$args = array(
	'fields'                 => 'id=>name',
    'taxonomy'               => array( 'category' ),
	'order'                  => 'ASC',
	'orderby'                => 'name',
    'update_term_meta_cache' => false,
);
$query = new WP_Term_Query( $args );

Note that typically, you’ll only need to disable these cache priming functions when you observe that they are affecting the response time of certain transactions, and they are unnecessary to that transaction.

Last updated: December 22, 2023

Relevant to

  • WordPress