Moving a large WordPress site to Craft without losing the rankings
The redirect map is the whole job. Everything else is data entry with extra steps.
Migrations get sold as a technical exercise and they fail as an editorial one. Moving content between two databases is largely mechanical and entirely solvable. Deciding what the content ought to be, and guaranteeing that every URL which ever earned a link still resolves to something sensible, is where the risk lives and where the project actually gets won or lost.
We've done enough of these to have a fixed order of operations. It starts in a place that surprises people.
Start with the URL inventory, before anything else
Before a single field is modelled, we assemble every URL the site has ever served. Four sources, because no single one is complete:
- The current sitemap, which gives you what the site thinks it publishes.
- Analytics, going back as far as the data does, which gives you what people actually visit.
- Search Console, which gives you what search engines have indexed — including pages the sitemap forgot.
- Server access logs where we can get them, which catch the pages nothing links to internally but something external still hits every week.
That last one is the difference between a good migration and a lucky one. Logs routinely surface a PDF from 2018 that a trade publication linked to, or an old campaign landing page that still gets traffic from a printed QR code nobody remembers making.
The combined list becomes the contract for the project. Every URL on it either survives unchanged or receives a permanent redirect to the closest genuine equivalent. Not the homepage.
On redirecting to the homepage
It is worth being blunt about this because it is the most common way migrations lose traffic. Redirecting a retired page to the homepage looks tidy in a spreadsheet and behaves, as far as a search engine is concerned, like a soft 404 — the page didn't move, it stopped existing, and pointing at something unrelated doesn't change that.
The signal that page had accumulated is discarded. Do it across a few hundred URLs and you have thrown away years of accumulated authority in an afternoon, which will show up as a traffic decline six weeks later that nobody can explain.
If a page has a genuine successor, redirect to it. If it genuinely has none, let it return a 404 and remove it from the sitemap. An honest 404 is better than a dishonest redirect.
Then decide what shouldn't come across at all
Most large WordPress sites contain a decade of pages that nobody has read since the week they were published. A migration is realistically the only moment anyone will ever be willing to delete them, and deleting them usually helps: a smaller site of pages that are all worth reading tends to perform better than a large one padded with abandoned material.
This is a client decision and not a developer one, so we don't make it. We produce the inventory with traffic figures and inbound-link counts against each entry, and the client decides what dies. Our only rule is that the decision gets made explicitly. Content that survives by nobody having looked at the list is the worst outcome, because it survives into the new site's structure and shapes it.
Model the content properly, once
The temptation at this point is to reproduce the WordPress structure in Craft so the migration script stays simple. It is a false economy of the most expensive kind: you have paid for a better CMS and imported the previous one's compromises, including every custom field bolted on over the years to work around a limitation that no longer applies.
The specific things worth un-picking: categories and tags that were used interchangeably by different people over five years. Custom fields that duplicate each other because two developers solved the same problem twice. Page-builder blocks whose content is really HTML in a text field. Post types that exist because a plugin needed them rather than because the content is genuinely different.
Model it the way it should have been modelled. The migration script gets harder to write. The next five years get considerably easier, and the script is thrown away the day after launch.
A redirect to the homepage is a soft 404 wearing a costume.
The script is the boring part, and should stay boring
We write migrations as repeatable scripts rather than one-off imports, and we run them many times. That matters because content keeps being published while the new site is being built — a migration that can only be run once forces a content freeze, and content freezes on a busy site are either painful or ignored.
A re-runnable script means we can do a full import in week two to find the problems, again in week five to check the fixes, and once more the night before launch to pick up everything published in between. Nobody has to stop working.
The things that break, in rough order of frequency: inline images referencing paths that no longer exist, shortcodes that render as literal text, character encoding on anything typed in Word, and posts with an author who no longer has an account.
Launch, then actually watch
Redirect rules deploy with the site, not after it. On launch day we check the top hundred URLs by traffic by hand, because automated checks confirm a redirect exists without confirming it goes somewhere sensible.
Then it's Search Console daily for a fortnight, watching the coverage report for 404s the inventory missed. It always misses some. That's not a failure of the process — it's why the fortnight exists.
In our experience most post-migration losses aren't caused by missing redirects at all. They're caused by missing redirects that nobody looked for until the monthly report, by which time the decline has a month of momentum and the client has formed a view about the new site.
What to expect, so nobody panics
A short dip while search engines re-crawl and re-establish the mapping is normal even when every single thing has been done correctly. Rankings wobble, then settle. Telling the client this in advance is part of the job, because the alternative is an anxious phone call in week two about a completely expected fluctuation.
What is not normal is a dip that doesn't recover. That's a redirect problem, it's findable, and it's fixable — which is the strongest argument for keeping access to the old site's analytics and Search Console well beyond launch. Losing that access on launch day, which happens more often than you'd think, means diagnosing a problem with no view of what the site used to do.