Migrating a Legacy WordPress Site to Cloudflare Pages Without Losing SEO Equity
If a content site is going to outgrow WordPress, it does so quietly, one plugin update and one hosting bill at a time, until the whole thing is held together by memory rather than documentation. Almost nobody wants to be the one who breaks it moving away. A site that has been running for the better part of a decade carries thousands of inbound links, a long tail of indexed URLs with their own ranking history, and template quirks nobody remembers the reason for. Get the migration wrong and you don't get a bug report. You get a slow drop in organic traffic over the following weeks, as Google recrawls URLs it used to trust and finds nothing there.
We recently took an aging WordPress affiliate content site through that move: off a traditional host and onto a static build served from Cloudflare Pages. Building the static site itself was the easy part. Keeping it invisible to both visitors and search engines while doing it was the actual job.
A pipeline, not a deploy
The first decision was to treat every future deploy as a pipeline rather than a one-off event. A manual "build locally, upload the folder" process works fine for the first migration and then quietly rots: someone forgets a step, a stale file ships, and nobody notices until a page renders wrong in production. We built a GitHub Actions workflow with five ordered stages that runs on every push to main:
- The static build itself, where the site generator renders every page from source content into plain HTML.
- A content-integrity guard. A script checks every generated page for a non-empty content body before anything ships. A malformed source file can otherwise build a page that looks completely normal, with title, byline and layout all present and a blank space where the article should be. That passes a visual skim. It only gets caught by something checking for it specifically, so we made it a deploy blocker.
- Cache-busting. CSS and JS assets get content-hashed and renamed on every build, and every HTML reference is rewritten to match, so returning visitors don't get served a stale copy of something that actually changed.
- Redirect generation, mapping legacy URL patterns to their new equivalents from a fresh site crawl rather than a list someone wrote once during launch week and never revisited.
- Asset pruning, then deploy. Anything the built HTML doesn't reference gets dropped before upload.
Each stage gates the next one. A failed integrity check stops the deploy. A missing crawl file fails the build loudly instead of shipping stale redirects. This wasn't a one-time launch-day script; it's the pipeline every future deploy runs through, so it had to survive deploy two hundred as well as deploy one.
Protecting a decade of inbound links
Before touching a single URL, we ran a full site crawl and cross-referenced it against a backlink report to find every external link still pointing at the old site. The rule we applied throughout: fix the actual broken link at the source first, and treat a redirect as the fallback for links you don't control, the ones already indexed by Google or bookmarked somewhere you can't edit.
In practice that meant several hundred internal link corrections across the content and templates before we wrote a single redirect rule. Most were dull: trailing-slash mismatches, old category paths, numeric permalinks nobody had updated since the site changed its URL structure. The redirect list that shipped alongside those corrections was still long, and every entry on it pointed at the specific page that had actually replaced the dead one. None of them bounced to the homepage. A homepage redirect tells Google "this moved" about as convincingly as a 404 does.
A decade-old content site also carries thousands of pages that were never worth a redirect in the first place: old news posts, one-off announcements, content that just went stale, ballast rather than assets. Redirecting all of it would preserve ranking signal on pages that don't deserve it and bury the site's real content in noise. Sorting the keep-and-redirect set from the safe-to-drop set at that scale isn't a job for a single manual pass, so a few thousand candidate pages go through a three-stage verification pipeline before anything is finalised: two fast, self-hosted models triage the bulk first, flagging anything out of date or off-topic, and a stronger paid model checks their judgment on the harder calls before a human signs off. Only what survives that gets a real redirect; the rest is left to expire honestly rather than propped up with a fake 301.
The bug that only Google could see
The most serious issue we found during the migration wasn't a build bug at all, and it never showed up on the rendered page. Once the new content set was in place, we audited every surviving page's canonical tag, the field that tells search engines which URL is the authoritative one when duplicate or near-duplicate content exists. Thirty-six pages had a canonical pointing somewhere other than themselves. Thirty-five of them all pointed at the same unrelated, off-topic page, the fingerprint of a stale default carried over from the legacy CMS rather than anything set on purpose. The worst of the thirty-six pointed at a live page on a completely different site: one of the site's own core content pages was quietly telling Google that the "real" version of it lived on a competitor's domain.
A wrong canonical tag changes nothing a visitor can see. The page renders identically either way, so nobody browsing the site will ever notice, and the only way to catch it is to go looking at the markup instead of the page. Left alone, it would have kept redirecting that page's search ranking equity toward someone else's domain for as long as Google trusted the tag. Thirty-five of the affected pages also carried the wrong social-preview image, inherited from the same bad legacy data, a second symptom of the same root cause. We reset every canonical to point at itself and corrected the mismatched images before calling the migration done.
Performance bugs that only surface in production
A few performance issues didn't show up until the new site was live and being used the way people actually use it, which means scrolling a long page on a mid-range phone rather than loading it once on a fast desktop connection. A frosted-glass blur effect on the fixed header and footer looked great in the mockup and recalculated every frame anything moved behind it, a cheap-looking CSS effect that's expensive precisely because it's always in view. We dropped it from both. A decorative particle-connection background scaled quadratically with particle count and started competing with scroll for the main thread; killing the animation outright during scroll looked like a visible glitch, worse than the lag it fixed, so we disabled only the expensive connection-line pass and let the lighter particle motion keep running. And an off-canvas mobile nav panel, sitting just off the right edge of the viewport, had no overflow clipping anywhere in its parent chain. It never scrolled into view, so nobody spotted it by looking, but it silently widened the page's real scrollable width on every page, mobile only.
None of these are exotic bugs. They're the ordinary cost of shipping a redesign fast and not going back to profile it under real conditions. The fixes were small. Finding them required actually using the site the way a visitor would, not just checking that the build succeeded.
Giving every page a real author
One structural change went in alongside the migration: replacing a generic "Staff" byline with real, topic-matched author personas, each with a bio and a dedicated archive page. Google's own quality guidance leans harder every year on demonstrable expertise and a clear, checkable "who wrote this." A placeholder byline is a missed signal on every page of a content site. We mapped the existing articles to the right specialist by topic and wired the byline and author archive pages off the same author data, so adding an author or reassigning content later is a data change, not a template rewrite.
Don't trust a page that looks fine
Most people scope a CMS migration as "make the new site look the same as the old one." That framing is what gets sites into trouble, because the defects that actually cost you traffic are the ones a rendered page can't show you: a canonical tag crediting a competitor, a blank article body under a perfectly normal-looking headline, a nav panel quietly widening the page on every phone. Every check we built came out of the same suspicion. If a page renders correctly, that tells you almost nothing about whether it's correct.
That suspicion is cheap to hold and expensive to skip. Hold it and the migration passes without visitors or Google noticing anything happened. Skip it and you get an unexplained traffic dip six weeks later, long after everyone has stopped connecting it to the launch.
If you're sitting on an aging WordPress site and the idea of migrating it makes you nervous about losing your rankings, talk to us about a migration audit.
References
- Google Search Central. (2025). Consolidate duplicate URLs (rel=canonical).
- Google Search Central. (2025). Site moves with URL changes.
- Google Search Central. (2025). Creator information structured data / E-E-A-T guidance.
- Cloudflare Docs. (n.d.). Cloudflare Pages: redirects and deployment.
- Screaming Frog. (n.d.). SEO Spider: crawling for migrations. screamingfrog.co.uk












