Caching Strategies
The Caching Stack
Effective WordPress caching happens at multiple levels:
User Request
↓
[CDN Cache] ← Edge location
↓
[Page Cache] ← Full HTML
↓
[Object Cache] ← Database queries
↓
[Opcode Cache] ← PHP compilation
↓
DatabasePage Caching
Page caching stores fully rendered HTML pages, bypassing PHP entirely.
Popular Caching Plugins
| Plugin | Best For |
|---|---|
| WP Super Cache | Simple sites |
| W3 Total Cache | Advanced users |
| WP Rocket | Premium, all-in-one |
| LiteSpeed Cache | LiteSpeed servers |
| WP Fastest Cache | Beginners |
Manual Page Caching
// Simple page cache implementation
function my_page_cache_start() {
$cache_file = WP_CONTENT_DIR . '/cache/' . md5($_SERVER['REQUEST_URI']) . '.html';
if (file_exists($cache_file) && (time() - filemtime($cache_file) < 3600)) {
readfile($cache_file);
exit;
}
ob_start();
}
function my_page_cache_end() {
$cache_file = WP_CONTENT_DIR . '/cache/' . md5($_SERVER['REQUEST_URI']) . '.html';
file_put_contents($cache_file, ob_get_contents());
ob_end_flush();
}
Don't Cache Dynamic Content: Exclude shopping carts, user dashboards, and logged-in pages from page caching.
Object Caching
Object caching stores database query results in memory.
Redis/Memcached
// wp-config.php
define('WP_CACHE', true);
// Object cache with Redis
define('WP_REDIS_HOST', '127.0.0.1');
define('WP_REDIS_PORT', 6379);
define('WP_REDIS_DATABASE', 0);Using Transients
function get_expensive_data() {
// Try cache first
$data = get_transient('my_expensive_data');
if (false === $data) {
// Cache miss - do expensive operation
$data = expensive_database_query();
// Store for 1 hour
set_transient('my_expensive_data', $data, HOUR_IN_SECONDS);
}
return $data;
}
// Clear when data changes
function on_data_updated() {
delete_transient('my_expensive_data');
}
add_action('save_post', 'on_data_updated');WordPress Object Cache API
// Store with expiration
wp_cache_set('my_key', $data, 'my_group', 3600);
// Retrieve
$data = wp_cache_get('my_key', 'my_group');
// Delete
wp_cache_delete('my_key', 'my_group');
// Delete entire group
wp_cache_flush_group('my_group');Browser Caching
Control how browsers cache static assets:
# .htaccess
<IfModule mod_expires.c>
ExpiresActive On
# Images
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
# CSS/JS
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
# Fonts
ExpiresByType font/woff2 "access plus 1 year"
# HTML - don't cache
ExpiresByType text/html "access plus 0 seconds"
</IfModule>
# Cache-Control headers
<IfModule mod_headers.c>
<FilesMatch ".(ico|jpg|jpeg|png|gif|webp|svg|js|css|woff2)$">
Header set Cache-Control "max-age=31536000, public, immutable"
</FilesMatch>
</IfModule>CDN Integration
A CDN serves static assets from edge locations worldwide.
Popular CDNs for WordPress
| CDN | Highlights |
|---|---|
| Cloudflare | Free tier, full proxy |
| BunnyCDN | Affordable, fast |
| KeyCDN | Pay-as-you-go |
| StackPath | Enterprise features |
Basic CDN Setup
// Change asset URLs to CDN
define('WP_CONTENT_URL', 'https://cdn.example.com/wp-content');
// Or use a filter
add_filter('wp_get_attachment_url', function($url) {
return str_replace(
'https://example.com',
'https://cdn.example.com',
$url
);
});Cloudflare Page Rules
Create rules for optimal caching:
# Cache static assets aggressively
URL: *example.com/wp-content/*
Cache Level: Cache Everything
Edge TTL: 1 month
# Bypass cache for admin
URL: *example.com/wp-admin/*
Cache Level: BypassPreloading & Hints
<!-- DNS prefetch for third parties -->
<link rel="dns-prefetch" href="//fonts.googleapis.com">
<!-- Preconnect for critical resources -->
<link rel="preconnect" href="https://cdn.example.com" crossorigin>
<!-- Preload critical assets -->
<link rel="preload" href="/fonts/custom.woff2" as="font" crossorigin>
<link rel="preload" href="/hero.webp" as="image">
<!-- Prefetch next page -->
<link rel="prefetch" href="/next-page/">Cache Invalidation
// Clear page cache on post update
add_action('save_post', function($post_id) {
// Clear specific cache
if (function_exists('wp_cache_delete_page')) {
wp_cache_delete_page($post_id);
}
// Clear homepage
if (function_exists('wp_cache_delete_url')) {
wp_cache_delete_url(home_url('/'));
}
});
// Clear all caches
function clear_all_caches() {
// Object cache
wp_cache_flush();
// W3 Total Cache
if (function_exists('w3tc_flush_all')) {
w3tc_flush_all();
}
// LiteSpeed Cache
if (class_exists('LiteSpeed_Cache_API')) {
LiteSpeed_Cache_API::purge_all();
}
}Next Steps
In the next lesson, we'll optimize images - often the biggest performance impact.
🎯 Lesson Complete! You can now implement multi-level caching for WordPress.