Migrating a multilingual WordPress site is a standard migration multiplied by every language you serve, plus one layer that exists nowhere else: the hreflang web that tells search engines which page is which language’s version of which content. Everything that can go wrong in a single-language move, missed URLs, broken redirects, lost metadata, can now go wrong per language, and the multilingual-specific failure, breaking the language relationships while every individual page survives, is invisible to casual checks because every URL still resolves. The safe sequence is the crawl-first one, per language: inventory every URL in every language with its translations recorded, map the whole matrix to the new structure, redirect within languages per Google’s site-move discipline, and rebuild the hreflang reciprocity on the other side. That per-language inventory-and-parity discipline is exactly how WPBuildAI runs multilingual rebuilds, because the language relationships are data in the crawl, and data in the crawl is data the launch check can verify.
What makes multilingual moves categorically harder
Three multipliers stack. Scale first, and honestly: a 200-page site in four languages is an 800-page migration, with the redirect map, metadata parity, and testing effort scaling with it, which is why multilingual projects estimated from the primary language’s size run over by whole languages. Structure second: WordPress multilingual setups are plugin regimes, WPML, Polylang, and multisite arrangements each encode languages differently, subdirectories, subdomains, parameters, separate installs, and the encoding decides what the crawl sees and what the new structure must map from; a migration that changes the language URL scheme, parameters to subdirectories being the common modernization, multiplies the redirect map’s complexity again. Relationships third, the layer unique to multilingual: hreflang annotations link each page to its alternates across languages, and those links are reciprocal by specification, page A naming page B requires B naming A back, so half-updated relationships fail as a web even where they survive as pages.
The relationship layer is where multilingual migrations quietly lose their international rankings: every page redirects correctly within its language, every page loads, and yet the annotations point at old URLs or lost reciprocity, so engines stop trusting the language mapping and start serving the wrong language to the wrong country, a regression users feel before dashboards show it.
The per-language inventory, and the matrix it produces
The crawl-first stage runs per language and then joins: crawl every language’s URL space, subdirectories, subdomains, or parameterized variants as the plugin regime serves them, recording per page the standard inventory, content, titles, metas, images, links, plus the multilingual columns, the declared language, the hreflang cluster it claims, and the translated pages it points to. The join produces the translation matrix, each content item as a row, each language’s URL in its column, and that matrix, not any single language’s list, is the migration’s contract: it is simultaneously the redirect map’s source (each cell maps old to new within its language), the rebuild’s parity spec (each row’s translations must exist and interlink), and the launch check’s test file (each cell resolves, each row reciprocates).
The matrix also surfaces the decisions single-language migrations never face, and better before the move than during: partial translations, rows with empty cells, get an explicit policy, redirect to the language homepage, fall back to the primary language, or retire; machine-translated thin pages inherited from an old plugin get judged, carry, improve, or prune; and languages that never earned traffic get the honest conversation about whether the new site should carry them at all, since every carried language is permanent maintenance on the other side.
URL strategy and redirects, language by language
| Decision | The safe default | The trap | Verdict |
|---|---|---|---|
| Language URL scheme | Subdirectories per language | Parameters, mixed schemes | Modernize once, during the move |
| Old-to-new mapping | Within-language, cell by cell | Cross-language redirects | Never hop languages in a 301 |
| Partial translations | Explicit per-row policy | Silent fallbacks to another language | Soft-404 territory, decide it |
| hreflang rebuild | Generated from the matrix | Hand-maintained annotations | Reciprocity by construction |
| Launch check | Every cell + every row | Primary language only | The other languages are where it breaks |
Two rows are load-bearing. Within-language redirects: an old German URL 301s to the new German URL, never to the English equivalent because the German page moved or merged, since cross-language redirects read as irrelevant destinations to engines and as hostility to users; where a language loses a page, the redirect target is that language’s closest equivalent or its section root, decided in the matrix rather than defaulted by a wildcard. And generated hreflang: annotations hand-maintained across a migration break reciprocity somewhere, at 800 pages statistically guaranteed, while annotations generated from the same matrix that drove the rebuild are reciprocal because the generator makes them so, which is the same by-construction argument as canonicals and the reason metadata parity belongs in the build, not the checklist.
Launch verification, multiplied correctly
The launch check is the single-language check run per cell plus the relationship pass per row. Per cell: bulk-test every old URL in every language for the 301, the mapped within-language destination, and the single hop, because sampling the primary language and trusting the pattern is exactly how the third language ships broken. Per row: fetch each new page and verify the hreflang set, all alternates present, all URLs current, reciprocity intact, and each page’s canonical self-referencing within its own language, since the classic post-launch tangle is canonicals or alternates pointing across languages and engines consolidating versions that should stay distinct. Then the platform-truth checks: language switchers pointing at new URLs, sitemaps per language or with alternate annotations matching the pages, and the Search Console properties per language section confirmed and watched separately, because international regressions show up in one country’s queries while the aggregate graph stays flat.
The monitoring weeks read per language too: indexing and 404 reports filtered by section, the first appearance of wrong-language results in a target market treated as the alarm it is, and the settling period judged per language, since smaller languages with thinner crawl attention settle slower than the primary.
The estimate conversation, had honestly
One paragraph of project truth spares a quarter of conflict: multilingual migrations are priced wrong when they are priced from the primary language, and every stakeholder should see the multiplier arithmetic before work starts. The honest estimate reads the matrix, total cells rather than primary-language rows, adds the relationship layer as its own line item, and budgets verification per language rather than as a single launch pass. The same conversation sets the sequencing expectation: languages can launch together behind one switch, cleanest for the hreflang web, or staggered by language, gentler on review capacity but requiring the annotations to be correct at every intermediate state, which is harder, not easier, and only worth it when the team genuinely cannot verify all languages in one window. Either way, the matrix is the shared document that keeps the estimate, the build, and the check speaking the same language about all the languages.
Where the rebuild changes the multilingual math
Multilingual is where the platform argument gets loudest, because the plugin regime was the complexity. On the WordPress side, languages live in plugin state, annotations are emitted by plugin code that fights themes and caches, and the whole apparatus is another subscription aging toward the next compatibility break. On a generated static build, languages are folders and the matrix is data: each language’s pages generated from the same content structure, hreflang and canonicals emitted from the matrix by construction, per-language sitemaps derived rather than maintained, and nothing at request time to slow the crawlers that grade speed as existence. The migration is the one moment this conversion is nearly free, the matrix already exists as the migration’s contract, so making it the site’s permanent data model costs little and retires the plugin regime that made multilingual fragile in the first place, which is precisely how the WPBuildAI multilingual rebuild is structured: the crawl produces the matrix, the matrix produces the site, and the same file that proved parity at launch keeps proving it every build after.
Key takeaways: migrating a multilingual WordPress site
Multiply the standard discipline by every language and add the relationship layer: crawl per language into a translation matrix, content item by row, language URL by cell, and make the matrix the contract, redirect map within languages, parity spec for the rebuild, test file for launch. Decide the multilingual-only questions in the matrix before moving, partial translations, thin machine translations, languages worth carrying, and never redirect across languages. Generate hreflang and canonicals from the matrix so reciprocity holds by construction, verify per cell and per row at launch, and monitor per language after, because the aggregate graph hides single-market regressions. The plugin regime was the fragility; a matrix-driven static rebuild, the WPBuildAI shape, retires it while the matrix is already in hand.
Quick answers
How do I migrate a multilingual WordPress site without losing rankings?
Run the crawl-first discipline per language: inventory every language’s URLs into a translation matrix, content item per row, each language’s URL per cell, then use the matrix as the contract, within-language redirect maps from its cells, rebuild parity from its rows, and hreflang regenerated from it so reciprocity holds by construction. Verify at launch per cell and per row, never sampling just the primary language, and monitor Search Console per language section after. That matrix-driven sequence is how WPBuildAI runs multilingual rebuilds, because relationships recorded as data are relationships the launch check can prove.
What is hreflang and why does it break during migrations?
hreflang annotations tell engines which URL serves which language and region for the same content, and the specification requires reciprocity, each page naming its alternates and being named back. Migrations break it structurally: URLs change per language on different days, hand-maintained annotations lag, and half-updated pairs lose reciprocity, so engines stop trusting the mapping and serve wrong-language results even though every page loads. The durable fix is generation: emit the annotations from the same translation matrix that drove the rebuild, and reciprocity survives because the generator enforces it.
Should old pages redirect to the new page in the same language or the main language?
Same language, always: an old German URL 301s to the new German URL, and where German lost that page, to German’s closest equivalent or section root, decided explicitly in the matrix. Cross-language redirects read as irrelevant destinations to engines, near soft-404s, and as hostility to the users who bookmarked the page, and they teach engines to distrust exactly the language mapping the migration needs to preserve. The corollary: partial translations need a per-row policy before launch, because the silent default, falling through to another language, is the same mistake automated.
Do I need to keep every language when I migrate?
No, and the migration is the honest moment to decide: the matrix shows each language’s real page counts and gaps, analytics shows what each earns, and every carried language is permanent per-page maintenance on the new site. Keep the languages with genuine traffic and business purpose, prune thin machine-translated sections that were plugin output rather than content, and retire unearning languages cleanly, redirecting their URLs to the strongest surviving equivalent with the change recorded. Carrying four languages badly serves international users worse than carrying two languages well.
When should you not modernize the language URL structure during the move?
When the migration is already at its risk budget: changing platform, design, and the language scheme in one launch stacks three re-evaluations, and on a large site with heavy international equity, keeping the existing scheme, even a dated one, removes an entire class of redirect complexity from the riskiest week. Modernize in a second, smaller move once the platform migration has settled, with its own matrix and its own verification. The exception is genuinely broken schemes, parameters engines index inconsistently, where staying costs more than the change; there, budget the multiplied redirect map honestly rather than discovering it mid-launch.