Cache Strategy for Your DTC Site: Page, Object, and Browser Cache Setup
1. What Each of the Three Cache Layers Handles
Caching on a DTC site breaks into three layers, each solving a different problem. Don’t lump them together. Page cache saves the fully rendered HTML as a static file, so the next visit to the same URL gets the file straight back without running PHP or hitting the database. Object cache stores database query results in memory (such as Redis or Memcached), so the same query next time comes from memory instead of MySQL. Browser cache uses HTTP response headers to tell the visitor’s browser “keep this file locally,” so the next visit reads it straight from local disk.
The performance gains differ a lot across the three layers. Page cache delivers the most: it skips PHP execution and database queries entirely, bringing LCP from over 4 seconds down to under 1 second. Object cache delivers a moderate gain: it only saves database query time, and if page cache already hits, object cache never gets triggered at all. Browser cache pays off for returning visitors: the first visit still has to download, but from the second visit on it reads locally, so repeat visits get noticeably faster.
| Cache layer | What it stores | Where it lives | Performance gain | Typical tools |
|---|---|---|---|---|
| Page caching | Full HTML pages | Server disk or memory | Largest, cuts LCP by 60% to 80% | WP Rocket、LiteSpeed Cache |
| Object cache | Database query results, PHP objects | Redis or Memcached | Moderate, cuts DB query time by 50% | Redis、Memcached |
| Browser cache | CSS/JS/images | Visitor’s browser, locally | Returning visitors, faster second visit | Cache-Control response header |
| CDN cache | Static assets + some HTML | Global edge nodes | Cuts cross-region latency by over 50% | Cloudflare、Akamai |
Many people jump straight into tuning Redis and Memcached, but for a B2B site, getting page caching right already solves 80% of your performance problems. Object caching is a bonus, worth adding once you pass 50,000 monthly unique visitors or your database queries start slowing down. For how CDN fits with the three caching layers, see Global CDN acceleration and node selection, and for the performance benchmarks you should hit, see Core Web Vitals Optimization.
2. Page Caching: How to Store HTML Without Breaking Things
Page caching delivers the biggest win, and it’s also the easiest layer to misconfigure. The classic symptoms of a bad setup: a visitor submits an inquiry and then sees the previous visitor’s submission, or a logged-in user still sees the logged-out version of the page. The cause is page caching storing HTML with dynamic content as a static file.
The right approach is to split pages into two groups by URL and user state: public static pages (homepage, product pages, blog posts) go through page caching; dynamic pages (after an inquiry form is submitted, wp-admin, pages shown after login, the shopping cart) must skip the cache. WordPress caching plugins (WP Rocket, LiteSpeed Cache) all support “exclude URL” and “skip cache by cookie” rules.
| Page type | Cache? | Cache duration | Exclusion rule |
|---|---|---|---|
| Homepage, product listing pages | Cache | 1 to 4 hours | Exclude logged-in users |
| Blog post page | Cache | 12 hours to 1 day | Manually refresh when content changes |
| Inquiry form page | Do not cache | None | Always fetch from origin |
| Form submission success page | Do not cache | None | Has session cookie |
| wp-admin | Do not cache | None | Exclude admin cookie |
| Search results page | Short cache or no cache | 5 minutes | Avoid caching different search terms |
Example: an industrial equipment site has a product detail page at /products/cnc-machine-a/. Its content changes maybe once every few months, so caching it for 1 day is perfectly fine. But the inquiry form’s “submitted successfully” page lives at /inquiry-thank-you/, and every visitor should see their own confirmation there, so it must never be cached. In WP Rocket, add /inquiry-thank-you/ and /wp-admin/* to the Never Cache URL(s) list.
Cache invalidation is just as important as page caching itself. You edit a blog post, how do you make it go live immediately? Two ways: manually purge the entire cache on publish, or use “refresh by URL” to clear only that one page. WP Rocket automatically refreshes related caches when a post is updated, but many custom pages won’t trigger it, so get in the habit of hitting Purge after you publish. crater ties cache invalidation into the publishing workflow on overseas sites; see crater’s tech stack and four in-house plugins.
3. Object Caching: How to Reuse Database Query Results
When a page cache hit occurs, neither PHP nor the database runs, so object caching never comes into play either. But when the page cache misses — say you just published a new post, or someone hit a dynamic page that shouldn’t be cached — PHP has to query the database. A typical WordPress page runs 12 to 20 database queries, and every query goes through disk I/O. Stack up enough slow queries and page load time climbs past 1 second.
Object caching stores those query results in Redis or Memcached, so the next identical query reads straight from memory. Install Redis on a single server, connect WordPress through the Redis Object Cache plugin, and you don’t need to change a single line of code. Configured correctly, database query time drops by more than 50%, and response time on a page cache miss falls from 1.5 seconds to under 0.5 seconds.
| Metrics | No object cache | With Redis object cache | Improvement |
|---|---|---|---|
| Database queries per page | 12 to 20 per page | 2 to 5 per page | 70% to 80% fewer |
| Time per query | 5 to 20 ms (disk I/O) | 0.1 to 1 ms (memory) | 10 to 50 times faster |
| Response time on page cache miss | 1 to 1.5 seconds | 0.3 to 0.5 seconds | Over 50% faster |
| MySQL CPU usage | Over 80% at peak | 30% to 40% at peak | More than halved |
Object caching isn’t mandatory. For B2B sites under 10,000 monthly unique visitors, database load is light and page caching already absorbs 95% of requests, so Redis brings little benefit. When should you add it? Two signals: first, your MySQL slow query log shows more than 100 queries per day taking over 1 second; second, after you save an edit in the admin, the front end takes several minutes to reflect it (object cache isn’t invalidating properly). For slow queries and index optimization, see Slow Queries and Index Optimization for Standalone Sites.
4. Browser caching: how to set cache headers for static assets
Browser caching is the easiest of the three layers to configure. It doesn’t touch any server-side program — just add a few response headers in your web server (Nginx or Apache). The idea: when the server returns CSS, JS, or images, it adds Cache-Control: max-age=2592000 to the HTTP response headers, telling the browser “keep this file locally for 30 days.” For the next 30 days, the browser won’t request it from the server again.
But there’s a classic trade-off: a long browser cache makes visits fast, yet when you change your CSS or JS, users still have the old version locally and see a broken layout. The fix isn’t to shorten the cache time — it’s to add a version number or hash to the filename, like style.css?v=2 or style.abc123.css. When the file content changes, the URL changes, and the browser downloads it again automatically.
| Asset type | Recommended Cache-Control | max-age | Update strategy |
|---|---|---|---|
| Images (jpg/png/webp) | public, max-age=31536000 | 1 year | Hash in filename, new name on every image swap |
| Font files | public, max-age=31536000 | 1 year | Fonts rarely change, no update needed |
| CSS stylesheets | public, max-age=604800 | 7 days | Version number in filename ?ver=2 |
| JavaScript | public, max-age=604800 | 7 days | Version number in filename ?ver=2 |
| HTML pages | no-cache, must-revalidate | Do not cache | Revalidate on every origin fetch |
| favicon.ico | public, max-age=604800 | 7 days | Rarely changes |
A counterintuitive call: many people worry that a long cache time means users won’t see their content updates, so they set max-age to 1 hour for every asset. The result is that every visitor re-downloads all your CSS and JS on every visit, which actually slows down first paint. The right approach is to set long cache times with confidence (1 year for images, 7 days for CSS/JS) and handle updates with file hashes or version numbers. WordPress’s wp_enqueue_script function adds a version number automatically, and that version number changes when themes and plugins update, so you don’t have to manage it by hand.
For image optimization and media asset governance, see Managing media assets and compressing images. Static asset caching on multilingual sites also needs to account for how hreflang interacts with CDN caching, see Hreflang for multilingual sites.
5. Cache Invalidation Strategies and Common Conflicts
Once caching is set up, the biggest problem is “how do you make the cache expire when it should?” If the cache doesn’t invalidate in time, users see stale content; if it invalidates too easily, you lose the performance gains. There are four common cache invalidation scenarios on a standalone site: publishing a new post, updating product information, changing CSS/JS, and submitting an inquiry form. Each scenario calls for a different invalidation strategy.
| Scenario | Invalidation scope | Invalidation method | What to watch for |
|---|---|---|---|
| Publishing a new blog post | Homepage + post list + single post | WP Rocket refreshes automatically | Category and tag pages need refreshing too |
| Updating product prices | Product detail page + list page | Manually purge the corresponding URLs | Don’t purge everything, it hurts performance |
| Changing CSS/JS | The corresponding static files | Change the version number and it takes effect automatically | Don’t change max-age, change the file name |
| Submitting an inquiry form | Form pages should never be cached | URL exclusion rules | The success page can’t be cached either |
| Full site redesign | All caches | One-click Purge All | Do it during off-peak hours |
| Updating plugins/themes | All caches | Automatic or manual purge | Back up before updating |
There are two common conflicts. First, installing two caching plugins (say WP Rocket and LiteSpeed Cache at the same time) means both plugins are editing .htaccess and output buffering, which results in a blank page or broken styles. The rule is to install only one caching plugin site-wide. Second, page caching conflicts with login state: a user logs into the admin, but the front end still serves the cached logged-out page, so the navigation bar they see is wrong. The fix is for the caching plugin to detect the login cookie and skip the cache automatically.
Once your caching strategy is live, keep monitoring it, checking cache hit rate and LCP once a month. A sudden drop in cache hit rate usually means someone changed the URL structure or added links with random parameters. For the monitoring and alerting checklist, see Site monitoring and alerts, and for routine maintenance tasks, see Six Monthly Tasks for Site Maintenance. You should also run a backup and recovery drill after any change to your cache configuration, see Backup and recovery drills for your site.
FAQ
Does a WordPress standalone site have to install a caching plugin?
Can inquiry form pages be cached?
When should you add Redis object caching?
How long should browser cache times be set?
What if users can’t see content changes after caching?
Do page caching and CDN caching conflict?
Final thoughts
Caching is where beginners tend to swing to one of two extremes: either they skip it entirely, so every page runs PHP and hits the database on the fly and the first screen takes 4+ seconds, or they cache too aggressively, including form pages, and users end up seeing someone else’s submission. The right approach is to cache in layers: cache static pages boldly, never cache dynamic pages, and give static assets a long cache life plus a version number.
Three steps to get there. First, install a page caching plugin (WP Rocket or LiteSpeed Cache, pick one) and exclude form pages and wp-admin. Second, set Cache-Control headers in Nginx: one year for images, seven days for CSS/JS, no caching for HTML. Third, once you pass 50,000 monthly unique visitors, add Redis object caching. With those three steps done, LCP usually drops under one second, and you won’t get the dreaded incident where cached content leaks across users.
One line worth remembering: caching is the lever for your independent site’s performance. Page caching saves 80% of the time, object caching saves the database, browser caching saves repeat visits. Each layer handles its own job, so keep form pages out of the cache.
