I faced an interesting challenge with some of our XM Cloud projects: how to efficiently update statically generated pages when content changes. We needed a way for content editors to trigger on-demand regeneration of Next.js pages after modifying the underlying content in Sitecore XM Cloud CMS. While Sitecore XM Cloud hooks are often the go-to solution for such scenarios, we discovered that these calls can be queued and may take some time to execute. To address this and speed up page revalidation, I developed a custom plugin. This solution bridges the gap between Sitecore XM Cloud CMS and Next.js heads using Incremental Static Regeneration (ISR).
I'm pleased to share that this plugin will soon be available on the Sitecore marketplace for others who might find it useful.
The Challenge
In a typical Sitecore XM Cloud setup with a Next.js head, pages are statically generated at build time. But what happens when content authors update pages in Sitecore? Without proper revalidation, these changes won't be reflected until the next full build. This is where our revalidate plugin comes into play.
Architecture Overview
The revalidation plugin operates as follows:
- 1. Content Update: A content author makes changes in Sitecore XM Cloud Content Management (CM).
- 2. Trigger: The update triggers a PowerShell script within Sitecore.
- 3. Configuration Retrieval: The script fetches configuration details from the Revalidate Plugin Config.
- 4. API Call: Using the configuration, the script constructs and sends an API call to the Next.js Revalidate API.
- 5. Page Revalidation: The Next.js API processes the request and revalidates the affected static pages.
- 6. Content Delivery: Updated static pages are now ready to be served to end users.
This workflow ensures that content changes in Sitecore XM Cloud are promptly reflected in the statically generated Next.js frontend, maintaining both the performance benefits of static generation and the dynamic nature of content management.
The solution consists of two main components:
- 1. A Sitecore PowerShell script that runs in the Content Management (CM) instance
- 2. A Next.js API endpoint that handles revalidation requests
Let's dive into each component.
The PowerShell Script in Sitecore CMS
The PowerShell script is the bridge between Sitecore and our Next.js head. Here's how it works:
function Get-PageDetails { param( [Parameter(Mandatory = $true)] [Sitecore.Data.Items.Item]$Item ) $configItem = Get-Item -Path "master:" -ID "{1FD49D13-CFB4-459D-BFAB-A8C3024686A5}" # ... configuration logic ... $relativePath = $itemPath.Substring($siteRootItem.Paths.FullPath.Length) $relativePath = $relativePath -ireplace '^/home(?=/|$)', '' return @{ SiteUrl = $siteUrl Secret = $secret RelativePath = $relativePath } }
The script does several clever things:
- 1. Determines the page's relative path within the site
- 2. Fetches configuration (API URL and secret) based on the site root
- 3. Handles multi-language support
- 4. Makes a secure API call to the Next.js head
The Next.js Revalidate API
On the Next.js side, we've implemented a secure revalidation endpoint:
// This function handles the revalidation requests from Sitecore export default async function handler( req: NextApiRequest, res: NextApiResponse ) { // Only process POST requests if (req.method === "POST") { // Extract the secret from the query parameters const secret = req.query?.secret; // Verify the secret here (implementation not shown) try { // Extract pages and locale from the request body const pages = req.body?.pages; const locale = req.body?.locale; // Array to store successfully revalidated pages const revalidatedPages = []; // Iterate through each page for (const page of pages) { // Construct the full page path - note how in Sitecore head implementation we add locale and _site_ to the path const pagePath = `/${locale}/_site_${sitecoreSiteName}${page}`; // Revalidate the page await res.revalidate(pagePath); // Add to list of revalidated pages revalidatedPages.push(pagePath); } // Return success response return res.status(200).json({ revalidated: true, pages: revalidatedPages, now: Date.now(), }); } catch (error) { // Error handling (implementation not shown) return res.status(500).json({ error: "Error revalidating" }); } } else { // Return method not allowed for non-POST requests return res.status(405).json({ error: "Method not allowed" }); } }
What this revalidation endpoint does:
- Validates the secret token
- Handles multiple page revalidations
- Supports multi-language content
- Follows Sitecore's foundation head URL structure
Configuration and Setup
In Sitecore, I've configured some configuration items for the revalidate plugin, which I'm omitting for brevity. Here's they contain:
- Site Root (Reference to your site's root item)
- Revalidate API URL
- Secret (for secure communication)
A few notes on implementation details:
Path Handling: Notice how we handle the /home segment in paths:
$relativePath = $relativePath -ireplace '^/home(?=/|$)', ''
Security: Always use HTTPS and keep your secret token secure. The PowerShell script URL-encodes the secret:
$encodedSecret = [System.Web.HttpUtility]::UrlEncode($secret)
Error Handling: Both components include robust error handling to ensure content authors get meaningful feedback.
What's Next?
Some enhancements I thougtht about, which could include:
- Support for wildcard revalidation
- Automatic dependency tracking
- Queue-based revalidation for high-load scenarios
Conclusion
This revalidate plugin bridges the gap between Sitecore XM Cloud's content authoring experience and Next.js's static generation capabilities. It's a practical solution that maintains the benefits of both worlds: fast static pages and instant content updates.
Remember, the key to success with this implementation is understanding your specific use case and adjusting the configuration accordingly. The provided code is a solid foundation that you can build upon based on your needs.
This solution has been battle-tested in production environments and continues to evolve. Feel free to reach out if you have questions or want to contribute to its improvement!