Introducing Cache Buddy: a companion for your WordPress page caching solution

WordPress is, by default, completely dynamic. On every page load, a bunch of “work” happens. Cookies are read. A database is queried. Content is transformed. All of this makes WordPress very powerful and flexible. But for sites that get a lot of traffic and mostly just need to crank out the same pages for everyone, this dynamic nature can become a challenge.

The common solution to this is to layer a page cache on top of WordPress. Batcache, W3 Total Cache, and WP Super Cache are examples of page caches built as WordPress plugins. Varnish, Nginx fastcgi caching, and CDNs like Akamai or Cloudflare are examples of page caching that happens outside of the WordPress layer. They store the HTML that WordPress generates for a given URL and then store it for later, so that when people request that URL in the future, they can just get the cached version, for little or no work on WordPress’ part.

But these page caching solutions all share the same downside: they can’t cache pages for logged-in WordPress users or users with WordPress comment cookies. Why not? Well, because WordPress looks at these cookies and alters the page based on them. A logged in user will see the WordPress toolbar at the top, which is customized to them. Users with more privileges might see “edit” links next to content that they can edit. And returning commenters will see their name, e-mail, and URL helpfully filled in to comment forms. All these things change the output of the page, such that it wouldn’t be worth it for a page cache to hold on to that page — it would only be of use to the individual visitor who triggered it. So all of these page caching solutions have rules that make them “skip” the page cache if a user has a WordPress comment cookie, or a WordPress user account cookie (and also a post password cookie, though this is an infrequently used feature). If a site has an active commenting community or has open registration (or required registration), this means that a much smaller percentage of page views can be cache hits. Instead, they are the dreaded cache miss, and they fall back to having WordPress generate a dynamic page.

The difference between a cache miss and a cache hit is not small. A cache hit takes minimal effort for the server, and can be delivered to the user much faster. It can be the difference between 1 second and 0.002 seconds. Five hundred times slower. Dynamic views keep the server connection open for longer, and take up CPU cycles. This can snowball under heavy load. Pages start taking longer, and because they start taking longer, less CPU is available. Eventually they can time out, or the server can run out of connections. Not good. You want cache hits, during a situation like this, but if the traffic isn’t anonymous (non-comment-cookie, non-logged-in-cookie), the available caching solutions just give up.

I’ve been solving this issue for years with custom caching solutions that strip the customizations from the page, so that the cache can be configured to serve one static page to everyone. Now, I’ve moved these techniques into a plugin, and I’m calling it Cache Buddy.

Cache Buddy works by doing the following:

  1. Changes what paths logged-in cookies are set for (so they work in the WordPress backend, but don’t exist on the front of the site).
  2. Sets custom cookies with relevant information about the logged-in user, on the front of the site, making these cookies JavaScript-readable.
  3. Sets custom cookies for commenters (again, JavaScript-readable), and doesn’t set the normal WordPress comment cookies.
  4. Uses the information from these JavaScript cookies, plus some comment form magic, to recreate the comment form experience users would get from a dynamic page.

This means that you can log in to WordPress, and then go a view a post’s comment form, and see “You are logged in as Mark. Log out?”. Or you can be a non-account-having commenter who has commented, and your information will be filled in. Or maybe the site requires registration, and you’re not signed in. You’ll see the normal prompt to sign in. But here’s the kicker: all of these pages are the same page, and will be cached by page caching solutions. The customizations are all done in JavaScript, using the custom (and unknown to WordPress-optimized page caches) cookies that Cache Buddy sets.

What about the toolbar?

Well, by default, Subscriber and Contributor users won’t see it. But it honestly isn’t very useful to them anyway. But Authors, Editors and Administrators (who should be a very small percentage of viewers) will still get dynamic page views like they do now, and they’ll see the toolbar.

What about BuddyPress?

Good luck. Some plugins customize the page so much that all views really do need to be dynamic. Object Caching is your friend, for these cases.

Is this for every site?

No. If you have a BuddyPress site or an e-commerce site, you may honestly need WordPress logged-in cookies available on the front of your site. But if you’re just running a blog/CMS site with a significant number of commenters and logged-in Subscribers, this plugin could massively speed up your site, because requests that had to always be dynamic before, can now be served from a page cache.

What about the “Meta” widget?

Not currently supported, but I’m hoping to add support for it.

What about other logged-in site customizations?

The user will appear to by an anonymous visitor. But you could recreate them in JS by reading the cookies that Cache Buddy sets.