Introduction
Migrating an enterprise website from WordPress to Sitecore is not a one-time event.
Most organizations have hundreds of pages, multiple business stakeholders, SEO considerations, and ongoing content publishing requirements. A complete cutover often introduces unnecessary risk, especially when business teams expect uninterrupted service throughout the migration journey.
In one of our recent migration projects, the business decided to move from WordPress to Sitecore AI using a phased rollout strategy rather than a full migration in one shot. The objective was simple: migrate content incrementally while ensuring visitors continued to experience a single website.
Although the concept sounds straightforward, the routing architecture required careful planning.
During the migration period:
- Some pages were served from Sitecore.
- Some pages remained in WordPress.
- Both platforms had to coexist.
- Existing URLs could not change.
- SEO rankings had to be protected.
- Content teams needed the flexibility to migrate sections independently.
The challenge was not migrating content. The challenge was making two CMS platforms behave like one website.
This article explains the architecture, routing strategy, and Netlify Edge Function implementation we used to achieve that goal.
The Migration Challenge
The original website was fully managed in WordPress. The target platform was Sitecore AI running on a modern composable architecture.
Migrating every page at once was not realistic. Different business units owned different sections of the website. Some content areas were ready for migration while others required redesign, content review, or approval cycles.
As a result, both platforms needed to remain active for several months. The business had one non-negotiable requirement:
Users must continue accessing content through the same URLs regardless of which CMS serves the page.
For example:
/products/business-banking
/resources/industry-report
/about-us
/contact
Those URLs already had search engine rankings, backlinks, marketing campaign references, and bookmarks.
Changing them was not an option.
High-Level Architecture
The website was hosted on Netlify, which provided an ideal place to introduce a routing layer.
The architecture looked like this:
Every request entered through Netlify. The Edge Function acted as a traffic controller. Instead of maintaining a large routing table, the architecture relied on Sitecore being the primary source of truth. If Sitecore could resolve a route, the request remained in Sitecore. If Sitecore could not resolve the route, the request automatically fell back to WordPress. This approach simplified migration management considerably.
Why We Chose a 404 Fallback Model
One of the first design decisions involved determining how route ownership would be managed.
Several approaches were considered:
Central Route Registry
Maintain a database containing all migrated routes. While technically possible, it introduced additional maintenance overhead. Every migration release would require route updates. Every rollback would require route updates. Operational complexity grows quickly.
Migration Mapping File
Store route ownership inside configuration files. This works for smaller websites but becomes difficult to maintain as the number of migrated pages increases.
Sitecore-First Routing
Allow Sitecore to handle every request first. If Sitecore returns content, serve it. If Sitecore returns 404, fall back to WordPress. This was the simplest and most maintainable option.
The implementation follows exactly this pattern. The Edge Function calls the Sitecore application first through context.next(). If Sitecore returns anything other than a 404, the response is immediately returned to the visitor. Only when Sitecore responds with a 404 does the WordPress proxy logic execute.
GitHub Link- router.ts
Request Flow
The request lifecycle is straightforward.
This design creates a natural migration path. The moment a page is published in Sitecore, Sitecore becomes the owner of that URL. No routing table updates are required. No deployment changes are required. The ownership transition happens automatically.
URL Normalization Challenges
One challenge we encountered involved differences between Sitecore and WordPress URL structures.
During development and content migration, requests sometimes included:
/staging/5474/about-us
or
/old-site/en/banking
These routes made sense in Sitecore but did not exist in WordPress.
To handle this, the Edge Function performs URL normalization before forwarding requests to WordPress.
The router removes:
- Staging prefixes
- Sitecore site identifiers
- Locale prefixes
Examples:
/staging/5474/about-us
becomes
/about-us/
and
/old-site/en/banking
becomes
/banking/
The router also automatically adds trailing slashes to WordPress page URLs while avoiding modifications to static assets and files. This ensures WordPress receives URLs in the format it expects.
GitHub Link- router.ts
Proxying Requests to WordPress
Once a route is determined to be unavailable in Sitecore, the request is forwarded to WordPress.
The Edge Function constructs a WordPress URL using the normalized path and original query string.
For example:
https://www.company.com/resources/report?id=123
might become:
https://wordpress-site.com/resources/report/?id=123
The visitor never sees this internal URL. Everything continues to appear under the primary website domain. From a user perspective, nothing changes.
Header Management
Forwarding requests sounds simple until authentication, language selection, and browser context enter the picture.
The router selectively forwards important request headers including:
- Accept
- Accept-Language
- User-Agent
- Content-Type
- Authorization
At the same time, cookies are intentionally excluded. This was an important decision. Forwarding all cookies from Sitecore requests into WordPress often creates unnecessary coupling between systems and can introduce unexpected behaviour. The router only forwards the information WordPress genuinely needs to generate the response.
GitHub Link- router.ts
Handling Redirects Correctly
Redirects become particularly interesting when multiple systems are involved.
Imagine WordPress returns:
Location:
https://old-site.com/about-us/
Without additional handling, visitors could suddenly be redirected to the WordPress origin. That would expose implementation details and break the unified website experience. To prevent this, the Edge Function rewrites redirect locations before returning responses. Internally generated WordPress redirects are transformed so they continue pointing to the public website domain. Visitors remain on the same website while WordPress remains hidden behind the routing layer.
GitHub Link- router.ts
Managing Redirect Chains
WordPress plugins, SEO tools, and legacy URL rules often generate multiple redirects. The router therefore follows redirects manually. Instead of blindly accepting redirect responses, the implementation performs controlled redirect handling with a maximum redirect threshold. This prevents infinite loops while ensuring legitimate redirects continue to function. Operationally, this proved valuable because migration projects frequently expose old redirect rules that nobody remembers creating. The logging built into the Edge Function helped identify several redirect chains during testing that would otherwise have gone unnoticed.
GitHub Link- router.ts
What This Means for Content Teams
One of the biggest advantages of this architecture is that migration ownership shifts from technical teams to content teams.
A typical migration process looks like this:
Before Migration
/about-us
exists only in WordPress. WordPress serves the page.
During Migration
Content authors rebuild the page in Sitecore. The page is tested and approved.
After Publication
Sitecore now resolves:
/about-us
The Edge Function receives a successful Sitecore response. The WordPress fallback is never triggered. Traffic automatically moves to Sitecore. No routing updates are required. No deployment is required. The URL remains unchanged.
Operational Lessons Learned
A few observations became clear during implementation.
First, simplicity wins.It is tempting to create sophisticated route ownership databases and synchronization processes. In practice, allowing Sitecore to become the route authority dramatically reduced operational overhead.
Second, URL normalization requires more attention than most teams expect. Site structures, locale handling, and legacy URL patterns often contain years of accumulated complexity.
Third, logging is critical.
When a page unexpectedly appears from WordPress instead of Sitecore, the first question is always:
"Why did the fallback happen?"
Detailed routing logs significantly reduce troubleshooting time.
Finally, treat redirects as a first-class migration concern. Redirect behaviour that worked perfectly in a standalone WordPress environment may behave differently once a proxy layer is introduced.
Testing redirect scenarios early saves a lot of production support effort later.
Final Thoughts
Running two CMS platforms behind a single website sounds complicated, but the routing strategy does not need to be. By placing Netlify Edge Functions in front of both systems and adopting a Sitecore-first, WordPress-fallback approach, we created a migration model that was easy to operate, easy to scale, and easy for content teams to understand.
- Pages could move from WordPress to Sitecore independently.
- URLs remained unchanged.
- SEO value was preserved.
- Users continued to interact with a single website.
Most importantly, the migration could progress at the pace the business needed without introducing unnecessary technical complexity.
Sometimes the best migration architecture is not the one with the most moving parts. It is the one that quietly stays out of the way and lets the business migrate content with confidence.
GitHub Link- router.ts
References
- Netlify Edge Functions Overview
- Netlify Edge Functions API Reference
- Netlify Routing and Redirects Documentation
- Sitecore XM Cloud Documentation
- WordPress Permalinks Documentation



No comments:
Post a Comment