WordPress cache integration for Next.js Pages Router
Use Surrogate-Key headers to enable edge cache clearing for Pages Router sites when WordPress content changes
This guide shows you how to set up cache invalidation for a Next.js site that uses the Pages Router (pages/ directory with getStaticProps). It works with both Next.js 15 and Next.js 16.
Learning objectives
This tutorial walks you through:
- Configuring
Surrogate-Keyresponse headers innext.config.mjsto associate cache tags with routes - Setting up
@pantheon-systems/nextjs-cache-handlerfor persistent caching - Creating Pages Router pages with
getStaticPropsand ISR for WordPress data - Building a revalidation API endpoint that uses
res.revalidate()for path-based cache purging - Connecting a WordPress mu-plugin that sends webhooks when content changes
- Configuring shared secrets on both sites via Terminus Secrets Manager
If your site uses the App Router (app/ directory), you do not need Surrogate-Key headers. The cache handler extracts tags automatically. See:
Requirements
- A Next.js site on Pantheon using the Pages Router (see Hello World tutorial to create one)
- A WordPress site on Pantheon
@pantheon-systems/nextjs-cache-handlerversion 0.7.0 or later- Install the following:
* Requires logging in after installation.
How it works
You define Surrogate-Key response headers in next.config.mjs that map route patterns to cache tags. Pantheon's edge CDN reads these headers and associates the listed tags with each route. When WordPress content changes and a webhook fires, the revalidation endpoint calls res.revalidate() to regenerate the page, and the cache handler clears the matching paths from the edge CDN.
Install the cache handler
Configure Next.js
Create a cache-handler.mjs file in your project root:
Reference it in next.config.mjs and add Surrogate-Key headers for your routes:
Header values by route
| Route | Surrogate-Key value | Invalidated when |
|---|---|---|
/blogs | post-list | Any post changes |
/blogs/my-post | post-my-post post-list | That specific post or any post list change |
/blogs?category=5 | post-list term-5 | Any post changes or category 5 content changes |
The headers config supports:
- Path parameters — Named segments like
:slugin thesourcepattern can be interpolated into header values. - Named captures from
hasconditions — Regex capture groups in query parameter matchers like(?<categoryId>\\d+)are available as:categoryIdin header values.
Create Pages Router pages
Use getStaticProps with ISR for your blog pages:
Create the revalidation endpoint
Pages Router API routes cannot use revalidateTag() directly. Instead, use res.revalidate() for path-based revalidation. The endpoint receives surrogate keys from WordPress and resolves them to page paths using the Surrogate-Key header patterns:
In the App Router, revalidateTag() invalidates cache entries by tag and the cache handler automatically resolves tags to paths for CDN purging. In the Pages Router, you must map tags to paths yourself and use res.revalidate(path) instead.
Connect WordPress webhooks
You need:
-
A WordPress mu-plugin that sends webhooks when content changes. See Add the WordPress mu-plugin.
-
Shared secrets configured on both sites. See Configure secrets.
The surrogate key patterns (post-{slug}, post-list, term-{id}) must match between the WordPress mu-plugin and your Surrogate-Key header values.
Rule ordering and cumulative headers
Next.js applies headers cumulatively. If multiple rules match a request, all of their headers are added. If you need exclusive matching — where only the most specific rule applies — use the missing condition on the base rule:
Limitations
The headers config in next.config.mjs can only interpolate values from the URL — path segments and query parameters. It cannot include data resolved at runtime (e.g., WordPress post IDs looked up from a slug). Use slug-based keys consistently on both sides to avoid this limitation.
Next steps
- WordPress cache integration for Next.js 15 (App Router) — App Router with automatic tag extraction.
- WordPress on-demand revalidation for Next.js 16 — Next.js 16 with
cacheTag(). - Set environment variables
- Deploy to Test and Live environments