Most WordPress performance advice starts and ends with “install a caching plugin.” That’s like telling someone to buy a toolbox without explaining what any of the tools do. You end up with a plugin running on default settings, no idea what it’s actually doing, and a site that’s still slow.
I’ve set up caching on 300+ WordPress sites. Some went from 3-second load times to under 1 second. Others saw zero improvement because the real problem was somewhere else entirely. Caching is powerful, but it’s not magic. You need to understand what it does, what it skips, and where it breaks.
This chapter gives you all of that.
What Caching Actually Does (and Doesn’t Do)
Think of your WordPress site like a restaurant kitchen. Every time a visitor lands on a page, WordPress fires up the grill. It queries the database, runs PHP, assembles the HTML, and serves the page. Fresh every time. That’s great for a five-table restaurant. It’s a disaster when 500 people walk in at once.
Caching is like prepping meals in advance. Instead of cooking every order from scratch, you make a batch, store it in the warming drawer, and serve it instantly. The food is the same. The customer gets it faster. The kitchen doesn’t catch fire.
That’s what caching does for WordPress. It stores a finished copy of your pages so your server doesn’t rebuild them for every visitor. Instead of running 30-50 database queries per page load, it serves a static HTML file. The difference is dramatic. I’ve seen server response times drop from 800ms to 50ms just from page caching.
But here’s what caching doesn’t do. It doesn’t fix a slow server. If your hosting is garbage, caching puts a bandage on a broken leg. It doesn’t fix bloated themes or plugins. A page that loads 3MB of JavaScript will still load 3MB of JavaScript, cached or not. And it doesn’t help logged-in users by default, because their experience is personalized. The admin bar, the “Welcome, John” message, the WooCommerce cart. None of that can be served from a generic cached copy.
Caching fixes the “rebuilding the same page thousands of times” problem. That’s a big problem. But it’s not the only problem.
Types of Caching You Need to Know
There are four types of caching that matter for WordPress. Each one works at a different level, and they stack on top of each other.
Page caching stores the fully built HTML page. This is the big one. When someone visits your homepage, instead of running PHP and querying the database, the server just hands them a saved HTML file. Fast. Simple.
Browser caching tells your visitor’s browser to save certain files locally. CSS, JavaScript, images. The first visit downloads everything. The second visit loads most of it from the browser’s local storage. No network requests needed.
Object caching stores database query results in memory (RAM). WordPress runs the same database queries over and over. Object caching with Redis or Memcached keeps those results in fast memory so the database doesn’t get hammered.
Opcode caching (OPcache) stores compiled PHP code in memory. PHP normally reads your code, compiles it, then executes it. With OPcache, the compiled version stays in memory. It’s handled at the server level, and most decent hosts have it enabled already. You don’t need to touch this one.
These four layers work together. Page caching handles the big picture. Browser caching handles repeat visits. Object caching handles database efficiency. OPcache handles PHP execution. Turn them all on, and your site runs like a different machine.
Page Caching: The Biggest Win
If you do nothing else in this chapter, set up page caching. It’s the single biggest performance improvement you can make on most WordPress sites.
Here’s how it works. When the first visitor hits your “About” page, WordPress runs all its PHP, queries the database, assembles the header, footer, sidebar, content, everything. That takes time. Maybe 200-500ms on a decent server. Page caching saves the finished HTML output to a file. When the second visitor hits that same page, the server skips all the PHP and database work and just serves the saved file. That takes 10-50ms.
The speed difference is 5-20x faster. And the server can handle 10-50x more traffic before it starts struggling.
What Page Caching Skips
Page caching doesn’t work for everything. It skips:
Logged-in users. If you’re logged into WordPress, you see the admin bar, personalized content, and edit links. That’s different for every user, so it can’t be cached. This is fine. Your logged-in users are you and your team, not thousands of visitors.
WooCommerce cart and checkout pages. These are dynamic by nature. Each customer has a different cart. Caching plugins know to exclude these.
Recently updated content. When you publish or update a post, the cache for that page (and usually the homepage) gets cleared automatically. The next visitor triggers a fresh cache.
POST requests. Form submissions, comments, login attempts. These need to hit the server for real.
Pages with specific cookies. If a plugin sets certain cookies (like WooCommerce’s cart cookie), the cache is bypassed for that user.
Good caching plugins handle all of this automatically. You don’t need to manually exclude pages unless you have custom dynamic content that the plugin doesn’t recognize.
Object Caching with Redis or Memcached
Page caching handles your front-end visitors. Object caching handles everything else. Your WordPress admin dashboard, WooCommerce store management, any page that can’t be page-cached because it’s dynamic or personalized.
WordPress has a built-in object cache, but it only lasts for a single page load. Once the page finishes rendering, the cache disappears. That’s like having a cheat sheet you throw away after every test.
Redis and Memcached are in-memory data stores that keep the cache persistent across page loads. WordPress stores query results in Redis, and the next time it needs the same data, it grabs it from memory instead of hitting the database. Memory is thousands of times faster than disk-based database queries.
When You Need It
You need object caching if:
Your site has 10+ active plugins. Each plugin makes database queries. Object caching reduces the load.
You run WooCommerce. Dynamic pages, cart calculations, product queries. Redis makes all of this faster.
Your admin dashboard feels sluggish. Page caching doesn’t help the backend. Object caching does.
You have a membership site or LMS. Logged-in users can’t benefit from page caching. Object caching picks up the slack.
For a simple blog with 5-10 plugins and mostly anonymous visitors? Page caching alone handles 90% of the problem. But the moment you add complexity, Redis becomes worth it.
How to Set It Up on Cloudways
If you’re on Cloudways (which I recommend for managed hosting), Redis is one click away.
- Log into your Cloudways dashboard
- Go to your application settings
- Click “Packages” in the left sidebar
- Find Redis and toggle it on
- Install the “Redis Object Cache” plugin by Till Kruss on your WordPress site
- Go to Settings > Redis in your WordPress admin
- Click “Enable Object Cache”
That’s it. You should see “Connected” status and your cache hit ratio will start climbing. After a day of normal traffic, check the stats. A hit ratio above 85% means Redis is doing its job.
On other hosts, the setup varies. Some managed hosts like Kinsta and WP Engine include Redis in higher-tier plans. On a VPS, you’d install Redis via SSH and configure the wp-config.php constants manually. But Cloudways makes it trivially easy.
Browser Caching: Setting Proper Cache-Control Headers
Browser caching tells visitors’ browsers: “Hey, you already downloaded this CSS file. Don’t download it again for the next 30 days.”
This matters because a typical WordPress page loads 15-30 static files. CSS, JavaScript, images, fonts. On the first visit, every file gets downloaded. On repeat visits, properly cached files load from the browser’s local storage. Zero network requests. Instant.
What to Cache and for How Long
The rule is simple. Files that rarely change get long cache times. Files that change often get short ones.
Images (JPG, PNG, WebP, SVG): Cache for 1 year. You’re not changing your logo every week. If you update an image, the filename usually changes anyway.
CSS and JavaScript: Cache for 1 year. WordPress appends version numbers to CSS/JS URLs (style.css?ver=6.4). When you update the file, the version changes, and the browser treats it as a new file.
Fonts: Cache for 1 year. Font files never change.
HTML pages: Don’t set long browser cache times for HTML. Your page caching plugin handles this at the server level. HTML should be fresh or very short-lived (a few minutes at most).
Most caching plugins set these headers for you. FlyingPress, WP Rocket, and LiteSpeed Cache all handle browser caching out of the box. If you’re using Cloudflare, it sets browser TTL (time to live) based on what your server sends, or you can override it in the Cloudflare dashboard.
Check your headers using Chrome DevTools. Open any page, go to the Network tab, click on a CSS or image file, and look for the Cache-Control header. You should see something like max-age=31536000 (that’s one year in seconds).
My Caching Plugin Recommendation: FlyingPress
I switched from WP Rocket to FlyingPress in 2023, and I haven’t looked back.
WP Rocket is a fine plugin. It’s easy to use, it works out of the box, and it’s the most popular premium caching plugin for a reason. But FlyingPress consistently delivers faster results on the sites I manage. I’ve tested both on identical setups, same server, same theme, same content. FlyingPress produces lower TTFB (Time to First Byte) and better Core Web Vitals scores.
The difference comes down to how FlyingPress handles critical CSS generation, JavaScript deferral, and image lazy loading. It’s more aggressive, and the results show.
FlyingPress Settings I Use on Every Site
Here’s my exact configuration:
Caching tab. Enable page caching. Set mobile caching to “Separate cache” only if your theme serves different markup to mobile (most modern themes don’t, so “Same cache” is fine). Enable cache preloading so pages are cached before visitors arrive, not after.
CSS tab. Enable “Remove Unused CSS.” This is FlyingPress’s strongest feature. It scans each page and strips CSS rules that aren’t used. On most WordPress sites, 60-80% of loaded CSS is unused. Removing it is a massive win for render speed. Enable “Load removed CSS on interaction” as a safety net. Some CSS might be needed for interactive elements that aren’t visible on page load.
JavaScript tab. Enable “Defer JavaScript.” This stops JS from blocking page rendering. Enable “Delay JavaScript” and add third-party scripts (analytics, chat widgets, ads) to the delay list. These don’t need to load until the user interacts with the page.
Images tab. Enable lazy loading for images. Set “Exclude above-the-fold images” to 2-3 (this prevents your hero image from lazy loading, which would cause layout shift). Enable “Add missing width/height” to prevent CLS (Cumulative Layout Shift).
Fonts tab. Enable “Self-host Google Fonts” and “Preload fonts.” This eliminates the third-party connection to Google’s servers and loads fonts faster.
Skip the CDN tab if you’re using Cloudflare. They’ll conflict.
Caching Pitfalls: What Goes Wrong
Caching works beautifully until it doesn’t. Here are the problems I see most often.
Stale Cache
You update a page, but visitors still see the old version. This happens when the cache doesn’t clear properly after an edit. Most caching plugins auto-purge when you save a post, but sometimes it fails. Reasons include: CDN caching on top of plugin caching (double caching), server-level caching (like Varnish) that the plugin doesn’t control, or aggressive browser caching headers on HTML.
Fix: After publishing updates, manually purge your caching plugin, then purge your CDN (Cloudflare has a “Purge Everything” option). If the issue persists, check if your host runs server-level caching (Cloudways uses Varnish by default, and you need to purge it separately or set up the Breeze plugin integration).
Cache Conflicts
Running two caching plugins at once is a recipe for blank pages, broken layouts, and random errors. I’ve seen it dozens of times. Someone installs WP Rocket, forgets about LiteSpeed Cache that came with their host, and wonders why pages look broken.
Fix: One caching plugin only. If your host provides server-level caching (LiteSpeed, Varnish), you can use it alongside a plugin, but disable the plugin’s page caching and let the server handle it. Don’t double up on the same caching layer.
Debugging Cached Pages
“Is this page actually cached?” It’s a valid question, and it’s easy to check.
Method 1: Check response headers. In Chrome DevTools, go to Network > select the HTML document > look for headers like X-Cache: HIT, CF-Cache-Status: HIT (Cloudflare), or X-FlyingPress-Cache: HIT. If you see “MISS,” the page wasn’t served from cache.
Method 2: View page source. Most caching plugins add a comment at the bottom of the HTML source. Look for something like <!-- This page is cached by FlyingPress --> with a timestamp. If it’s there, caching works.
Method 3: Check TTFB. A cached page should have a TTFB under 100ms (often under 50ms). If your TTFB is 300ms+, the page is either not cached or something is intercepting the cache.
The Caching Test: Verify Your Setup Works
After setting up caching, run this quick verification:
- Open an incognito/private browser window (no login cookies)
- Visit your homepage
- Open DevTools > Network tab
- Reload the page
- Click on the first HTML request
- Check the response headers for cache HIT indicators
- Note the TTFB. It should be under 100ms for a cached page
- Visit the page again. TTFB should be similar (proving cache consistency)
Then test the logged-in experience:
- Log into WordPress in a regular browser
- Visit the same page
- TTFB will be higher (200-500ms is normal for uncached/logged-in)
- This confirms that logged-in users bypass the cache correctly
If both tests pass, your caching setup is solid. If the incognito visit shows high TTFB or MISS headers, something isn’t configured right. Go back through your plugin settings and verify page caching is enabled and your page isn’t on the exclusion list.
Caching is the foundation. Get it right, and everything else in this course builds on top of a fast baseline. Get it wrong, and you’ll spend hours optimizing things that won’t matter because the fundamentals aren’t there.
Chapter Checklist
- [ ] Understand the four types of caching: page, browser, object, and opcode
- [ ] Page caching is enabled and verified (check response headers)
- [ ] Browser caching headers are set for static assets (1-year for CSS/JS/images/fonts)
- [ ] Object caching with Redis is set up (if running WooCommerce, membership, or 10+ plugins)
- [ ] Only one caching plugin is active (no double caching)
- [ ] Cache preloading is enabled so pages are ready before visitors arrive
- [ ] Unused CSS removal is enabled in your caching plugin
- [ ] JavaScript defer/delay is configured
- [ ] Stale cache issues are resolved (auto-purge on post update works)
- [ ] You can verify caching is working using response headers or page source comments
Chapter Exercise
Run a caching audit on your site right now:
- Open your homepage in an incognito window with DevTools Network tab open
- Record the TTFB and total load time
- Check the response headers for cache HIT/MISS status
- If MISS: enable page caching, purge, reload, and test again
- If HIT but TTFB is above 200ms: check for server-level caching conflicts
- View page source and search for your caching plugin’s comment at the bottom
- Visit 3 more pages and repeat. All should show HIT status
- Log in and verify that logged-in pages bypass the cache (higher TTFB is expected)
Write down your before and after TTFB numbers. You should see at least a 3-5x improvement on cached pages.
Disclaimer: This site is reader-supported. If you buy through some links, I may earn a small commission at no extra cost to you. I only recommend tools I trust and would use myself. Your support helps keep gauravtiwari.org free and focused on real-world advice. Thanks. - Gaurav Tiwari