Wordpress - Explanation of update_post_(meta/term)_cache

Object cache everywhere

WordPress tries to reduce the number of database queries as much as possible.

For example, anytime you get a meta field or a taxonomy field, before querying the database, WordPress looks if that that was already queried and stored in cache, and returns it from there instead of querying the database.

The "cache job" is done via WP_Object_Cache class and wp_cache_* functions (that are wrapper to that class methods.)

Where cache lives

By default, the "cache" is nothing more than a PHP global variable. It means that it is in memory, but also means that it vanishes on every request.

However, via dropins (advanced-cache.php and / or object-cache.php), it is possible to setup a custom way to handle this cache.

Usually, this dropins are used to setup some sort of caching mechanism that "survive" the singular requests.

For this reason, among WP people, these are know as "persistent cache" plugins (even if outside the bubble the words "cache" and "persistent" don't not make a lot of sense together).

Popular choices nowadays are Memcached or Redis.

So using "persistent cache" plugins you can drastically reduce the number of database queries, because the cache is not updated on every request.

Some examples

$foo = get_post_meta('foo', $post_id, true);
// a lot of code in the middle
$bar = get_post_meta('bar', $post_id, true);

The 2 lines of code above will trigger, at maximum, 1 database query.

In fact, when you query a custom field, all the fields for that post are retrieved from database, cached via object cache, and subsequent requests pull data from cache and not from db.

The same happen for taxonomy terms, WordPress pulls all the terms for a taxonomy once, then returns them from cache.

Object cache is used very widely in WordPress. Not only for posts, meta values and taxonomies, but also for users, comments, theme data...

What WP_Query has to do with all of this?

When you query some posts via WP_Query, by default, WordPress not only pulls them from database (or from cache if they are cached) but also updates the cache for all custom fields and all taxonomies related to the posts pulled.

So when you call, for example, get_the_terms() or get_post_meta() while looping posts got via WP_Query, you don't actually trigger any database query, but pull information from cache.

Nice, it isn't?

Well, yes, but it comes with a cost.

The cache update "magic" that WordPress does when pull posts via WP_Query happen in update_meta_cache for meta and in update_object_term_cache for taxonomies.

If you look at the source code of those functions, you'll see that there WordPress performs just one db query in each function, but also does a lot of processing. For example, in update_object_term_cache there are 7 nested foreach... if you have a lot of taxonomies, and the number of posts per page is high, this is not very performant.

About those WP_Query arguments, finally

What 'update_post_meta_cache' and 'update_post_term_cache' do when set to false is to prevent WordPress to update cache for custom fields and taxonomies, respectively.

In that case, the first time a custom field or a taxonomy is queried a database query is triggered, and data are cached.

It worth the trouble?

As usual, the answer is it depends. Most of the times to set those values to false, is a good choice, because it prevents unnecessary processing and database queries if not needed, and cache is updated anyway the first time custom field / taxonomy terms are required.

However, if you are going to call, even once, get_post_meta() during the loop and you are going to call get_the_terms() for all (or most) of the taxonomies supported by posts, then the cache updating is triggered anyway, and there might be no actual benefit on setting those query arguments to false.


The main point of interest here is the update_post_caches function. It is called after WP_Query got all the posts from the DB. Usually, the reason you want the posts in the first place is to display them which usually means to display the terms and something based on the metadata, therefor WP_Query will also by default query the DB for the meta and term data related to the returned posts and stores it the cache*. This information is not explicitly available in the data returned from WP_Query, but when you will call the relevant APIs to get the term and meta info of a specific post, it will already be available in memory and there will be no need to send a new query to the DB.

This enables wordpress to reduce the overhead related to sending requests to the DB by sending only one request to get the information for all of the posts instead of sending a request per each post.

Right now I can not find any non trivial example of when will you not want the cache to update, but a trivial one might be if you just want a list of the titles of all posts. For that you do not need term or meta data.

*cache - Most important here is the memory based cache in which WP stores almot everything which it gets from the DB even without having any object caching plugin active. Obviously when you do have object caching the information will be stored there as well.