📝 The REST Endpoint That Never Heard About the Update
A caching plugin or a reverse proxy in front of WordPress typically hooks into post-save actions to purge the cached HTML of the pages that display a post – but the WordPress REST API serves its own, separate set of URLs (/wp-json/wp/v2/posts/123 and similar), which a cache purge rule written with only the theme’s page templates in mind can miss entirely. The post itself updates correctly in the database, the website’s normal pages show the new content immediately, and the REST API – queried directly by a headless frontend or a mobile app – keeps serving the stale cached version until its own cache separately expires.
🔎 The Problem
A typical page-cache purge rule, configured (or defaulted) to clear cached URLs matching the site'"'"'s normal page patterns: / <- cleared on any post update /category/* <- cleared on any post update /2026/*/post-slug/ <- cleared for the specific post But a headless frontend or mobile app is actually querying: /wp-json/wp/v2/posts/123 /wp-json/wp/v2/posts?slug=post-slug Neither of these matches any pattern the purge rule was written for - the REST endpoint keeps serving its own separately cached response (whether cached by the same plugin, a CDN, or a reverse proxy in front of the whole site) until that cache entry expires on its own schedule, completely independent of the post actually being updated.
✅ Fix: Purge REST API URLs Explicitly, Not Just Theme Pages
- Whatever cache-purge hook fires on post save (whether a plugin’s own action or a custom function hooked to save_post) needs to explicitly include the post’s REST API URL pattern in whatever it purges – most popular caching plugins support adding custom URL patterns to a purge rule, but it has to be added, since it isn’t assumed by default.
- For a CDN or reverse proxy sitting in front of WordPress with its own independent cache, a purge API call (Cloudflare’s cache-purge API, or an equivalent) triggered from the same save_post hook keeps that outer cache layer in sync too – a purge rule that only clears WordPress’s own internal cache does nothing about a completely separate CDN cache layer sitting in front of it.
- Setting a deliberately short cache TTL specifically on wp-json/ routes (rather than matching the TTL used for regular page HTML) limits how stale the REST API can ever get even if a specific purge rule is missed, trading a small amount of cache efficiency for freshness on the endpoints an external app actually depends on.
⚠️ Why This Slips Past Normal Testing
- Whoever configured (or tested) the caching setup was very likely checking the website itself – the actual rendered pages – which purge correctly, so everything looks completely fine from that vantage point, with no reason to separately check a REST endpoint that the website’s own pages never call.
- This becomes visible specifically once a separate consumer of the REST API exists (a mobile app, a decoupled frontend, an integration) – a WordPress site used purely to render its own theme’s pages, with nothing else querying wp-json/ directly, would never surface this gap at all.
A cache purge rule only clears what it was told about – and a REST endpoint nobody mentioned when that rule was written keeps quietly serving yesterday’s answer, no matter how current the actual post is.
