Why Your WordPress Changes Don’t Appear After Editing Files
You edited a theme or plugin file, reloaded the page, even hard-refreshed — and the site still shows the old version. On a managed nginx host (often with a CDN in front) the reason is almost always a full-page cache sitting between the visitor and PHP, not your edit failing to save. wp cache flush does not clear it. You need the host’s own page-cache purge (a panel button or the WP-CLI command its cache plugin ships) and, if a CDN is in front, a CDN purge too. OPcache is a common scapegoat but usually innocent — I verified that on my own server below.
What you’ll learn: how to tell which cache is serving stale content, the exact commands that clear each layer, and how to check whether OPcache is actually involved before you go chasing it.
Evidence note: based on a real "my change won’t show" issue on a WordPress site I run on a managed nginx stack. Every config value here was read from the live php-fpm process and response headers on 2026-07-31; sensitive paths and keys are replaced with placeholders.
The symptom
I edited functions.php in the active theme, saved, and reloaded. Nothing changed. The usual reflexes all failed:
- Hard refresh (Ctrl/Cmd-Shift-R) — no change. That only clears the browser cache, and this wasn’t a browser cache.
?v=123on the URL — the change appeared. Misleading: a unique query string dodges the page cache, so it proves the file is correct but tells real visitors nothing, because they hit the plain cached URL.wp cache flush— no effect at all.
That last one is the key clue. wp cache flush empties WordPress’s object cache (transients, query results). It has no idea the nginx layer in front of PHP is holding a whole rendered HTML page.
The caches that are actually in the way
On a managed nginx host there can be up to three independent layers between a browser and your PHP:
- CDN (edge) — only if you use one. Check the
Server:and cache-status response headers; if a CDN is answering, it can serve cached HTML from its edge regardless of what the origin does. - The host’s full-page cache (nginx) — most managed panels offer an nginx page cache that stores the rendered page at the web server. You can usually see it working: the response carries a cache-status header (often named something like
x-cacheorx-<panel>-cache) that saysHITorMISS. A HIT means nginx answered from cache and PHP never ran. - PHP OPcache (php-fpm) — caches compiled PHP bytecode, not HTML. Whether it can serve stale code depends entirely on one setting, covered below.
wp cache flush touches none of these. Each needs its own purge.
The fix that works
Work from the layer closest to PHP outwards.
1. Purge the host’s page cache
WordPress core can’t clear an nginx page cache on its own. Managed panels usually ship a companion cache plugin with a Purge button in wp-admin, a purge button in the panel itself, and often a WP-CLI subcommand. Run wp help in the site’s directory to see which cache commands your stack added:
cd /var/www/YOUR_SITE
wp help | grep -i cache
# then run the purge-all subcommand your cache plugin provides
After purging, reload without any query string and confirm the cache-status header:
curl -sI https://YOUR_SITE/ | grep -iE 'cache'
# ...-cache: MISS ← good, the next request re-renders from PHP
2. If a CDN is in front, purge it too
This is the step people with a CDN miss. Even after the origin is fresh, the CDN can keep serving the old HTML from its edge. Purge it from the CDN dashboard (a purge-everything or single-URL purge), or via its API. If you don’t use a CDN, skip this.
3. Only if OPcache is genuinely stale
Here’s where I stopped guessing and measured. OPcache only serves stale code if opcache.validate_timestamps is off. When it’s on, php-fpm re-checks each file’s modification time and recompiles automatically, so your edit is picked up on the next request with no intervention.
I read the value straight from the running php-fpm process (not the CLI, which has its own separate config). On my server:
sapi=fpm-fcgi
opcache.enable=1
opcache.validate_timestamps=1
opcache.revalidate_freq=0
opcache.enable_cli=0
validate_timestamps=1 with revalidate_freq=0 means php-fpm revalidates on every request. So on this host OPcache was never the problem — the page cache was. This is the part most "clear your OPcache" advice gets wrong for many managed-host defaults.
If your host runs validate_timestamps=0 (common on performance-tuned stacks), then yes, you must reset OPcache after deploying code — and there’s a trap:
wp eval 'opcache_reset();'does nothing useful, because the CLI runs a different PHP process from php-fpm, and hereopcache.enable_cli=0— the CLI has no OPcache to reset. Resetting it in the CLI leaves the web server’s cache untouched.- Reset it through php-fpm instead. Drop a one-line file in the webroot and request it over HTTP so php-fpm executes it, then delete it immediately:
echo '<?php opcache_reset();' > /var/www/YOUR_SITE/_reset.php
curl -s https://YOUR_SITE/_reset.php
rm /var/www/YOUR_SITE/_reset.php
How to check your own validate_timestamps
Don’t assume — the CLI and php-fpm can differ. Read the value from php-fpm itself by executing a probe through the web server, then deleting it:
cat > /var/www/YOUR_SITE/_probe.php <<'PHP'
<?php header('Content-Type: text/plain');
echo 'sapi=', php_sapi_name(), "n";
echo 'validate_timestamps=', ini_get('opcache.validate_timestamps'), "n";
PHP
curl -s https://YOUR_SITE/_probe.php
rm /var/www/YOUR_SITE/_probe.php
If sapi=fpm-fcgi and validate_timestamps=1, OPcache is not your problem — stop looking at it and purge the page cache.
Why the obvious fixes fail
| What you tried | Why it didn’t work |
|---|---|
| Hard refresh | Clears the browser only; the stale copy lives on the server/CDN. |
?v=123 | Bypasses the page cache for you, but real visitors hit the plain URL. |
wp cache flush | Clears WordPress’s object cache, not the nginx page cache or the CDN. |
wp eval 'opcache_reset()' | Runs in the CLI SAPI, which is a separate process from php-fpm (and here has OPcache disabled). |
A reusable checklist
- Is a CDN in front? Check
Server:and the CDN’s cache-status header. If so — purge it. - Is the page cache serving you? Check the host’s cache-status header. HIT means PHP didn’t run — purge it from the panel or its cache plugin.
- Is OPcache even relevant? Probe php-fpm for
validate_timestamps. If1, skip it. - Only if
validate_timestamps=0: reset OPcache through php-fpm, never the CLI. - Re-request the real URL (no query string) and confirm the header now says
MISS.
Takeaway
"My WordPress edit won’t show" is nearly always a caching layer, not a failed save — and on a managed nginx host the layer is usually the nginx full-page cache (plus a CDN if you have one), which wp cache flush will never touch. Before blaming OPcache, spend thirty seconds reading validate_timestamps from php-fpm. In my setup it was 1, and every minute I’d have spent resetting OPcache would have been wasted. Your host may differ — so measure, don’t assume.
AI assisted with drafting and with running the read-only verification commands; the server, its configuration, and the results are from my own live environment.
