I was reading over some best practices from 10up and they mention setting these two flags to false in a WP_Query ( depending on what you’re querying ):
-
'update_post_meta_cache' => false
: useful when post meta will not be utilized. -
'update_post_term_cache' => false
: useful when taxonomy terms will not be utilized.
I am assuming it utilizing something like update_post_caches()
but I’m not even 100% sure what that means. Could somebody explain what these two flags mean in a WP_Query
and how useful they are? The more information the better as I do not know a whole lot about how WordPress caches things but a well thought out answer regarding these two flags is also acceptable.
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
.