Skip to main content
Builder’s Journal

Why Your WordPress Changes Don’t Appear After Editing Files

· · 5 min read

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 (RunCloud, and often with Cloudflare 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 purge (wp runcloud-hub purgeall) 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 my RunCloud-hosted WordPress sites. 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=123 on 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 RunCloud host there can be up to three independent layers between a browser and your PHP:

  1. CDN / Cloudflare (edge) — only if you use one. On mustafa.net the response header is Server: cloudflare, so Cloudflare can serve cached HTML from its edge regardless of what the origin does.
  2. RunCloud full-page cache (nginx) — RunCloud’s "native" cache stores the rendered page at the web server. You can see it working: the response carries an x-runcloud-cache: HIT or MISS header. A HIT means nginx answered from cache and PHP never ran.
  3. 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 RunCloud page cache

WordPress can’t clear RunCloud’s nginx cache, but RunCloud ships a WP-CLI command that can. From the site’s directory:

cd /home/USER/webapps/YOUR_APP
wp runcloud-hub purgeall

wp runcloud-hub really does exist and purgeall is a valid subcommand (there’s also purgeredis for the Redis object cache, if you run one). The RunCloud control panel has an equivalent Purge button. After this, reload without any query string and confirm:

curl -sI https://YOUR_SITE/ | grep -i x-runcloud-cache
# x-runcloud-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 on Cloudflare miss. Even after the origin is fresh, Cloudflare can keep serving the old HTML from its edge. Purge it from the Cloudflare dashboard (Caching → Configuration → Purge Everything, or a single-URL purge), or via the 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 RunCloud box:

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 RunCloud’s 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 here opcache.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();' > /home/USER/webapps/YOUR_APP/_reset.php
curl -s https://YOUR_SITE/_reset.php
rm /home/USER/webapps/YOUR_APP/_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 > /home/USER/webapps/YOUR_APP/_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 /home/USER/webapps/YOUR_APP/_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 triedWhy it didn’t work
Hard refreshClears the browser only; the stale copy lives on the server/CDN.
?v=123Bypasses the page cache for you, but real visitors hit the plain URL.
wp cache flushClears 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

  1. Is a CDN in front? Check Server: in the response headers. If Cloudflare/other — purge it.
  2. Is the page cache serving you? Check x-runcloud-cache. HIT means PHP didn’t run — wp runcloud-hub purgeall.
  3. Is OPcache even relevant? Probe php-fpm for validate_timestamps. If 1, skip it.
  4. Only if validate_timestamps=0: reset OPcache through php-fpm, never the CLI.
  5. 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 RunCloud the layer is 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.

Share this article