Skip to main content
Last Reviewed: 2026-04-14

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-Key response headers in next.config.mjs to associate cache tags with routes
  • Setting up @pantheon-systems/nextjs-cache-handler for persistent caching
  • Creating Pages Router pages with getStaticProps and 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
Information:
App Router?

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-handler version 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

RouteSurrogate-Key valueInvalidated when
/blogspost-listAny post changes
/blogs/my-postpost-my-post post-listThat specific post or any post list change
/blogs?category=5post-list term-5Any post changes or category 5 content changes

The headers config supports:

  • Path parameters — Named segments like :slug in the source pattern can be interpolated into header values.
  • Named captures from has conditions — Regex capture groups in query parameter matchers like (?<categoryId>\\d+) are available as :categoryId in 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:

Information:
Pages Router vs App Router revalidation

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:

  1. A WordPress mu-plugin that sends webhooks when content changes. See Add the WordPress mu-plugin.

  2. 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