Going headless from WordPress is one of the most common moves we're asked about, and one of the most often rushed. The risk isn't the export; it's ending up with your old HTML stuffed into a new CMS. This guide walks through the transform that turns WordPress content into real structured blocks, for Sanity or Payload, and the editor training that makes it stick. For the wider picture of moving between headless platforms, see our headless CMS migration guide.
What does a WordPress to Sanity migration involve?
A WordPress to Sanity migration involves four jobs: designing a content model, transforming WordPress HTML into structured blocks, rebuilding the front end, and protecting your URLs. WordPress renders pages on its own server; Sanity or Payload only store content, so a Next.js front end has to be built to display it.
That last point surprises people. Leaving WordPress for a headless CMS is not a content move alone; it's a new website build plus a content move. If you're new to the idea, our explainer on what a headless CMS is covers the basics without jargon. Typical ranges we see quoted for WordPress to headless Next.js projects run from about £13,000 to £30,000 over 6 to 12 weeks, and they vary a lot with the size of the site and how messy the content is.
Sanity or Payload?
Both work well as a WordPress replacement. Sanity is hosted and stores rich text as Portable Text. Payload is open source, runs inside your Next.js app and stores rich text as Lexical JSON. The transform steps below are the same for both; only the output format changes. Our comparison of Contentful, Sanity, Payload and Strapi helps you choose.
How do you export WordPress content for a headless CMS?
You export WordPress content either through the REST API, which returns posts, pages, media, categories and users as JSON, or through the Tools, Export screen, which produces a WXR XML file. We prefer the REST API because it gives typed fields, IDs and links, and it can include custom post types and custom fields when they're exposed.
Method | Best for | Limitations |
|---|---|---|
REST API (wp-json) | Most sites; scripted, repeatable exports | Custom fields must be exposed to the API |
WXR XML export | Locked-down hosts, quick snapshots | Messy XML; media is referenced, not included |
Direct database dump | Very large or heavily customised sites | Needs a developer; raw serialized data |
Migration plugins | Simple blogs | Output often still unstructured HTML |
Whichever you choose, pull SEO metadata too. If you use an SEO plugin, titles and descriptions live in its own fields, not the post title. Our guide on how to export a WordPress site's content covers each method, including media and custom fields.
How do you turn Gutenberg HTML into structured blocks?
You turn Gutenberg HTML into structured blocks by parsing the block comment markers WordPress saves around each block, then mapping each block type to a block in your new schema. Gutenberg saves a paragraph as HTML wrapped in a wp:paragraph comment, an image as wp:image with its attachment ID, and so on, which gives a script something reliable to read.
Gutenberg block | Sanity (Portable Text) | Payload (Lexical) |
|---|---|---|
wp:paragraph | block, style normal | paragraph node |
wp:heading | block, style h2 to h4 | heading node |
wp:list | blocks with listItem | list and listitem nodes |
wp:image | image object with asset reference | upload node to a media doc |
wp:quote | block, style blockquote | quote node |
wp:embed (YouTube etc.) | custom embed object | custom block |
wp:html or shortcodes | manual review | manual review |
For the HTML inside each block, Sanity's block tools package can convert HTML into Portable Text, and Payload's Lexical package includes an HTML-to-Lexical converter. Classic-editor posts, written before Gutenberg, have no block markers, so they go straight through the HTML converter with stricter clean-up rules.
Hypothetical example: a post with a shortcode and an inline style
For example, suppose a 2019 post contains a gallery shortcode, a paragraph with inline color styles and a raw HTML table.
The script strips the inline styles, because the new design system controls color. The gallery shortcode is matched by name and replaced with a gallery block whose images are looked up by attachment ID. The raw HTML table has no clean equivalent, so the script flags the post for manual review and logs its URL. At the end you get a short list of posts a person needs to fix, instead of hundreds of silently broken pages.
What are the steps to migrate WordPress content to Sanity or Payload?
The steps are: audit, model, export, transform, import, rebuild, redirect, then train. Run the transform repeatedly on a copy until the error log is short, and only freeze WordPress for the final import.
Audit the content
Decide what to keep, merge or drop. Old tag archives and thin posts rarely deserve a place in the new CMS.
Design the content model
Define posts, pages, authors, categories and the blocks editors may use. Our content modeling guide shows how to structure collections for a SaaS site.
Export and re-host media
Download every attachment, upload it to the new CMS, and keep a map from WordPress attachment IDs and URLs to new asset IDs.
Transform posts
Parse Gutenberg blocks, convert HTML to structured blocks, swap image URLs for asset references and rewrite internal links.
Import and spot-check
Import in dependency order: authors and categories first. Compare twenty key posts side by side with the live site.
Rebuild the front end
Build the Next.js templates against real imported content, not dummy text.
Map every URL
Export all live URLs, including date-based permalinks and category archives, and redirect each one that changes.
Train editors and cut over
Run the training sessions below, freeze WordPress, do a final import, then switch DNS.
How do you train editors after moving off WordPress?
You train editors with short, task-based sessions on real content, before launch, followed by a written cheat sheet. Editors coming from WordPress are used to a page that looks like the final site; a structured editor feels different, and without training they work around it.
- Session one, the model: what each document type is for, and why there's no free-form HTML box.
- Session two, everyday tasks: write and publish a post, add an image with alt text, add a link to another post.
- Session three, preview and SEO fields: use live preview, fill in the SEO title and description, schedule a post.
- First two weeks: a shared channel for questions, and a review of the first few posts each editor publishes.
If editors keep asking for a feature, that's useful feedback on the model, not a training failure. Adjust the schema early, while there's little content to update.
How do you protect SEO when leaving WordPress?
You protect SEO by keeping URLs where possible, redirecting every URL that changes, and carrying over titles, descriptions and canonical tags exactly. WordPress sites often have date-based permalinks, category paths and attachment pages that are easy to forget, and those are where traffic usually leaks after a move.
Crawl the old site before you start and save the URL list. After the import, crawl the staging site and compare the two: every old URL should return the same page or a single 301 redirect, never a chain or a 404. For a broader process that applies to any platform, see our guide to CMS content migration. If you later decide Sanity isn't right, the same principles apply to a Sanity to Payload migration.
