

Headless Website Cache Invalidation After Content Updates
Author
A technical runbook for mapping WordPress content events to cache keys, configuring webhooks for real-time invalidation, and verifying or rolling back the process.
Understanding Cache Invalidation in Headless WordPress
In a headless setup, WordPress acts as a content API, and the front end is built and served separately. Caches exist at multiple layers: the WordPress object cache, the API response cache, the build output, and the CDN edge.
Invalidation means removing or updating cached content when the underlying data changes.
The core decision is whether to use time-based revalidation or event-driven invalidation. Time-based revalidation is simple but can delay updates. Event-driven invalidation reacts to WordPress hooks and is the focus here.
A common approach is to purge the cache for a specific key when a post is saved. However, a single content update can affect many pages: the post itself, the homepage, category archives, tag pages, and search results.
You need a mapping that connects each content change to every cache key that might be affected.
Without a clear mapping, you risk either over-purging (which hurts performance) or under-purging (which serves stale content). The goal is to invalidate only what changed, but in practice you may need to invalidate a set of related keys.
Mapping Content Update Events to Cache Keys
WordPress fires specific hooks during the content lifecycle. The most relevant are `save_post`, `publish_post`, `wp_insert_post`, and `transition_post_status`. Each event can be mapped to a set of cache keys.
For example, when a post is published, the following cache keys may need invalidation:
– The post’s own URL (e.g., `/blog/my-post/`)
– The homepage (e.g., `/`)
– The category archive (e.g., `/category/news/`)
– The tag archive (e.g., `/tag/tech/`)
– The author archive (e.g., `/author/jane/`)
– Any search result pages that include the post
A practical way to implement this mapping is to define a function that, given a post ID, returns an array of cache keys. This function can use WordPress functions like `get_permalink()`, `get_the_category()`, and `get_the_tags()` to build the list.
Here is a simplified example in PHP:
“`php
function get_cache_keys_for_post($post_id) {
$keys = [];
$keys[] = get_permalink($post_id);
$keys[] = home_url(‘/’);
$categories = get_the_category($post_id);
foreach ($categories as $cat) {
$keys[] = get_category_link($cat->term_id);
}
$tags = get_the_tags($post_id);
if ($tags) {
foreach ($tags as $tag) {
$keys[] = get_tag_link($tag->term_id);
}
}
return array_unique($keys);
}
“`
This function is a starting point. You may need to extend it to include custom post types, taxonomies, or related posts. The key is to centralize the mapping so that every invalidation trigger uses the same logic.
Once you have the cache keys, you need to decide how to invalidate them. If you are using a CDN, you can call its purge API. If you are using a static site generator, you may need to trigger a rebuild for the affected pages.
Configuring Webhooks for Real-Time Invalidation
Webhooks allow WordPress to notify an external service when a content update occurs. The external service can then purge the CDN or trigger a build. This is more efficient than polling for changes.
To set up a webhook, you need to create an endpoint on your server that receives a POST request from WordPress. The endpoint should verify that the request is legitimate, parse the payload, and perform the invalidation.
WordPress can send webhooks using the `wp_remote_post()` function. You can hook into `save_post` and call the endpoint with the post ID and event type.
Here is an example of sending a webhook on post save:
“`php
function send_webhook_on_save($post_id) {
$webhook_url = ‘https://your-server.com/webhook/invalidate’;
$payload = json_encode([
‘post_id’ => $post_id,
‘event’ => ‘save_post’,
‘keys’ => get_cache_keys_for_post($post_id)
]);
wp_remote_post($webhook_url, [
‘body’ => $payload,
‘headers’ => [‘Content-Type’ => ‘application/json’]
]);
}
add_action(‘save_post’, ‘send_webhook_on_save’);
“`
On the receiving end, you need to validate the request. A common method is to include a secret token in the request headers or body. Your endpoint should check this token before processing.
After validation, the endpoint should iterate over the cache keys and purge them. If you are using a CDN like Cloudflare, you can use its API to purge by URL. If you are using a static site generator, you might trigger a rebuild for the specific pages.
Here is an example of a webhook receiver in Node.js:
“`javascript
const express = require(‘express’);
const app = express();
app.use(express.json());
app. post(‘/webhook/invalidate’, (req, res) => {
const token = req. headers[‘x-webhook-token’];
if (token ! == process. env. WEBHOOK_SECRET) {
return res. status(401). send(‘Unauthorized’);
}
const { keys } = req.
body;
// Purge each key from CDN or trigger build
keys. forEach(key => purgeCache(key));
res. status(200). send(‘OK’);
});
“`
You must handle failures. If the webhook request fails, you need a retry mechanism. WordPress can be configured to retry failed requests, or you can use a queue system. Also, consider logging all invalidation events for auditing.
Verification is critical. After a webhook fires, you should check that the cache was actually purged. You can do this by fetching the URL with a cache-busting query parameter and comparing the response to the expected content.
If the content is stale, you need to investigate the failure.
Rollback is also important. If a webhook causes an error, you should be able to revert to the previous state. This might involve restoring a backup or re-purging with a different method. Document your rollback steps in your runbook.
Finally, keep a drill record. Note the date, the content update, the cache keys invalidated, and the verification result. This helps you refine your mapping and webhook configuration over time.
By following this runbook, you can ensure that content updates are reflected quickly and reliably, without serving stale data to your visitors.
Triggering the Build and CDN Purge Pipeline
The first step is to trigger the build and purge sequence. In a typical setup, saving a content update in the CMS sends a webhook to your build system.
For example, a WordPress save action can fire a webhook to a CI service like GitHub Actions or a custom build server. The webhook payload should include the content ID and the type of change (create, update, delete).
Your build system then runs the site generator to produce static files or updates the API cache.
Example webhook configuration (illustrative):
“`json
{
"event": "post_updated",
"post_id": 12345,
"modified": "a previous platform version-04-01T10:30:00Z"
}
“`
After the build completes, you must purge the CDN cache for the affected URLs. Most CDNs provide an API for this. For instance, using a curl command to purge a specific path:
“`bash
curl -X POST https://api.cdnprovider.com/v1/purge \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d ‘{"urls": ["https://example.com/blog/new-post"]}’
“`
Expected result: The build succeeds, and the CDN returns a 200 OK with a purge request ID. You should log this ID for later verification. If the build fails, you will see a non-zero exit code in your CI logs, and the purge should not be attempted.
Verifying Page and API Cache Freshness
After triggering the purge, you must verify that the updated content is served correctly. For pages, check the response headers from the CDN.
A fresh page should show a cache status such as `HIT` or `MISS` depending on your configuration, but the content should reflect the latest update. Use curl to inspect headers:
“`bash
curl -I https://example.com/blog/new-post
“`
Look for headers like `x-cache-status: HIT` or `age: 0`. If the age is low and the content matches the CMS, the page is fresh. For APIs, send a request to the endpoint and compare the response body with the expected data. For example:
“`bash
curl https://api.example.com/posts/12345
“`
Check that the `updated_at` field matches the modification time from the webhook. If the API returns stale data, the cache key may not have been invalidated correctly.
In that case, you may need to purge the API cache separately or adjust the cache key design to include the content version.
Handling Invalidation Failures and Rollback
Failures can occur at any stage. Common signals include a build error, a purge API timeout, or a CDN still serving stale content after a reasonable time. If the build fails, the old content remains live, which is safe but means the update is not published.
You should fix the build error and retry. If the purge fails, you might see an error response from the CDN API. In that case, you can retry the purge with exponential backoff, but avoid hammering the API.
If the CDN continues to serve stale content, you may need to force a full cache clear or use a versioned URL strategy. For rollback, if the new content has issues, you can revert the CMS change and trigger a rebuild and purge again.
Alternatively, you can temporarily serve a cached version from the previous build. Document the rollback steps in your runbook so that any team member can execute them under pressure.
Documenting the Invalidation Runbook
After each invalidation event, record the operation details. This documentation serves as a drill record and helps improve future processes. Include timestamps, the commands executed, the purge request IDs, and the verification results. For example:
| Timestamp | Action | Command/Request ID | Result |
|———–|——–|——————-|——–|
| a previous platform version-04-01 10:31:00 | Build triggered | Build #1234 | Success |
| a previous platform version-04-01 10:32:00 | CDN purge | Purge ID: 98765 | Success |
| a previous platform version-04-01 10:33:00 | Page verification | curl -I | Fresh |
Store this log in a shared location, such as a wiki or a dedicated log file. Review it periodically to identify recurring issues. If you notice frequent purge failures, consider adjusting your cache key design or increasing the purge timeout.
The goal is to make the invalidation process predictable and auditable.
Next step
Need help implementing a robust cache invalidation workflow for your headless site? Contact our team for a technical consultation.
Related services and further reading
Official references and sources
Comments (0)
No comments yet. Be the first!