By Devport Team | Last updated: 2025-07-12 | 22 min read

The Comprehensive Guide to WordPress Caching Strategies

Caching is the single most effective way to improve WordPress performance. By storing frequently accessed data in fast-access memory, caching can reduce page load times from seconds to milliseconds. However, implementing effective caching requires understanding multiple layers and choosing the right strategy for your specific needs.

This comprehensive guide covers every aspect of WordPress caching, from basic browser caching to advanced edge caching strategies. Whether you're running a small blog or a high-traffic e-commerce site, you'll learn how to implement caching that dramatically improves performance while maintaining dynamic functionality.

Table of Contents

  1. Understanding Caching Layers
  2. Page Caching Implementation
  3. Object Caching with Redis/Memcached
  4. Browser and CDN Caching
  5. Database Query Caching
  6. Advanced Caching Techniques
  7. Cache Management and Invalidation

Understanding Caching Layers

The WordPress Caching Stack

Effective caching involves multiple layers, each serving a specific purpose:

┌─────────────────────────────────────┐
│     Browser Cache                   │ ← Fastest (0ms)
│     (User's Device)                 │
├─────────────────────────────────────┤
│     CDN Cache                       │ ← Very Fast (10-50ms)
│     (Global Edge Servers)           │
├─────────────────────────────────────┤
│     Page Cache                      │ ← Fast (1-5ms)
│     (Nginx/Varnish/Plugin)          │
├─────────────────────────────────────┤
│     Object Cache                    │ ← Fast (1-2ms)
│     (Redis/Memcached)               │
├─────────────────────────────────────┤
│     OpCode Cache                    │ ← Very Fast (0.1ms)
│     (OPcache)                       │
├─────────────────────────────────────┤
│     Database Cache                  │ ← Moderate (1-10ms)
│     (MySQL Query Cache)             │
└─────────────────────────────────────┘

How Caching Works

// Basic caching concept
function get_expensive_data($key) {
    // Check cache first
    $cached_data = wp_cache_get($key, 'my_cache_group');

    if ($cached_data !== false) {
        return $cached_data; // Cache hit!
    }

    // Cache miss - compute expensive operation
    $data = perform_expensive_operation();

    // Store in cache for next time
    wp_cache_set($key, $data, 'my_cache_group', 3600); // Cache for 1 hour

    return $data;
}

Cache Hit Rates and Performance

Cache Type Typical Hit Rate Performance Impact
Browser Cache 80-90% Eliminates request entirely
CDN Cache 70-85% Reduces latency significantly
Page Cache 60-80% Bypasses PHP/WordPress
Object Cache 85-95% Speeds up database queries
OpCode Cache 95-99% Eliminates PHP compilation

Page Caching Implementation

Server-Level Page Caching with Nginx

# Nginx FastCGI cache configuration
http {
    # Define cache zone
    fastcgi_cache_path /var/cache/nginx levels=1:2 
                       keys_zone=WORDPRESS:100m 
                       inactive=60m 
                       max_size=1g;

    # Cache key to use
    fastcgi_cache_key "$scheme$request_method$host$request_uri";

    # Cache status header
    add_header X-Cache-Status $upstream_cache_status;
}

server {
    listen 80;
    server_name example.com;
    root /var/www/wordpress;

    # Cache bypass conditions
    set $skip_cache 0;

    # POST requests and URLs with query string
    if ($request_method = POST) {
        set $skip_cache 1;
    }

    if ($query_string != "") {
        set $skip_cache 1;
    }

    # Don't cache these pages
    if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|sitemap(_index)?.xml") {
        set $skip_cache 1;
    }

    # Don't cache for logged in users
    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
        set $skip_cache 1;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;

        # FastCGI cache settings
        fastcgi_cache WORDPRESS;
        fastcgi_cache_valid 200 301 302 60m;
        fastcgi_cache_valid 404 1m;
        fastcgi_cache_use_stale error timeout updating invalid_header http_500;
        fastcgi_cache_bypass $skip_cache;
        fastcgi_no_cache $skip_cache;

        # Cache purging
        fastcgi_cache_purge $purge_method;
    }
}

Plugin-Based Page Caching

// Custom page caching implementation
class Advanced_Page_Cache {
    private $cache_dir;
    private $cache_time = 3600;
    private $excluded_urls = [];

    public function __construct() {
        $this->cache_dir = WP_CONTENT_DIR . '/cache/pages/';
        $this->excluded_urls = [
            '/wp-admin/',
            '/wp-login.php',
            '/cart/',
            '/checkout/',
            '/my-account/'
        ];

        // Only cache for non-logged-in users
        if (!is_user_logged_in() && !is_admin()) {
            add_action('init', [$this, 'start_cache'], 1);
            add_action('shutdown', [$this, 'end_cache'], 999);
        }

        // Cache clearing hooks
        add_action('save_post', [$this, 'clear_post_cache']);
        add_action('comment_post', [$this, 'clear_comment_cache']);
        add_action('switch_theme', [$this, 'clear_all_cache']);
    }

    public function start_cache() {
        if ($this->should_cache()) {
            $cache_file = $this->get_cache_file();

            if ($this->is_cache_valid($cache_file)) {
                $this->serve_cache($cache_file);
                exit;
            }

            ob_start();
        }
    }

    public function end_cache() {
        if ($this->should_cache() && ob_get_level() > 0) {
            $content = ob_get_contents();

            if (!empty($content)) {
                $this->save_cache($content);
            }
        }
    }

    private function should_cache() {
        // Don't cache POST requests
        if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
            return false;
        }

        // Don't cache if there are GET parameters (except allowed ones)
        $allowed_params = ['utm_source', 'utm_medium', 'utm_campaign'];
        $query_params = array_diff(array_keys($_GET), $allowed_params);
        if (!empty($query_params)) {
            return false;
        }

        // Check excluded URLs
        $current_url = $_SERVER['REQUEST_URI'];
        foreach ($this->excluded_urls as $excluded) {
            if (strpos($current_url, $excluded) !== false) {
                return false;
            }
        }

        // Don't cache 404s
        if (is_404()) {
            return false;
        }

        return true;
    }

    private function get_cache_file() {
        $url = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
        $hash = md5($url);

        // Create subdirectory based on first 2 characters of hash
        $subdir = substr($hash, 0, 2);
        $dir = $this->cache_dir . $subdir . '/';

        if (!file_exists($dir)) {
            wp_mkdir_p($dir);
        }

        return $dir . $hash . '.html';
    }

    private function is_cache_valid($cache_file) {
        if (!file_exists($cache_file)) {
            return false;
        }

        $file_time = filemtime($cache_file);
        $current_time = time();

        return ($current_time - $file_time) < $this->cache_time;
    }

    private function serve_cache($cache_file) {
        // Set cache headers
        header('X-Cache: HIT');
        header('X-Cache-Time: ' . date('Y-m-d H:i:s', filemtime($cache_file)));

        // Serve gzipped content if supported
        if (function_exists('gzencode') && 
            isset($_SERVER['HTTP_ACCEPT_ENCODING']) && 
            strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false) {

            $gzip_file = $cache_file . '.gz';

            if (file_exists($gzip_file)) {
                header('Content-Encoding: gzip');
                readfile($gzip_file);
            } else {
                readfile($cache_file);
            }
        } else {
            readfile($cache_file);
        }
    }

    private function save_cache($content) {
        $cache_file = $this->get_cache_file();

        // Add cache information comment
        $cache_info = sprintf(
            "\n<!-- Cached on %s -->\n<!-- Cache expires on %s -->",
            date('Y-m-d H:i:s'),
            date('Y-m-d H:i:s', time() + $this->cache_time)
        );

        $content .= $cache_info;

        // Save regular version
        file_put_contents($cache_file, $content);

        // Save gzipped version
        if (function_exists('gzencode')) {
            $gzipped = gzencode($content, 9);
            file_put_contents($cache_file . '.gz', $gzipped);
        }
    }

    public function clear_post_cache($post_id) {
        if (wp_is_post_revision($post_id)) {
            return;
        }

        $post = get_post($post_id);
        if ($post->post_status !== 'publish') {
            return;
        }

        // Clear specific URLs
        $urls_to_clear = [
            get_permalink($post_id),
            home_url('/'),
            get_post_type_archive_link($post->post_type)
        ];

        // Add category and tag pages
        $taxonomies = get_object_taxonomies($post->post_type);
        foreach ($taxonomies as $taxonomy) {
            $terms = wp_get_object_terms($post_id, $taxonomy);
            foreach ($terms as $term) {
                $urls_to_clear[] = get_term_link($term);
            }
        }

        foreach ($urls_to_clear as $url) {
            $this->clear_url_cache($url);
        }
    }

    private function clear_url_cache($url) {
        $parsed = parse_url($url);
        $cache_url = $parsed['host'] . $parsed['path'];
        $hash = md5($cache_url);
        $subdir = substr($hash, 0, 2);

        $files = [
            $this->cache_dir . $subdir . '/' . $hash . '.html',
            $this->cache_dir . $subdir . '/' . $hash . '.html.gz'
        ];

        foreach ($files as $file) {
            if (file_exists($file)) {
                unlink($file);
            }
        }
    }

    public function clear_all_cache() {
        $this->recursive_rmdir($this->cache_dir);
        wp_mkdir_p($this->cache_dir);
    }

    private function recursive_rmdir($dir) {
        if (is_dir($dir)) {
            $objects = scandir($dir);
            foreach ($objects as $object) {
                if ($object != "." && $object != "..") {
                    if (is_dir($dir . "/" . $object)) {
                        $this->recursive_rmdir($dir . "/" . $object);
                    } else {
                        unlink($dir . "/" . $object);
                    }
                }
            }
            rmdir($dir);
        }
    }
}

// Initialize page cache
new Advanced_Page_Cache();

Varnish Configuration

# Varnish VCL for WordPress
vcl 4.0;

import std;

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .connect_timeout = 600s;
    .first_byte_timeout = 600s;
    .between_bytes_timeout = 600s;
}

# ACL for purging
acl purge {
    "localhost";
    "127.0.0.1";
    "::1";
}

sub vcl_recv {
    # Normalize the host header
    if (req.http.host ~ "(?i)^(www.)?example.com") {
        set req.http.host = "example.com";
    }

    # Allow purging
    if (req.method == "PURGE") {
        if (!client.ip ~ purge) {
            return (synth(405, "Not allowed."));
        }
        return (purge);
    }

    # Normalize the query string
    set req.url = std.querysort(req.url);

    # Remove tracking parameters
    if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=") {
        set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
        set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
        set req.url = regsub(req.url, "\?&", "?");
        set req.url = regsub(req.url, "\?$", "");
    }

    # Remove cookies for static files
    if (req.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|otf|ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") {
        unset req.http.Cookie;
        return (hash);
    }

    # Don't cache WordPress admin
    if (req.url ~ "wp-admin|wp-login|preview=true") {
        return (pass);
    }

    # Don't cache these pages
    if (req.url ~ "/(cart|my-account|checkout|addons)") {
        return (pass);
    }

    # Remove cookies for cached pages
    if (req.http.Cookie) {
        set req.http.Cookie = ";" + req.http.Cookie;
        set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
        set req.http.Cookie = regsuball(req.http.Cookie, ";(wordpress_logged_in_|wp-postpass_|comment_author_)=", "; \1=");
        set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
        set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");

        if (req.http.Cookie == "") {
            unset req.http.Cookie;
        }
    }
}

sub vcl_backend_response {
    # Set grace period
    set beresp.grace = 6h;

    # Set cache time for different content types
    if (bereq.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|otf|ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") {
        unset beresp.http.set-cookie;
        set beresp.ttl = 1y;
    }

    # Cache HTML for 10 minutes
    if (beresp.http.content-type ~ "text/html") {
        set beresp.ttl = 10m;
    }
}

sub vcl_deliver {
    # Add cache hit/miss header
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
        set resp.http.X-Cache-Hits = obj.hits;
    } else {
        set resp.http.X-Cache = "MISS";
    }
}

Object Caching with Redis/Memcached

Redis Implementation

// Redis object cache drop-in (object-cache.php)
class WP_Object_Cache {
    private $redis;
    private $connected = false;
    private $cache = [];
    private $global_groups = [];
    private $non_persistent_groups = [];
    private $multisite = false;
    private $blog_prefix;

    public function __construct() {
        $this->multisite = is_multisite();
        $this->blog_prefix = $this->multisite ? get_current_blog_id() . ':' : '';

        $this->connect();

        // Define global groups
        $this->global_groups = [
            'users', 'userlogins', 'usermeta', 'user_meta',
            'site-transient', 'site-options', 'site-lookup',
            'blog-lookup', 'blog-details', 'rss',
            'global-cache-test', 'networks', 'sites'
        ];

        // Define non-persistent groups
        $this->non_persistent_groups = ['counts', 'plugins'];
    }

    private function connect() {
        try {
            $this->redis = new Redis();

            // Connection parameters
            $host = defined('WP_REDIS_HOST') ? WP_REDIS_HOST : '127.0.0.1';
            $port = defined('WP_REDIS_PORT') ? WP_REDIS_PORT : 6379;
            $timeout = defined('WP_REDIS_TIMEOUT') ? WP_REDIS_TIMEOUT : 1;

            // Connect
            $this->connected = $this->redis->connect($host, $port, $timeout);

            // Authentication
            if ($this->connected && defined('WP_REDIS_PASSWORD')) {
                $this->connected = $this->redis->auth(WP_REDIS_PASSWORD);
            }

            // Select database
            if ($this->connected && defined('WP_REDIS_DATABASE')) {
                $this->connected = $this->redis->select(WP_REDIS_DATABASE);
            }

            // Set serialization
            if ($this->connected) {
                $this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
            }

        } catch (Exception $e) {
            $this->connected = false;
            error_log('Redis connection failed: ' . $e->getMessage());
        }
    }

    public function get($key, $group = 'default', $force = false, &$found = null) {
        if (!$this->connected) {
            $found = false;
            return false;
        }

        $derived_key = $this->build_key($key, $group);

        // Check local cache first
        if (isset($this->cache[$derived_key]) && !$force) {
            $found = true;
            return $this->cache[$derived_key];
        }

        // Non-persistent groups
        if (in_array($group, $this->non_persistent_groups)) {
            $found = false;
            return false;
        }

        try {
            $value = $this->redis->get($derived_key);

            if ($value === false) {
                $found = false;
                return false;
            }

            $this->cache[$derived_key] = $value;
            $found = true;

            return $value;

        } catch (Exception $e) {
            $found = false;
            return false;
        }
    }

    public function set($key, $data, $group = 'default', $expire = 0) {
        if (!$this->connected) {
            return false;
        }

        $derived_key = $this->build_key($key, $group);

        // Store in local cache
        $this->cache[$derived_key] = $data;

        // Non-persistent groups
        if (in_array($group, $this->non_persistent_groups)) {
            return true;
        }

        try {
            if ($expire > 0) {
                return $this->redis->setex($derived_key, $expire, $data);
            } else {
                return $this->redis->set($derived_key, $data);
            }
        } catch (Exception $e) {
            return false;
        }
    }

    public function delete($key, $group = 'default') {
        if (!$this->connected) {
            return false;
        }

        $derived_key = $this->build_key($key, $group);

        unset($this->cache[$derived_key]);

        if (in_array($group, $this->non_persistent_groups)) {
            return true;
        }

        try {
            return $this->redis->del($derived_key) > 0;
        } catch (Exception $e) {
            return false;
        }
    }

    public function flush() {
        $this->cache = [];

        if (!$this->connected) {
            return false;
        }

        try {
            if ($this->multisite) {
                // Flush only current site's keys
                $pattern = $this->blog_prefix . '*';
                $keys = $this->redis->keys($pattern);

                if (!empty($keys)) {
                    return $this->redis->del($keys) > 0;
                }

                return true;
            } else {
                return $this->redis->flushDB();
            }
        } catch (Exception $e) {
            return false;
        }
    }

    public function add($key, $data, $group = 'default', $expire = 0) {
        if (!$this->connected) {
            return false;
        }

        if ($this->get($key, $group) !== false) {
            return false;
        }

        return $this->set($key, $data, $group, $expire);
    }

    public function replace($key, $data, $group = 'default', $expire = 0) {
        if (!$this->connected) {
            return false;
        }

        if ($this->get($key, $group) === false) {
            return false;
        }

        return $this->set($key, $data, $group, $expire);
    }

    public function incr($key, $offset = 1, $group = 'default') {
        if (!$this->connected) {
            return false;
        }

        $derived_key = $this->build_key($key, $group);

        try {
            $value = $this->redis->incrBy($derived_key, $offset);
            $this->cache[$derived_key] = $value;

            return $value;
        } catch (Exception $e) {
            return false;
        }
    }

    public function decr($key, $offset = 1, $group = 'default') {
        return $this->incr($key, -$offset, $group);
    }

    private function build_key($key, $group = 'default') {
        if (empty($group)) {
            $group = 'default';
        }

        $prefix = in_array($group, $this->global_groups) ? '' : $this->blog_prefix;

        return WP_CACHE_KEY_SALT . $prefix . $group . ':' . $key;
    }

    public function stats() {
        if (!$this->connected) {
            return [];
        }

        try {
            $info = $this->redis->info();

            return [
                'hits' => isset($info['keyspace_hits']) ? $info['keyspace_hits'] : 0,
                'misses' => isset($info['keyspace_misses']) ? $info['keyspace_misses'] : 0,
                'uptime' => isset($info['uptime_in_seconds']) ? $info['uptime_in_seconds'] : 0,
                'memory_used' => isset($info['used_memory_human']) ? $info['used_memory_human'] : '0B'
            ];
        } catch (Exception $e) {
            return [];
        }
    }

    public function close() {
        if ($this->connected && $this->redis) {
            try {
                $this->redis->close();
            } catch (Exception $e) {
                // Ignore close errors
            }
        }

        $this->connected = false;
    }

    public function __destruct() {
        $this->close();
    }
}

// Initialize global cache object
$GLOBALS['wp_object_cache'] = new WP_Object_Cache();

Memcached Implementation

// Memcached configuration
class Memcached_Cache {
    private $memcached;
    private $servers = [];

    public function __construct() {
        $this->servers = [
            ['127.0.0.1', 11211, 100], // host, port, weight
        ];

        $this->connect();
    }

    private function connect() {
        $this->memcached = new Memcached();

        // Set options
        $this->memcached->setOptions([
            Memcached::OPT_COMPRESSION => false,
            Memcached::OPT_SERIALIZER => Memcached::SERIALIZER_PHP,
            Memcached::OPT_PREFIX_KEY => WP_CACHE_KEY_SALT,
            Memcached::OPT_DISTRIBUTION => Memcached::DISTRIBUTION_CONSISTENT,
            Memcached::OPT_LIBKETAMA_COMPATIBLE => true,
            Memcached::OPT_NO_BLOCK => true,
            Memcached::OPT_TCP_NODELAY => true,
            Memcached::OPT_CONNECT_TIMEOUT => 2000, // 2 seconds
            Memcached::OPT_RETRY_TIMEOUT => 2,
            Memcached::OPT_SERVER_FAILURE_LIMIT => 3,
        ]);

        // Add servers
        foreach ($this->servers as $server) {
            $this->memcached->addServer($server[0], $server[1], $server[2]);
        }
    }

    public function get($key, $group = 'default') {
        $derived_key = $this->build_key($key, $group);
        return $this->memcached->get($derived_key);
    }

    public function set($key, $data, $group = 'default', $expire = 0) {
        $derived_key = $this->build_key($key, $group);
        return $this->memcached->set($derived_key, $data, $expire);
    }

    private function build_key($key, $group) {
        return $group . ':' . $key;
    }
}

Browser and CDN Caching

Browser Cache Headers

// Advanced browser caching implementation
class Browser_Cache_Headers {

    public function __construct() {
        add_action('send_headers', [$this, 'set_cache_headers']);
        add_filter('wp_headers', [$this, 'modify_headers']);
        add_action('wp_head', [$this, 'add_cache_meta_tags'], 1);
    }

    public function set_cache_headers() {
        if (is_admin() || is_user_logged_in()) {
            return;
        }

        // Different cache times for different content types
        $cache_times = [
            'text/html' => 600, // 10 minutes
            'text/css' => 31536000, // 1 year
            'application/javascript' => 31536000, // 1 year
            'image/jpeg' => 31536000, // 1 year
            'image/png' => 31536000, // 1 year
            'image/gif' => 31536000, // 1 year
            'image/webp' => 31536000, // 1 year
            'font/woff2' => 31536000, // 1 year
        ];

        // Get content type
        $content_type = $this->get_content_type();
        $cache_time = isset($cache_times[$content_type]) ? $cache_times[$content_type] : 3600;

        // Set cache headers
        header('Cache-Control: public, max-age=' . $cache_time);
        header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $cache_time) . ' GMT');

        // ETag generation
        if (!is_404()) {
            $etag = $this->generate_etag();
            header('ETag: "' . $etag . '"');

            // Check If-None-Match
            if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && 
                trim($_SERVER['HTTP_IF_NONE_MATCH'], '"') === $etag) {
                header('HTTP/1.1 304 Not Modified');
                exit;
            }
        }

        // Add Vary header for dynamic content
        if ($content_type === 'text/html') {
            header('Vary: Accept-Encoding, Cookie');
        } else {
            header('Vary: Accept-Encoding');
        }
    }

    private function get_content_type() {
        $headers = headers_list();
        foreach ($headers as $header) {
            if (stripos($header, 'Content-Type:') === 0) {
                $parts = explode(':', $header);
                $content_type = trim($parts[1]);
                return explode(';', $content_type)[0];
            }
        }
        return 'text/html';
    }

    private function generate_etag() {
        // Generate ETag based on content
        $factors = [
            get_queried_object_id(),
            wp_get_theme()->get('Version'),
            get_option('posts_last_modified', ''),
            is_user_logged_in() ? 'logged-in' : 'guest'
        ];

        return md5(implode('-', $factors));
    }

    public function modify_headers($headers) {
        // Security headers
        $headers['X-Content-Type-Options'] = 'nosniff';
        $headers['X-Frame-Options'] = 'SAMEORIGIN';
        $headers['X-XSS-Protection'] = '1; mode=block';
        $headers['Referrer-Policy'] = 'strict-origin-when-cross-origin';

        // Remove unnecessary headers
        unset($headers['X-Powered-By']);

        return $headers;
    }

    public function add_cache_meta_tags() {
        if (is_singular()) {
            $post = get_post();
            ?>
            <!-- Cache meta tags -->
            <meta http-equiv="last-modified" content="<?php echo get_the_modified_date('c', $post); ?>">
            <meta http-equiv="cache-control" content="public">
            <?php
        }
    }
}

new Browser_Cache_Headers();

CDN Integration

// CDN URL rewriting and optimization
class CDN_Integration {
    private $cdn_url;
    private $site_url;
    private $directories = ['wp-content', 'wp-includes'];
    private $extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'css', 'js', 'woff', 'woff2', 'ttf', 'svg'];

    public function __construct() {
        $this->cdn_url = defined('CDN_URL') ? CDN_URL : '';
        $this->site_url = get_option('siteurl');

        if (!empty($this->cdn_url)) {
            add_filter('wp_get_attachment_url', [$this, 'rewrite_attachment_url']);
            add_filter('style_loader_src', [$this, 'rewrite_asset_url']);
            add_filter('script_loader_src', [$this, 'rewrite_asset_url']);
            add_filter('the_content', [$this, 'rewrite_content_urls']);
            add_filter('widget_text', [$this, 'rewrite_content_urls']);

            // Srcset for responsive images
            add_filter('wp_calculate_image_srcset', [$this, 'rewrite_srcset'], 10, 5);
        }
    }

    public function rewrite_attachment_url($url) {
        if ($this->should_rewrite($url)) {
            $url = str_replace($this->site_url, $this->cdn_url, $url);
        }

        return $url;
    }

    public function rewrite_asset_url($url) {
        if ($this->should_rewrite($url)) {
            $url = str_replace($this->site_url, $this->cdn_url, $url);

            // Add version string for cache busting
            if (strpos($url, '?ver=') === false) {
                $version = $this->get_asset_version($url);
                $url .= '?ver=' . $version;
            }
        }

        return $url;
    }

    public function rewrite_content_urls($content) {
        if (is_admin() || is_feed()) {
            return $content;
        }

        // Build regex pattern
        $dirs = implode('|', $this->directories);
        $exts = implode('|', $this->extensions);

        $pattern = '#(' . quotemeta($this->site_url) . ')?/((' . $dirs . ')/.+\.(' . $exts . '))#';

        $content = preg_replace($pattern, $this->cdn_url . '/$2', $content);

        return $content;
    }

    public function rewrite_srcset($sources, $size_array, $image_src, $image_meta, $attachment_id) {
        foreach ($sources as &$source) {
            if ($this->should_rewrite($source['url'])) {
                $source['url'] = str_replace($this->site_url, $this->cdn_url, $source['url']);
            }
        }

        return $sources;
    }

    private function should_rewrite($url) {
        // Don't rewrite external URLs
        if (strpos($url, $this->site_url) !== 0) {
            return false;
        }

        // Don't rewrite admin URLs
        if (strpos($url, '/wp-admin/') !== false) {
            return false;
        }

        // Check if URL contains allowed directory
        $has_dir = false;
        foreach ($this->directories as $dir) {
            if (strpos($url, '/' . $dir . '/') !== false) {
                $has_dir = true;
                break;
            }
        }

        if (!$has_dir) {
            return false;
        }

        // Check extension
        $extension = pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION);

        return in_array(strtolower($extension), $this->extensions);
    }

    private function get_asset_version($url) {
        // For theme assets, use theme version
        if (strpos($url, get_template_directory_uri()) !== false) {
            return wp_get_theme()->get('Version');
        }

        // For plugins, try to get plugin version
        if (strpos($url, '/wp-content/plugins/') !== false) {
            preg_match('#/wp-content/plugins/([^/]+)/#', $url, $matches);
            if (!empty($matches[1])) {
                $plugin_data = get_plugin_data(WP_PLUGIN_DIR . '/' . $matches[1] . '/' . $matches[1] . '.php');
                if (!empty($plugin_data['Version'])) {
                    return $plugin_data['Version'];
                }
            }
        }

        // Default to file modification time
        $file_path = str_replace($this->site_url, ABSPATH, $url);
        $file_path = parse_url($file_path, PHP_URL_PATH);

        if (file_exists($file_path)) {
            return filemtime($file_path);
        }

        return time();
    }
}

// Initialize CDN integration
new CDN_Integration();

Database Query Caching

Query Result Caching

// Advanced database query caching
class Query_Cache {
    private $cache_group = 'query_cache';
    private $cache_time = 3600; // 1 hour default

    public function cache_query($sql, $callback, $cache_time = null) {
        $cache_key = 'query_' . md5($sql);
        $cache_time = $cache_time ?: $this->cache_time;

        // Try to get from cache
        $result = wp_cache_get($cache_key, $this->cache_group);

        if ($result === false) {
            // Execute query
            $result = call_user_func($callback);

            // Cache result
            wp_cache_set($cache_key, $result, $this->cache_group, $cache_time);
        }

        return $result;
    }

    public function get_posts_with_meta($args = [], $cache_time = 3600) {
        $defaults = [
            'posts_per_page' => 10,
            'post_status' => 'publish'
        ];

        $args = wp_parse_args($args, $defaults);
        $cache_key = 'posts_meta_' . md5(serialize($args));

        return $this->cache_query($cache_key, function() use ($args) {
            global $wpdb;

            // Build optimized query
            $query = new WP_Query($args);
            $posts = $query->posts;

            if (empty($posts)) {
                return [];
            }

            // Get all post IDs
            $post_ids = wp_list_pluck($posts, 'ID');

            // Batch load all meta data
            update_meta_cache('post', $post_ids);

            // Batch load all terms
            update_object_term_cache($post_ids, 'post');

            return $posts;
        }, $cache_time);
    }

    public function get_popular_posts($days = 7, $limit = 10) {
        $cache_key = "popular_posts_{$days}_{$limit}";

        return $this->cache_query($cache_key, function() use ($days, $limit) {
            global $wpdb;

            $sql = $wpdb->prepare("
                SELECT p.*, COUNT(pm.meta_id) as view_count
                FROM {$wpdb->posts} p
                INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
                WHERE p.post_status = 'publish'
                AND p.post_type = 'post'
                AND pm.meta_key = 'post_views'
                AND p.post_date > DATE_SUB(NOW(), INTERVAL %d DAY)
                GROUP BY p.ID
                ORDER BY view_count DESC
                LIMIT %d
            ", $days, $limit);

            return $wpdb->get_results($sql);
        }, 3600); // Cache for 1 hour
    }

    public function clear_query_cache($type = 'all') {
        if ($type === 'all') {
            wp_cache_flush_group($this->cache_group);
        } else {
            // Clear specific cache types
            $patterns = [
                'posts' => 'posts_*',
                'popular' => 'popular_posts_*',
                'query' => 'query_*'
            ];

            if (isset($patterns[$type])) {
                // If using Redis/Memcached with pattern support
                wp_cache_delete_by_pattern($patterns[$type], $this->cache_group);
            }
        }
    }
}

// Usage
$query_cache = new Query_Cache();

// Cache complex query
$popular_posts = $query_cache->get_popular_posts(30, 5);

// Cache custom query
$results = $query_cache->cache_query('custom_key', function() {
    global $wpdb;
    return $wpdb->get_results("SELECT * FROM custom_table WHERE status = 'active'");
}, 7200); // Cache for 2 hours

Advanced Caching Techniques

Fragment Caching

// Fragment caching for expensive operations
class Fragment_Cache {

    public static function get($key, $callback, $expiration = 3600) {
        $fragment = wp_cache_get($key, 'fragments');

        if ($fragment === false) {
            ob_start();
            call_user_func($callback);
            $fragment = ob_get_clean();

            wp_cache_set($key, $fragment, 'fragments', $expiration);
        }

        return $fragment;
    }

    public static function output($key, $callback, $expiration = 3600) {
        echo self::get($key, $callback, $expiration);
    }

    public static function delete($key) {
        return wp_cache_delete($key, 'fragments');
    }

    public static function flush() {
        return wp_cache_flush_group('fragments');
    }
}

// Usage in templates
Fragment_Cache::output('sidebar_recent_posts', function() {
    $recent_posts = new WP_Query([
        'posts_per_page' => 5,
        'no_found_rows' => true,
        'update_post_term_cache' => false,
        'update_post_meta_cache' => false
    ]);

    if ($recent_posts->have_posts()) {
        echo '<ul class="recent-posts">';
        while ($recent_posts->have_posts()) {
            $recent_posts->the_post();
            echo '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
        }
        echo '</ul>';
    }

    wp_reset_postdata();
}, 3600);

Edge Side Includes (ESI)

// ESI implementation for dynamic content in cached pages
class ESI_Cache {
    private $esi_enabled = false;

    public function __construct() {
        // Check if behind Varnish or CDN that supports ESI
        $this->esi_enabled = isset($_SERVER['HTTP_SURROGATE_CAPABILITY']) && 
                           strpos($_SERVER['HTTP_SURROGATE_CAPABILITY'], 'ESI/1.0') !== false;

        add_shortcode('esi', [$this, 'esi_shortcode']);
        add_action('init', [$this, 'register_esi_endpoints']);
    }

    public function esi_shortcode($atts) {
        $atts = shortcode_atts([
            'src' => '',
            'ttl' => 300,
            'fallback' => ''
        ], $atts);

        if (empty($atts['src'])) {
            return '';
        }

        if ($this->esi_enabled) {
            // Return ESI tag for Varnish
            return sprintf(
                '<esi:include src="%s" onerror="continue"/>',
                esc_url($atts['src'])
            );
        } else {
            // Fallback: fetch content directly
            $response = wp_remote_get($atts['src']);

            if (!is_wp_error($response)) {
                return wp_remote_retrieve_body($response);
            }

            return $atts['fallback'];
        }
    }

    public function register_esi_endpoints() {
        // Register custom endpoints for ESI fragments
        add_rewrite_rule(
            '^esi/([^/]+)/?$',
            'index.php?esi_fragment=$matches[1]',
            'top'
        );

        add_filter('query_vars', function($vars) {
            $vars[] = 'esi_fragment';
            return $vars;
        });

        add_action('template_redirect', [$this, 'handle_esi_request']);
    }

    public function handle_esi_request() {
        $fragment = get_query_var('esi_fragment');

        if (!$fragment) {
            return;
        }

        // Set appropriate cache headers
        header('Cache-Control: public, max-age=300');
        header('Surrogate-Control: max-age=300');

        // Output fragment based on type
        switch ($fragment) {
            case 'user-menu':
                $this->output_user_menu();
                break;

            case 'cart-count':
                $this->output_cart_count();
                break;

            case 'recent-comments':
                $this->output_recent_comments();
                break;
        }

        exit;
    }

    private function output_user_menu() {
        if (is_user_logged_in()) {
            $user = wp_get_current_user();
            echo '<div class="user-menu">';
            echo 'Welcome, ' . esc_html($user->display_name);
            echo ' | <a href="' . wp_logout_url() . '">Logout</a>';
            echo '</div>';
        } else {
            echo '<div class="user-menu">';
            echo '<a href="' . wp_login_url() . '">Login</a>';
            echo ' | <a href="' . wp_registration_url() . '">Register</a>';
            echo '</div>';
        }
    }

    private function output_cart_count() {
        if (function_exists('WC')) {
            $count = WC()->cart->get_cart_contents_count();
            echo '<span class="cart-count">' . $count . '</span>';
        }
    }

    private function output_recent_comments() {
        $comments = get_comments([
            'number' => 5,
            'status' => 'approve'
        ]);

        echo '<ul class="recent-comments">';
        foreach ($comments as $comment) {
            echo '<li>';
            echo esc_html($comment->comment_author) . ' on ';
            echo '<a href="' . get_comment_link($comment) . '">';
            echo get_the_title($comment->comment_post_ID);
            echo '</a>';
            echo '</li>';
        }
        echo '</ul>';
    }
}

new ESI_Cache();

Cache Management and Invalidation

Smart Cache Invalidation

// Intelligent cache invalidation system
class Cache_Invalidation {
    private $purge_urls = [];

    public function __construct() {
        // Post changes
        add_action('save_post', [$this, 'purge_post_cache'], 10, 3);
        add_action('deleted_post', [$this, 'purge_post_cache'], 10, 2);
        add_action('trash_post', [$this, 'purge_post_cache']);
        add_action('publish_future_post', [$this, 'purge_post_cache']);

        // Comments
        add_action('comment_post', [$this, 'purge_comment_cache'], 10, 2);
        add_action('edit_comment', [$this, 'purge_comment_cache']);
        add_action('delete_comment', [$this, 'purge_comment_cache']);

        // Terms
        add_action('created_term', [$this, 'purge_term_cache'], 10, 3);
        add_action('edited_term', [$this, 'purge_term_cache'], 10, 3);
        add_action('delete_term', [$this, 'purge_term_cache'], 10, 4);

        // Theme changes
        add_action('switch_theme', [$this, 'purge_all_cache']);
        add_action('customize_save', [$this, 'purge_all_cache']);

        // Execute purges at shutdown
        add_action('shutdown', [$this, 'execute_purges']);
    }

    public function purge_post_cache($post_id, $post = null, $update = false) {
        if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
            return;
        }

        if (!$post) {
            $post = get_post($post_id);
        }

        if (!$post || $post->post_status !== 'publish') {
            return;
        }

        // Add URLs to purge
        $this->add_purge_url(get_permalink($post_id));
        $this->add_purge_url(home_url('/'));

        // Post type archive
        $post_type_archive = get_post_type_archive_link($post->post_type);
        if ($post_type_archive) {
            $this->add_purge_url($post_type_archive);
        }

        // Author archive
        $this->add_purge_url(get_author_posts_url($post->post_author));

        // Date archives
        $this->add_purge_url(get_year_link(get_the_date('Y', $post)));
        $this->add_purge_url(get_month_link(get_the_date('Y', $post), get_the_date('m', $post)));
        $this->add_purge_url(get_day_link(get_the_date('Y', $post), get_the_date('m', $post), get_the_date('d', $post)));

        // Taxonomies
        $taxonomies = get_object_taxonomies($post->post_type);
        foreach ($taxonomies as $taxonomy) {
            $terms = wp_get_object_terms($post_id, $taxonomy);
            foreach ($terms as $term) {
                $this->add_purge_url(get_term_link($term));
            }
        }

        // Related posts (if using a specific meta key)
        $related_ids = get_post_meta($post_id, '_related_posts', true);
        if (!empty($related_ids)) {
            foreach ($related_ids as $related_id) {
                $this->add_purge_url(get_permalink($related_id));
            }
        }

        // Pagination pages
        $this->add_pagination_urls(home_url('/'));

        // Feed URLs
        $this->add_purge_url(get_bloginfo('rss2_url'));
        $this->add_purge_url(get_bloginfo('atom_url'));
    }

    public function purge_comment_cache($comment_id, $comment_approved = 1) {
        $comment = get_comment($comment_id);

        if (!$comment || $comment_approved !== 1) {
            return;
        }

        // Purge post page
        $this->add_purge_url(get_permalink($comment->comment_post_ID));

        // Purge recent comments widgets
        $this->purge_fragment_cache('widget_recent_comments');
    }

    public function purge_term_cache($term_id, $tt_id, $taxonomy) {
        $term = get_term($term_id, $taxonomy);

        if (!$term || is_wp_error($term)) {
            return;
        }

        // Term archive
        $this->add_purge_url(get_term_link($term));

        // Posts in this term
        $posts = get_posts([
            'tax_query' => [
                [
                    'taxonomy' => $taxonomy,
                    'terms' => $term_id
                ]
            ],
            'posts_per_page' => -1,
            'fields' => 'ids'
        ]);

        foreach ($posts as $post_id) {
            $this->add_purge_url(get_permalink($post_id));
        }
    }

    public function purge_all_cache() {
        // Clear all caches
        if (function_exists('wp_cache_flush')) {
            wp_cache_flush();
        }

        // Clear page cache
        $this->clear_page_cache_files();

        // Clear CDN cache
        $this->purge_cdn_cache('/*');

        // Clear Varnish cache
        $this->purge_varnish_cache();
    }

    private function add_purge_url($url) {
        if (!empty($url)) {
            $this->purge_urls[] = $url;
        }
    }

    private function add_pagination_urls($base_url) {
        global $wp_rewrite;

        // Add first 5 pagination pages
        for ($i = 2; $i <= 5; $i++) {
            if ($wp_rewrite->using_permalinks()) {
                $this->add_purge_url($base_url . 'page/' . $i . '/');
            } else {
                $this->add_purge_url(add_query_arg('paged', $i, $base_url));
            }
        }
    }

    public function execute_purges() {
        if (empty($this->purge_urls)) {
            return;
        }

        // Remove duplicates
        $this->purge_urls = array_unique($this->purge_urls);

        // Purge each URL
        foreach ($this->purge_urls as $url) {
            $this->purge_url($url);
        }

        // Clear URLs after purging
        $this->purge_urls = [];
    }

    private function purge_url($url) {
        // Purge from various cache layers

        // 1. Page cache files
        $this->purge_page_cache_file($url);

        // 2. Varnish cache
        $this->purge_varnish_url($url);

        // 3. CDN cache
        $this->purge_cdn_url($url);

        // 4. Fragment cache
        $cache_key = 'page_' . md5($url);
        wp_cache_delete($cache_key, 'pages');
    }

    private function purge_page_cache_file($url) {
        $cache_dir = WP_CONTENT_DIR . '/cache/pages/';
        $parsed = parse_url($url);
        $path = $parsed['host'] . $parsed['path'];
        $hash = md5($path);
        $subdir = substr($hash, 0, 2);

        $files = [
            $cache_dir . $subdir . '/' . $hash . '.html',
            $cache_dir . $subdir . '/' . $hash . '.html.gz'
        ];

        foreach ($files as $file) {
            if (file_exists($file)) {
                unlink($file);
            }
        }
    }

    private function purge_varnish_url($url) {
        if (!defined('VARNISH_SERVERS')) {
            return;
        }

        $servers = explode(',', VARNISH_SERVERS);

        foreach ($servers as $server) {
            wp_remote_request($url, [
                'method' => 'PURGE',
                'headers' => [
                    'Host' => parse_url($url, PHP_URL_HOST)
                ],
                'sslverify' => false,
                'timeout' => 1
            ]);
        }
    }

    private function purge_cdn_url($url) {
        // Example: Cloudflare purge
        if (defined('CLOUDFLARE_ZONE_ID') && defined('CLOUDFLARE_API_KEY')) {
            $api_url = 'https://api.cloudflare.com/client/v4/zones/' . CLOUDFLARE_ZONE_ID . '/purge_cache';

            wp_remote_post($api_url, [
                'headers' => [
                    'X-Auth-Email' => CLOUDFLARE_EMAIL,
                    'X-Auth-Key' => CLOUDFLARE_API_KEY,
                    'Content-Type' => 'application/json'
                ],
                'body' => json_encode([
                    'files' => [$url]
                ])
            ]);
        }
    }

    private function clear_page_cache_files() {
        $cache_dir = WP_CONTENT_DIR . '/cache/pages/';

        if (!is_dir($cache_dir)) {
            return;
        }

        $this->recursive_remove_directory($cache_dir);
        wp_mkdir_p($cache_dir);
    }

    private function recursive_remove_directory($directory) {
        foreach (glob($directory . '/*') as $file) {
            if (is_dir($file)) {
                $this->recursive_remove_directory($file);
            } else {
                unlink($file);
            }
        }

        if (is_dir($directory)) {
            rmdir($directory);
        }
    }
}

// Initialize cache invalidation
new Cache_Invalidation();

Best Practices

Caching Strategy Checklist

## Page Caching
- [ ] Cache HTML pages for anonymous users
- [ ] Exclude dynamic pages (cart, checkout, account)
- [ ] Set appropriate cache times (10min - 1hr for content)
- [ ] Implement cache warming for critical pages
- [ ] Monitor cache hit rates

## Object Caching
- [ ] Use Redis or Memcached for persistent object cache
- [ ] Cache expensive queries and API calls
- [ ] Set reasonable expiration times
- [ ] Monitor memory usage
- [ ] Implement cache groups for easy management

## Browser Caching
- [ ] Set far-future expires for static assets
- [ ] Use cache busting for updates
- [ ] Implement ETags for dynamic content
- [ ] Add appropriate Vary headers
- [ ] Test with different browsers

## CDN Caching
- [ ] Use CDN for all static assets
- [ ] Configure proper cache headers
- [ ] Implement cache purging API
- [ ] Monitor CDN hit rates
- [ ] Use multiple CDN regions

## Cache Invalidation
- [ ] Clear cache on content updates
- [ ] Implement smart invalidation (only affected pages)
- [ ] Avoid clearing entire cache when possible
- [ ] Set up automatic cache warming
- [ ] Monitor invalidation frequency

Conclusion

Effective caching is essential for WordPress performance, but it requires understanding multiple layers and implementing the right strategy for each. By following this guide:

Remember that caching is not "set and forget"—it requires ongoing monitoring and optimization. Start with basic page caching, then progressively add layers based on your site's specific needs. The investment in proper caching pays enormous dividends in performance, user experience, and reduced hosting costs.


Continue optimizing your WordPress site with our comprehensive WordPress Performance Optimization Guide for more advanced techniques and strategies.