Full-page caching stores the complete HTML output of a WordPress page so subsequent requests are served without executing PHP or querying MySQL. It is the most impactful single performance optimisation for most WordPress sites — the difference between 10ms and 500ms page response time.
Problem: A WordPress site serves dynamically generated HTML on every request — PHP, database queries, and template rendering run for every page view even when the content rarely changes, causing high TTFB under moderate traffic.
Solution: Implement full-page caching: serve static HTML files from disk for anonymous visitors using a plugin (WP Super Cache, W3 Total Cache) or Nginx fastcgi_cache. Configure cache bypass rules for logged-in users, POST requests, WooCommerce cart/checkout pages, and query string parameters. Purge the cache selectively on post save with the save_post hook.
The examples below compare the four main full-page caching strategies, implement a minimal file-based cache in a must-use plugin, and show the correct approach for bypassing cache for logged-in users and WooCommerce cart pages.
# Full-page cache strategy comparison:
#
# Strategy Where cache lives Miss cost Config difficulty
# ─────────────────────────────────────────────────────────────────────
# Nginx FastCGI Nginx layer Lowest Medium (nginx.conf)
# Varnish Proxy layer Lowest High (VCL)
# WP Super Cache PHP / Apache Low Low (plugin)
# W3 Total Cache PHP / CDN Low Medium (plugin)
# Object Cache Pro Redis (page cache) Medium Low (plugin)
#
# Recommended for VPS/dedicated: Nginx FastCGI cache (fastest)
# Recommended for shared hosting: WP Super Cache or W3 Total Cache
# ── Nginx FastCGI Cache setup ──
# /etc/nginx/nginx.conf (http block):
# fastcgi_cache_path /var/cache/nginx/wordpress
# levels=1:2 keys_zone=WORDPRESS:100m inactive=60m max_size=1g;
# fastcgi_cache_key "$scheme$request_method$host$request_uri";
# /etc/nginx/sites-available/helloadmin.com (server block):
# set $skip_cache 0;
# if ($request_method = POST) { set $skip_cache 1; }
# if ($query_string != "") { set $skip_cache 1; }
# if ($request_uri ~* "/wp-admin/") { set $skip_cache 1; }
# if ($http_cookie ~* "wordpress_logged_in") { set $skip_cache 1; }
# if ($http_cookie ~* "woocommerce_items_in_cart") { set $skip_cache 1; }
#
# fastcgi_cache WORDPRESS;
# fastcgi_cache_valid 200 60m;
# fastcgi_cache_bypass $skip_cache;
# fastcgi_no_cache $skip_cache;
# add_header X-Cache $upstream_cache_status;
Minimal PHP output-buffer page cache as a must-use plugin:
NOTE: Always bypass the page cache for: logged-in users, POST requests, pages with query strings (except whitelisted SEO parameters), WooCommerce cart/checkout/account pages, and pages with personalised content. A cache that serves logged-in content to anonymous users is worse than no cache at all.