Taxonomy performance improvements in WordPress 6.0

As part of the 6.0 release of WordPress, the new performance team has been hard at work to improve the performance of term queries. There are many term queries on the average page load and improving these improves the performance of WordPress in general. 

Improvement to term query caching. 

Queries run by WP_Term_Query have been cached since 4.6. The way these caches are primed and handled has been improved in WordPress 6.0.

Removing to cache limit

Prior to WordPress 6.0, term query caches were limited to a 24-hour period for those using persistent object caching. This limitation is now removed, so if caches are not invalidated, it means that term query should cache much longer. For inactive sites or overnight, caches should remain primed, which should improve site performance. 

For more information, see #54511.

Term query cache only caches the term ID

Term query caches have been changed so that instead of caching the whole term object, now only the term IDs are cached. This means that the value stored in cache will be much smaller (in terms of memory) and will not fill up memory in session or persistent object cache.

Once all the IDs for the terms are loaded, the _prime_term_cache function is called. This loads into memory terms that are not already in cache. If the term is already in memory, then it is not loaded again, which is a performance benefit. On an average page load, a term may be requested multiple times, like the case of a tagtag A directory in Subversion. WordPress uses tags to store a single snapshot of a version (3.6, 3.6.1, etc.), the common convention of tags in version control systems. (Not to be confused with post tags.) archive page. Early in the page load, get_term_by, will prime the term cache and all other calls, such as get_the_terms, will have the term already primed in page memory. This results, in most cases in fewer and smaller queries that are run against the term table. 

For more information, see #37189.

Improved term query cache key generation

Previously, similar term queries that have similar cache keys would result in basically the same query being run twice on a single page load. Because all queries now only get the term ID and store it in cache (see above), the cache exactly the same. For example, you create a call to get_terms where you request all categories and return only the field slug. If you do the same query and request only the name, then this would hit the same cache.

Another improvement is the handling of parameters that can be passed to WP_Term_Query that can be ambiguous. Fields like slug that can be either a string or an array are now converted to always be an array, meaning that the likelihood of reusing a cache is higher as the cache key is the same, no matter which type of parameter is passed. 

For more information, see #55352.

Improve performance for navigation menuNavigation Menu A theme feature introduced with Version 3.0. WordPress includes an easy to use mechanism for giving various control options to get users to click from one place to another on a site. items

Convert wp_get_nav_menu_items to use a taxonomyTaxonomy A taxonomy is a way to group things together. In WordPress, some common taxonomies are category, link, tag, or post format. https://codex.wordpress.org/Taxonomies#Default_Taxonomies. query

This replaces usage of get_objects_in_term function with a simple taxonomy query. This replacement converts the use of two queries to get the menu items to use one simple query. This saves one query for each menu requested and adds consistency. 

For more information, see #55372.

Prime all term and posts caches in wp_get_nav_menu_items

The wp_get_nav_menu_items function now calls _prime_term_cache and _prime_post_cache for all objects linked to menu items. If a menu contains a list of categories and pages, all the related objects are now primed in two cache calls (one for terms and one for posts). This will result in far fewer requests to the database and cache.

For more information, see #55428.

Convert term_exists to use get_terms

The function term_exists has now been converted to use get_terms ( WP_Term_Query ) internally replacing raw uncached database queries. This function was one of the last places to perform raw queries to the terms table in the database. Using the get_terms function has a number of key benefits, including: 

  • Consistency with other coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. functions like get_term_by
  • The ability to filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. the results.
  • Results of get_terms are cached 

term_exists is designed for back-end use and is mostly used in core functions designed to write data to the term table. However, term_exists can and is used by some theme and pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party developers. This results in raw uncachable and unfilterable queries to be run on the front-end of a site. 

Now that term_exists is cached, custom import / migrationMigration Moving the code, database and media files for a website site from one server to another. Most typically done when changing hosting companies. tools may need to check if they correctly cache invalidation terms. If your importation code is using core functions like wp_insert_term, then there is no need to do anything, as core does its own cache invalidation for you. However, if you are writing data to the term table manually, then you may need to call the clean_term_cache function. 

For those that need to ensure that term_exists is getting an uncached result, there are two ways to do this:

  1. Using the new term_exists_default_query_args filter 
$callback = function ( $args ) {
   $args['cache_domain'] = microtime();
};
add_filter( 'term_exists_default_query_args',  $callback );
$check = term_exists( 123, 'category' );
remove_filter( 'term_exists_default_query_args',  $callback );
  1. Using wp_suspend_cache_invalidation
wp_suspend_cache_invalidation( true );
$check = term_exists( 123, 'category' );
wp_suspend_cache_invalidation( false );

For more information, see #36949.

Add a limit to taxonomy queries

The ​​WP_Tax_Query class is used in WP_Query to limit queries by term. Under the hood, ​​WP_Tax_Query uses ​​WP_Term_Query, which means that ​​WP_Tax_Query will get the benefits of the cache improvements documented above. The ​​WP_Tax_Query run, which transforms term slugs / names into term IDs to be queried, now has a limit added to it. This query limit improves the performance of the query, as well as improves the likelihood of an existing cache query to continue to exist in the object cache. For example, a standard tag archive calls get_term_by and primes the cache. By the time it gets to the ​​WP_Tax_Query, that query is being loaded from cache. This removes one query per tag archive page. 

For more information, see #55360.

Props to @milana_cap, @shetheliving, @flixos90 for peer review.

#6-0, #dev-notes, #dev-notes-6-0, #performance, #users