How Caching Works
This guide explains the internals of MilliCache's caching mechanism, from request interception to cache serving.
The Caching Lifecycle#
1. Request Interception#
When a request arrives, WordPress loads the advanced-cache.php drop-in before most of WordPress initializes. MilliCache's Engine starts here:
Request → wp-config.php → advanced-cache.php → MilliCache Engine
This early interception enables:
- Serving cached content without loading WordPress
- Evaluating rules before plugins load
- Minimal resource usage for cache hits
2. Bootstrap Rules Evaluation#
Before WordPress loads, MilliCache evaluates Bootstrap Rules to determine if caching should proceed:
| Rule | Condition | Result |
|---|---|---|
| WP_CACHE check | WP_CACHE !== true |
Skip caching |
| Request method | Not GET or HEAD | Skip caching |
| CLI check | Running via WP-CLI | Skip caching |
| REST API | REST_REQUEST === true |
Skip caching |
| XMLRPC | XMLRPC_REQUEST === true |
Skip caching |
| File request | URL matches file pattern | Skip caching |
| No-cache cookies | Excluded cookie present | Skip caching |
| No-cache paths | URL matches excluded path | Skip caching |
| TTL check | TTL ≤ 0 | Skip caching |
If any rule triggers cache bypass, MilliCache lets WordPress handle the request normally.
3. Cache Lookup#
If caching proceeds, MilliCache generates a cache key from:
- Request URL (path and query string)
- Cookies (excluding ignored ones)
- Custom unique variables (if configured)
The key is hashed and used to look up cached content in Redis:
Cache Key = hash( URL + filtered_cookies + unique_vars )
4. Cache Hit#
If cached content exists and is fresh:
- Decompress content (if gzip enabled)
- Send stored HTTP headers
- Output HTML to browser
- Exit immediately (WordPress never loads)
Response time: typically 5-15ms.
5. Cache Miss#
If no cache exists or content is expired:
- Let WordPress load normally
- Register WordPress Rules on
plugins_loaded - Start output buffering on
template_redirect(priority 200) - Evaluate WordPress Rules to either cache or bypass
- Capture the complete response
- Store in Redis with flags
- Send response to browser
6. Grace Period Serving#
If cached content is expired but within the grace period:
- Serve stale content immediately
- Mark cache for regeneration
- Next request triggers actual regeneration
- Fresh content stored for future requests
This ensures visitors never wait for page generation.
Cache Storage Structure#
Each cache entry contains:
| Component | Description |
|---|---|
content |
Full HTML response |
headers |
HTTP response headers |
flags |
Tags for invalidation |
created |
Timestamp when cached |
ttl |
Time-to-live value |
grace |
Grace period value |
gzip |
Compression status |
Flags (Tags)#
Every cached page is tagged with flags for targeted invalidation:
Homepage: [home, archive:post]
Single post: [post:123]
Archives: [archive:category:5, archive:post]
Author: [archive:author:1]
When a post is updated, MilliCache clears all entries matching its flags.
Cache Flow Diagram#
┌──────────────────────────────────────────────────────────┐
│ REQUEST │
└──────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ advanced-cache.php │
│ (MilliCache Engine) │
└──────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ Bootstrap Rules │
│ [WP_CACHE] [Method] [Cookies] [Paths] [CLI] [REST] │
└──────────────────────────────────────────────────────────┘
│
┌────────────────────┴────────────────┐
│ │
Skip Cache Continue
│ │
▼ ▼
┌───────────────────┐ ┌─────────────────────────────┐
│ Load WordPress │ │ Generate Cache Key │
│ (no caching) │ │ URL + Cookies + ... │
└───────────────────┘ └─────────────────────────────┘
│
▼
┌───────────────────────────┐
│ Redis Lookup │
└───────────────────────────┘
│
┌───────────────────────────┼───────────────────────────┐
│ │ │
Cache HIT Cache MISS Grace HIT
│ │ │
▼ ▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐
│ Decompress (if gzip) │ │ Load WordPress │ │ Serve Stale Content │
│ Send Headers │ │ Register WP Rules │ │ Mark for Regeneration │
│ Output HTML │ │ Buffer Output │ └─────────────────────────┘
│ EXIT (~5-15ms) │ │ Store with Flags │
└─────────────────────────┘ │ Send Response │
└─────────────────────────┘
Cache Status Values#
| Status | Meaning |
|---|---|
hit |
Fresh cached content served |
miss |
No cache exists, content generated |
bypass |
Caching skipped (rule matched) |
grace |
Stale content served, regeneration pending |
View status via debug headers:
X-MilliCache-Status: hit
What Gets Cached#
Cached:
- GET and HEAD requests
- 200 OK responses
- Anonymous (logged-out) visitors
- Pages, posts, archives, taxonomies
- Custom post types and taxonomies
- Static front page
- RSS/Atom feeds (unless excluded)
Not Cached:
- POST, PUT, DELETE requests
- Logged-in users
- Non-200 responses (404, 500, etc.)
- AJAX requests (
DOING_AJAX) - Cron requests (
DOING_CRON) - REST API requests (
REST_REQUEST) - WP-CLI commands
- Pages with
DONOTCACHEPAGEconstant - Requests matching excluded cookies/paths
Cache Key Components#
The cache key ensures unique caching per variation:
| Component | Example | Effect |
|---|---|---|
| URL path | /blog/hello-world/ |
Each URL cached separately |
| Query string | ?page=2 |
Pagination cached separately |
| Filtered cookies | currency=USD |
Custom variations (if configured) |
| Unique variables | device=mobile |
Custom variations (if configured) |
Ignored Components#
By default, these don't affect the cache key:
- Cookies starting with
_(analytics) - Query params starting with
_orutm_ - Fragment identifiers (
#section)
Performance Characteristics#
| Metric | Cache Hit | Cache Miss |
|---|---|---|
| Response Time | 5-15ms | 200-2000ms |
| PHP Execution | None | Full WordPress |
| Database Queries | 0 | Typically 20-100+ |
| Memory Usage | Minimal | Full application |
Next Steps#
- Cache Clearing - Understand invalidation
- Rules - Condition-based caching control
- Cache Flags - Targeted invalidation