A WordPress production site has 4 independent caches and they don’t know about each other. wp cache flush touches 2 of them. OPCache and browser cache require completely different mechanisms.
A deploy that doesn’t flush all relevant cache layers will leave users seeing stale content from one layer while fresh content arrives from another. The result looks like intermittent bugs that resolve themselves — which is the worst kind of bug, because it suggests a flaky codebase when the actual cause is a cache layer nobody flushed.
After a CSS update to the inventory grid, some mobile visitors saw the old grid layout for 45 minutes while desktop visitors saw the new one. WP object cache and CDN were flushed. Browser cache on mobile was not — mobile users had cached the CSS file from the previous version. The fix (bumping the CSS query string) was already in the process for subsequent deploys, but this one slipped through.
Layer 1: PHP OPCache
Owns: compiled PHP bytecode
Flush trigger: any .php file change
How: opcache_reset() via one-shot PHP script, then delete script
Layer 2: WP Object Cache (in-memory / Redis / Memcached)
Owns: WP query results, post data, option values
Flush trigger: database data changes, option updates
How: wp cache flush (WP-CLI)
Layer 3: Full-Page Cache (Breeze, WP Rocket, Nginx FastCGI)
Owns: cached HTML output of pages
Flush trigger: content changes, template updates
How: plugin-specific API or wp cache flush with plugin active
Layer 4: Edge / CDN cache (Cloudflare, nginx proxy)
Owns: static assets, sometimes HTML
Flush trigger: asset version bumps, explicit API purge
How: Cloudflare API purge or Cache-Control: no-cache headers
OPCache is the most impactful and most forgotten cache layer. Changed PHP files run old bytecode until it’s flushed. The pattern: deploy a one-shot flush script, curl it, delete it:
<?php
if ( opcache_reset() ) {
echo json_encode( [ 'status' => 'flushed', 'time' => time() ] );
} else {
http_response_code( 500 );
echo json_encode( [ 'status' => 'failed' ] );
}
rsync opcache-flush.php prod:/path/to/webroot/
curl -s https://[site]/opcache-flush.php
ssh prod "rm /path/to/webroot/opcache-flush.php"
Browser cache can’t be manually purged for existing users. The only lever is making the asset URL different — every CSS and JS file that changes must have its query string bumped:
wp_enqueue_style(
'[client]-main',
get_template_directory_uri() . '/css/style.css',
[],
'20260512b' // Increment on every CSS change: YYYYMMDD + letter
);
wp_enqueue_script(
'[client]-site',
get_template_directory_uri() . '/js/site.js',
[ 'jquery' ],
'20260429g', // Increment on every JS change
true
);
# 1. OPCache (PHP bytecode)
rsync opcache-flush.php prod:/path/
curl -s https://[site]/opcache-flush.php
ssh prod "rm /path/to/opcache-flush.php"
# 2. WP object cache
ssh prod "cd /path/to/wp && wp cache flush"
# 3. Full-page cache (Breeze example)
ssh prod "cd /path/to/wp && wp breeze clear-all-cache"
# 4. Cloudflare edge cache (full zone on major deploys)
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
-H "Authorization: Bearer CF_TOKEN" \
-H "Content-Type: application/json" \
--data '{"purge_everything":true}'
# 5. Verify — check a versioned URL loads the new asset
curl -sI "https://[site]/css/style.css?v=20260512b" | grep "Last-Modified"
The 4 caches are independent. WP-CLI wp cache flush touches layers 2 and 3 (depending on plugin). It does nothing to OPCache or browser cache. A deploy process that runs wp cache flush and calls it done is leaving 2 of 4 layers unflushed.
Version strings on CSS/JS are the only cache control you have over browser caches for existing users. Ship a visual change without bumping the version string and some percentage of users will see the old UI for hours to days — and they won’t know to hard-refresh.
Full 4-layer flush sequence scripted into every deploy. 0 stale-cache incidents after the sequence was formalized. Prior: 3 incidents in the first 3 months (all OPCache-related). The Cloudflare purge is scoped to individual assets on minor deploys and full-zone on major deploys — full-zone adds ~2 minutes of edge warm-up traffic but prevents serving stale HTML to the first post-deploy visitors.
wp cache flush does not touch OPCache. Treat them as completely separate systems because they are.curl -sI on a versioned asset URL confirms the CDN is serving the new version. “I think it’s flushed” is not a close-out.Every lesson stays free — no account, no paywall, no email gate, ever. But if you’d rather have this system standing on your business than wire all 48 lessons yourself, leave your email. We’ll send you a direct line to a build — and you’ll be first to hear when we add new tools to the curriculum.
None of this gates a single lesson. The curriculum was free before you got here and it stays that way.
You came here to understand the system, and now you do. If you’d rather have it standing on your business than spend the next three months wiring it yourself, GAP Concierge is the same architecture from these lessons — a white-label AI agent that knows your catalog and captures your leads — set up for you, from $97/mo.
See GAP Concierge →