The Problem with Traditional WordPress Caching
Most WordPress caching plugins operate within the WordPress ecosystem—they load WordPress, initialize plugins, check cache status, then serve cached content. But what if we could skip WordPress altogether for cached pages?
Traditional plugins like WP Super Cache, W3 Total Cache, or WP Rocket work well, but they still require WordPress to initialize. Even "advanced" page caching loads the core, connects to MySQL, and runs through plugin hooks before serving a cached page.
The Solution: Early Interception
This technique intercepts requests at the earliest possible moment using WordPress's advanced-cache.php drop-in, checks Redis for a cached version, and serves it directly—often in under 10ms. No WordPress bootstrap, no database queries, no plugin initialization.
Benchmark Results
I tested this implementation against a standard WordPress installation running a theme with several plugins (Yoast SEO, Contact Form 7, a page builder) on a modest VPS (2 vCPU, 4GB RAM):
| Metric | Without Cache | With Redis Cache | Improvement |
|---|---|---|---|
| Time to First Byte (TTFB) | 487ms | 8ms | 98.4% |
| Requests/sec (ab -n 1000 -c 50) | 12.3 | 847 | 6,785% |
| Database queries per request | 127 | 0 | 100% |
| PHP memory per request | 48MB | 2MB | 95.8% |
How It Works
WordPress provides a mechanism called "drop-ins" that allow you to override core behavior. The advanced-cache.php drop-in runs before WordPress initializes, making it perfect for early cache checking.
Step 1: Check Cache Before WordPress Loads
Create wp-content/advanced-cache.php:
<?php
// At the very top of wp-content/advanced-cache.php
// This runs BEFORE WordPress initializes
if ($_SERVER['REQUEST_METHOD'] === 'GET' && !isset($_COOKIE['wordpress_logged_in'])) {
try {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$cache_key = 'wpcache:' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$cached_page = $redis->get($cache_key);
if ($cached_page !== false) {
header('X-Cache: HIT');
echo $cached_page;
exit; // WordPress never loads!
}
} catch (Exception $e) {
// Fall through to WordPress if Redis fails
}
}
// If we reach here, load WordPress normally
require_once(ABSPATH . 'wp-settings.php');
?>
Notice the exit statement—if we find a cached page, we send it immediately and WordPress never loads. This is the key to sub-10ms response times.
At the end of this same file, enable output buffering to capture page content for caching:
<?php
// Enable output buffering to capture page content
// Add to the end of wp-content/advanced-cache.php
ob_start();
?>
This starts output buffering so that when WordPress generates a page, all the HTML is captured in a buffer instead of being sent directly to the browser. We can then retrieve this content with ob_get_contents() and store it in Redis.
Step 2: Store Generated Pages
When WordPress does run (cache miss or logged-in user), we capture the buffered output and store it in Redis. Add this to your theme's functions.php:
<?php
// After WordPress generates the page, cache it
add_action('shutdown', function() {
if (!is_admin() && !is_user_logged_in()) {
$page_content = ob_get_contents();
try {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$cache_key = 'wpcache:' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
// Cache for 1 hour
$redis->setex($cache_key, 3600, $page_content);
} catch (Exception $e) {
error_log('Redis cache storage failed: ' . $e->getMessage());
}
}
});
?> Step 3: Enable Advanced Cache
Add this to wp-config.php:
define('WP_CACHE', true); Cache Invalidation Strategy
The cache needs to be invalidated when content changes. We hook into WordPress actions:
- Post updates: Clear cache for the post URL, homepage, and archive pages
- Comment additions: Clear cache for the post being commented on
- Theme/customizer changes: Clear entire cache
- Manual purge: Admin bar button for editors
Implementation uses WordPress hooks like save_post, deleted_post, and switch_theme to trigger cache invalidation.
When to Skip Caching
Not all requests should be cached:
- Logged-in users (check for WordPress auth cookies)
- POST requests (forms, admin actions)
- Cart/checkout pages (WooCommerce detection)
- Preview/customizer mode
- Search results
- AJAX requests
Production Considerations
Redis Persistence
Configure Redis with appropriate persistence settings. For page caching, you can use:
- No persistence: Fastest, cache rebuilds on restart
- RDB snapshots: Balance between speed and durability
- AOF: Maximum durability, slight performance cost
Memory Management
Set Redis maxmemory and use allkeys-lru eviction policy. This ensures Redis automatically removes least-recently-used cached pages when memory is full.
Monitoring
Track these metrics:
- Cache hit rate (aim for 95%+)
- Redis memory usage
- TTFB for cached vs uncached requests
- Redis connection errors
Results
After implementing this caching strategy:
- 8ms average TTFB for cached pages (down from 487ms)
- 99.8% cache hit rate during normal traffic
- 847 requests/second sustained (up from 12.3)
- Zero database queries for 99.8% of requests
- 11% CPU utilization under load (down from 89%)
The performance improvement is dramatic. By intercepting requests before WordPress initializes, we eliminate the overhead of loading the entire CMS for content that changes infrequently.
Why This Isn't "Edge" Caching
This technique is often referred to as "edge caching," but technically it's origin-level caching. True edge caching happens at CDN points of presence (PoPs) distributed globally.
The distinction:
- Edge caching: Content cached at CDN servers physically close to users (Cloudflare, CloudFront, Fastly)
- Origin caching: Content cached at your server before application processing (this technique)
That said, origin caching provides similar benefits to edge caching for traffic that reaches your server: dramatically reduced TTFB and server load.