If you've ever asked "do I need Redis if WP Rocket is already running?" you're in the right place. The WordPress caching stack has four distinct layers, each solving a different problem. They compose — but only if you understand what each one actually does.
This is the guide I wish existed when I started answering these tickets four years ago.
The four layers
┌──────────────────────────────────────────┐
│ 1. Page cache (Engintron + WP Rocket)
├──────────────────────────────────────────┤
│ 2. Object cache (Redis, Memcached)
├──────────────────────────────────────────┤
│ 3. OPcache (PHP bytecode)
├──────────────────────────────────────────┤
│ 4. Database query cache (buffer pool)
└──────────────────────────────────────────┘Each layer catches a different kind of work. You can skip layers, but skipping the wrong one costs you a lot of performance.
1. Page cache
What it does: Stores the fully-rendered HTML of a page. On a cache hit, PHP never runs. Neither does MySQL. The web server just streams bytes.
What it's good for: 95% of the traffic on 95% of WordPress sites. Blog posts, product listings, static pages — any URL that looks the same for a wide group of visitors.
What we run. Two layers, both of which earn their keep:
- Engintron sits in front of Apache as an nginx reverse proxy. It caches HTML for anonymous visitors at the server level — no plugin needed, no PHP touched. Comes pre-configured on every Rivervo plan.
- WP Rocket (paid) inside WordPress for fine-grained control: per-post cache lifetimes, automatic purge on content updates, lazy-loading, asset minification. The free path: W3 Total Cache or WP Super Cache — install one, turn on page caching, leave the defaults alone.
The two layers compose: Engintron catches the high-volume anonymous traffic at the edge, the WordPress plugin handles the trickier purging logic and asset optimisation.
The catch: Page caches don't help for logged-in users, checkout flows, or any URL that varies per visitor. WooCommerce cart pages, WP-admin, account pages — all bypass the page cache entirely.
2. Object cache
What it does: Stores the results of individual database queries and PHP function calls. Every time WordPress asks "what's the site title?" or "give me this user's metadata," the answer comes from memory instead of running a query.
What it's good for: The 5% of traffic that bypasses the page cache. Logged-in users, WooCommerce checkout, anything dynamic. This is where Redis earns its keep.
What to use: Redis with the redis-cache plugin, or Memcached if you prefer it. Both work. Redis is more common now and has more robust plugin support.
Do you need it on a static blog? No. If every visitor gets a page-cache hit, the object cache never runs. Turn it on when you have significant logged-in traffic or WooCommerce.
The single most common mistake: enabling Redis on a blog that gets 100% page cache hits, then claiming it "didn't do anything." Of course it didn't. It was never asked.
3. OPcache
What it does: Caches the compiled bytecode of PHP files so PHP doesn't re-parse them on every request.
Do you need to configure it? No. We enable it on every account by default, tuned for the shared-hosting workload. If you're on a VPS managing your own PHP install, set opcache.enable=1 and opcache.memory_consumption=256 and move on.
The one gotcha: If you edit PHP files and the change doesn't appear, OPcache might be serving the old bytecode. Restart PHP-FPM or flush OPcache in your dashboard.
4. Database query cache (buffer pool)
What it does: MySQL keeps hot tables and indexes in memory. This isn't really "a cache" in the configurable sense — it's just MySQL doing its job.
What to tune: On a VPS, innodb_buffer_pool_size should be ~60–70% of available RAM for database-heavy workloads. Too small and MySQL thrashes to disk; too big and the OS starves. On shared hosting, we tune this for you.
The order of operations
When a request comes in:
- Engintron (nginx) checks for a cached page. Hit → done, bytes out, Apache never started.
- Miss → request hits Apache → WP Rocket (or W3TC) checks for its own cached HTML. Hit → done.
- Miss → PHP starts. OPcache serves the compiled bytecode.
- PHP runs. Object cache (Redis) serves memoized query results.
- Miss → MySQL serves from buffer pool, or hits disk if cold.
Each layer's job is to prevent the next layer from being touched. That's the whole game.
Practical rules
Here's how I actually configure this for customers:
- Static blog, under 50k monthly visits: Engintron + OPcache. That's it. No WordPress caching plugin needed if Engintron is hitting.
- Blog with heavy commenters or logged-in users: Engintron + WP Rocket + OPcache + Redis.
- WooCommerce store, any size: Engintron (with cart-aware exclusions) + WP Rocket + OPcache + Redis. Redis is not optional.
- Membership or LMS site: WP Rocket + OPcache + Redis. Bypass Engintron for logged-in URLs and configure caching to vary on user role inside the plugin.
- Headless WordPress with a JS frontend: Object cache (Redis) is more important than page cache. Configure carefully.
Common mistakes
Turning on every WordPress caching plugin at once. W3 Total Cache on top of WP Rocket is worse than either alone. Pick one and commit.
Enabling Redis without a persistent connection. The plugin defaults work, but on high-traffic WooCommerce stores you want redis.session.save_handler = redis and Unix socket connections if your host supports them.
Not testing cache purge rules. A correctly-configured cache is invisible. A misconfigured one serves stale prices to your customers. Always test "update product → reload page → verify new price" before declaring victory.
Bottom line
Caching isn't one thing. It's four things that have to compose correctly. Start with the page cache — that alone solves 95% of the problem. Add Redis only when you have dynamic traffic that needs it. Leave OPcache and the MySQL buffer pool to your host.
If you're hosting with us and any of this isn't working, open a ticket and we'll look at your specific setup.
— Oona