WHA Docs

Caching

Cache layers from edge to application, what's active vs supported, and how to invalidate.

Caching happens at multiple layers between the visitor and the database. Understanding which layer is serving stale content is the first step in debugging cache issues.

Cache Layers

Cloudflare Edge Cache

Cloudflare caches public pages at the edge based on two rules configured in the Cloudflare dashboard:

RuleMatchAction
BypassesURI starts with /.well-known or /healthzSkip cache
Cache public pagesURI does not start with /wp/wp-admin and cookie does not contain wordpress_logged_inEligible for cache with edge TTL

Logged-in users always bypass the edge cache. Health check and ACME challenge endpoints are never cached.

Invalidate: Cloudflare dashboard → Caching → Purge Cache, or via API.

Static Assets (Nginx + Browser)

Nginx serves static assets (JS, CSS, images, fonts, SVGs) directly without hitting PHP, with expires max headers. Browsers cache these indefinitely. Cache busting is handled by content-hash query strings (e.g., app.css?ver=c3f97dd56f5e46be03ea) — when assets change, the hash changes and browsers fetch the new version.

Redis Object Cache (Supported, Not on Heroku)

The yax-performance mu-plugin supports Redis as a WordPress object cache backend. When active, it caches database query results, option lookups, and other expensive operations in memory. Runs in local dev via Docker. Not available on Heroku without a paid add-on.

Invalidate (local dev):

docker compose exec redis redis-cli FLUSHALL
npm run wp -- cache flush

WordPress Transients

The provider data handler caches AJAX collection responses as transients to mitigate the N+1 query pattern. Without Redis, transients fall back to the wp_options table — still faster than re-running queries.

Invalidate:

npm run wp -- transient delete --all

What's Cached Where

ContentLayerTTLNotes
Static assets (JS, CSS, fonts, images)Nginx + BrowserIndefiniteCache-busted by content hash
Public HTML pagesCloudflare EdgeEdge TTLBypassed for logged-in users
Health check (/healthz)NoneAlways bypasses all caches
wp-admin pagesNoneAlways bypasses edge cache
Provider AJAX dataWP TransientsApplication-controlledFalls back to MySQL without Redis
Database queriesRedis (when available)Per-requestNot active on Heroku

Debugging Stale Content

  1. CSS/JS looks old — Check that npm run production was run and assets/dist/ was committed. The content hash in the URL should change.
  2. Page content is stale for visitors — Purge Cloudflare cache. Check the wordpress_logged_in cookie bypass is working.
  3. Page content is stale for you (logged in) — Cloudflare shouldn't be caching. Check Redis (local dev) or WP transients.
  4. Provider data is stale — Flush transients: npm run wp -- transient delete --all
  5. Everything looks stale after a deploy — Flush Redis (if available) and purge Cloudflare.

On this page