What is the best way to cache pages and queries in WordPress?

No, there isn’t. WordPress does not provide page caching mechanisms, and has no APIs for it. There is no generic way to say example.com/page is now stale and needs recreating. Nor is there any generic way to pre-generate every page short of visiting them all. Every plugin uses a different solution with different APIs and storage mechanisms.

As for knowing which parts of the site are stale and need recreating when a post is saved, unfortunately you’ve ran into a fundamental computer science problem, cache invalidation. When a post gets updated, there are only a handful of places you can know for certain that require cache invalidation/flushing/refreshing:

  • the posts main page
  • its RSS comment feed
  • its REST API response

Otherwise the only way to know where else might feature the post to flush it out is to visit the page and generate it. You can proactively try to invalidate its post parent, term archives for terms it features in, but this is a heuristic with no guarantees, and doesn’t cover page templates, plugin generated interfaces, or other places such as the homepage. It also assumes your expensive queries completed and were able to generate a page that could be cached to begin with.

The only ‘live’ part of the site needs to be the discussion forums and comment sections.

If your posts change rarely you could empty the entire cache on update, it’s expensive but effective. You’d need to research the specific caching solution you’re using though. Otherwise bypassing page caching for those parts of the site is a plugin specific endeavour. The solution for say WP Supercache will be completely different to that for WP Rocket or another plugin.

what about wp_cache_set() and wp_cache_get(), is this the right kind of thinking?

This is the object cache, WordPress uses it to make sure it doesn’t fetch the same post from the database twice. It’s like cooking shows when they pull something from the under the counter and say “here’s something I prepared earlier”.

This won’t fix your problem though, this cache is in memory only, so it’s does not survive between page requests.

You can make it persist but it will require server software such as Redis/Memcached/Mongodb/etc and a suitable dropin PHP file to glue the two together. Most hosts do not provide this, and some managed/enterprise hosts provide it but do not give you the ability to configure it.

Even then, to use it you would need to build a page caching plugin from scratch, which leaves you back where you are at the moment with the Hummingbird plugin with the same questions. Plugins that use these two functions to store full pages already exist, and it’s very likely you’ve already used them yourself without realising.

An Alternative

HTML is cheap and quick to render, it’s the queries that are expensive, so why not cache those instead?

  • cache the queries, especially those using meta_query
  • fetching posts is cheap and fast, but figuring out which posts to fetch is expensive, so cache the post IDs, not the HTML
  • store the results either in transients, post meta, or if available, a persistent object cache

A Sidenote

Lots of people have these problems and find solutions who have never heard of WordPress, and people have struggled with caching for decades. There is no straightforward answer that can be recommended to you that you should install X, do Y, and Z will happen. Some solutions work very well, but won’t work for you, and others will work but have caveats. Do you install something like varnish that sits infront of your server? Rely on a CDN like cloudflare? Do you cache for a very short time so the data is almost current, or permanently until told otherwise? etc etc. It’s a game of tradeoffs, how current and recent do you want your data to be. Caching is no substitute for a fast page load, and ideally it’s a way to scale your traffic, not the main thing making your pages load quickly/