Skip to content
BetaDocs

WordPress Migration

The migration workflow and helper plugin are included in the open-source Typeroll distribution. Typeroll Cloud also offers migration as an operated, supported service.

The import itself is a deterministic workflow with no AI rewriting. Plan, map, review and fix a migration with your own AI agent (Claude Code, Codex or another MCP client) through MCP. The built-in AI assistant in the portal has no migration tools.

Start with Choose your migration approach: choose preserve or renew for text and design/images independently. Every combination uses standard blocks first, custom block types when needed and rare documented HTML exceptions. Every old public URL must keep working or redirect to relevant content.

Copy this prompt and replace [website URL] with your current website:

Help me migrate [website URL] to Typeroll CMS using https://github.com/Typeroll/site-starter. Read its AGENTS.md and guide me through the migration interview before starting work.

The agent helps you set up your own workspace and follows the starter’s interview. You choose separately whether to preserve or renew the text and the design/images. The detailed prompts, decisions and routines stay in your workspace, ready for future sessions. If your agent cannot read GitHub, use the workspace setup guide to provide the files. Connect Typeroll MCP and confirm the target Site and Version before making changes; verified Organization storage is required before importing.

The shared-taxonomy and fidelity-review changes described below require Core 0.2.5 and Helper 0.3.2. Cloud availability follows its Core rollout; self-hosted installations must update Core and the helper plugin.

Core 0.2.88 preserves publication/update instants from WordPress REST’s date_gmt and modified_gmt, adding Z when those UTC fields omit it. Helper 0.3.3 explicitly labels its GMT dates with Z; Core also understands earlier Helper exports. A local timestamp without a known timezone cannot establish an instant: only its calendar date is retained when no valid GMT field is available. Existing imports are not overwritten. Repair their dates from the original GMT fields or another timestamp with an explicit offset, then publish; do not append Z to an old local clock value. See publication dates.

The migration workflow imports accessible WordPress content (pages, posts and supported custom post types) into a new Typeroll site, transfers your media directly to your organization’s Cloudflare R2 storage, and generates redirects from old URLs to new slugs.

What it does:

  • Imports pages and posts as Typeroll pages
  • Transfers media (images) through the media API — only images actually used on imported pages
  • Maps custom post types to Typeroll content types
  • Generates URL redirects
  • Imports categories and tags once as Pages with their own Content types; articles store references
  • Preserves cleaned HTML without automatic AI rewriting or HTML-to-blocks conversion
  • Leaves imported content in Review before going live

What it doesn’t do:

  • Import your old WordPress theme or CSS (you build a new design in Typeroll)
  • Import plugins or plugin-specific data that isn’t content
  • Touch the source WordPress site in any way
  1. Build the target site’s design

    Record the text decision separately from the design/image decision. Preserve wording when requested even when deliberately redesigning. Import does not automatically reproduce a WordPress theme. Configure shared presentation separately:

    • Colour palette and fonts (update_site_settings)
    • Header partial with navigation
    • Footer partial
    • Reusable article and archive Page templates, plus a home page
    • Source screenshots at desktop and mobile widths for comparison
  2. Check that the WP REST API is accessible

    The migration needs https://yoursite.com/wp-json/wp/v2/ to be publicly accessible. Test it in your browser — you should see a JSON response.

    If the REST API is disabled or restricted, install the helper plugin which provides a separate authenticated export endpoint. Your administrator must allow access to that endpoint.

  3. Optional: install the helper plugin

    The helper plugin gives the AI agent access to custom post types, ACF fields and navigation menus that may not be exposed via the standard REST API.

The workspace starter owns the detailed migration prompts and routines. Open workflows/migration.md there; if you want guidance, the agent starts or resumes workflows/interview.md and saves progress in brief/interview.md. The interview asks about text and design/images separately. For example, retaining all text while refreshing the design is a supported choice.

Record both choices, source URLs, target Site/Version and exceptions in brief/migration.md, with owner rules and SEO strategy in their own brief files. Configure any WordPress Helper key through the agent’s secure credential mechanism, never in the prompt or repository. Documentation provides the short starting pointer; detailed prompts remain in the starter so you can adapt them in your own repository.

The AI agent will:

  1. Call get_import_readiness and resolve any storage requirements, then verify the WP REST API connection
  2. Build an inventory of all URLs on the site
  3. Import shared categories and tags, including archive URLs, hierarchy and available custom fields
  4. Import pages and posts with taxonomy references and cleaned HTML, transferring referenced images along the way; custom post types become Content types
  5. Rebuild the imported material as editable blocks and shared templates, after verifying representative prototypes
  6. Generate redirects and show coverage, reconstruction and review results separately

The portal can also run the migration on the server: New site → Migrate from WordPress creates a Site and starts it, and an existing Site runs it from Workflows. The same workflow is available to agents and scripts. With an organization API key, create_site_and_migrate (POST /api/v1/sites/create-and-migrate) creates the Site and starts the run; start_workflow with type: "migration" runs it on an existing Site (write permission). Poll get_workflow and approve its review step with approve_workflow once you have checked it. Own storage must be verified first in both the portal and the API. See Organization, access and workflow tools.

The workflow reads only the source site, and the source must be reachable on the public internet. The WordPress URL and every redirect it follows must resolve to public addresses; private, loopback and link-local addresses are refused. A self-hosted server can import an intranet WordPress by setting TYPEROLL_ALLOW_PRIVATE_NETWORK_FETCH=1; see Self-hosting. When an item’s REST body is nearly empty, the importer renders its page only if the item’s link belongs to the source site (same host, ignoring www.). Other links are logged and not fetched.

Password-protected posts and pages are not imported. WordPress omits their content, so importing them would publish an empty page or the password form. The workflow logs each one and lists it under protected_skipped in the import step’s result. Recreate the content deliberately or redirect its old URL before launch.

After the content is imported, the AI agent shows a coverage report:

Migration complete. Here's the coverage:
✅ 24 pages migrated
↪ 8 redirects created
⬜ 12 URLs excluded (pagination, feeds, admin)
⚠️ 3 URLs unhandled:
/category/projekt → needs a redirect or category page
/tag/stockholm → needs its tag Page and membership listing
/wp-content/uploads/2019/hero.pdf → file, needs manual handling

For each unhandled URL, decide: add a redirect, create a page, or exclude it. Category and tag archives are content; do not routinely discard them.

Each WordPress taxonomy becomes a Content type such as wp_taxonomy_category. A category is a Page whose title is the category name; its custom fields can hold an icon or emoji. Articles have a page_ref_list field pointing to those Pages. Edit the category once in Pages, filtered by its Content type. On an article, select category references instead of editing copied names or icons. Archive listings use reverse references so membership stays consistent.

Tag Pages work the same way: an article can reference several tags, and each tag Page lists the articles referencing it. Category and tag Pages have editable block bodies, so you can add a unique introduction, images and other content alongside the generated listing. They can also use shared Page templates.

A Page has one parent in the site tree, even when it has several categories or tags. That parent supplies breadcrumb ancestry. URLs are separate: the Content type’s route template or a Page’s explicit path determines its address. Migration preserves the old paths; nesting an article under a category must not silently change its URL. Tags do not change an article’s parent or address.

The importer preserves term parents, archive URLs, page parents and manual order. An explicit primary category from the helper plugin is used for breadcrumbs; a single assigned category can also be used. With multiple categories and no primary choice, review the breadcrumb hierarchy instead of guessing a category.

Retries use stable source IDs and preserve existing imported Pages, including subsequent edits. They do not refresh existing content from WordPress. A different Page at an imported URL, missing term, or incompatible schema stops the import with an error. Resolve the mapping before retrying. Older flattened imports need a separately reviewed repair; rerunning the importer does not rewrite them.

Compare a representative article sample, an archive and the home page against the source on desktop and mobile. Check heading sizes, text width, spacing, images, cards, breadcrumbs, table of contents and responsive behavior. Keep the table of contents as a generated block in a Page template, never a copied field on each article. Test forms and Extensions separately; a rendered shell does not prove that the integration works.

HTML is the managed importer’s intermediate format, not the intended final result of a block-based migration. Your external AI agent reads that content and rebuilds it with the ordinary MCP/API block and template tools. You do not need to convert every Page manually in the editor. An agent can also create block Pages directly from the WordPress source, without staging an HTML Page first.

Typeroll has no automatic HTML-to-blocks converter. The old editor conversion preview was removed in Core 0.2.58. Switching a Page to block mode does not convert its HTML; on a newly imported Page there are no blocks to display yet. The agent must preserve the complete source, build the block tree, save and read it back, and review the result before publication. Work on the selected Version and keep incomplete Pages out of publication. A reviewed prototype establishes the reusable mapping before the agent applies it to the remaining Pages.

Conversion notes are included in the workflow review. Use an HTML block only for an uncommon source-specific exception; recurring requirements belong in reusable blocks or templates. Missing native features must be resolved before converting the remaining pages. Source styles and interactive scripts are not ported automatically.

JavaScript from the WordPress site is not copied. Plugins and themes add their own scripts, such as jQuery, sliders, form and cookie plugins, page builders and calls to admin-ajax.php. On the new site they would load from, or send data to, the old site. What they did is rebuilt with blocks, Forms and site settings, or reported as a missing feature.

Analytics and advertising tags are the exception. They are carried over by ID, not as pasted code:

  1. Open Settings → Apps → Integrations and enter the IDs the old site used, for example the Google Analytics 4 measurement ID or the Meta Pixel ID.
  2. In Settings, turn on Enable cookie consent on this site, with your own text and a link to the privacy policy. Analytics and advertising tags then wait until the visitor accepts. The old site’s cookie plugin is not copied.
  3. A tag that the Integrations list doesn’t cover goes in the cookie banner’s optional scripts, never in the site-wide head or body scripts.

The launch report (get_migration_launch_report) is not ready to launch while the site carries scripts from the old platform, tracking code outside the consent gate, or analytics and advertising integrations with the cookie banner off. Its scripts section lists each finding and where it is.

The launch report requires current URL/SEO evidence and recorded fidelity review. Use record_migration_seo_acceptance with fidelity.desktop, mobile, shared_data and integrations plus an evidence description. These are review results, not automated screenshot tests. A successful HTTP request alone does not show that the migration is correct.

Sites imported with an older Typeroll version may have WordPress entities or markup left in titles and SEO text. Ask the AI agent to run repair_migration_plain_text as a dry run and show every proposed change. The repair is restricted to plain-text fields and leaves bodies, slugs, paths, and URLs alone. Approve the write only after reviewing the returned diffs; records with existing working copies are skipped rather than overwritten.

All imported pages start as status: "review". When you’re satisfied:

Publish all the imported pages and deploy.

Or review page by page and publish individually.

The Typeroll Helper Plugin gives the migration workflow access to:

  • Custom post types with show_in_rest: false
  • ACF fields with image references normalised
  • Navigation menus
  • Builder JSON (Elementor, Breakdance)
  • Complete canonical URL list
  • Shared taxonomy terms, archive URLs, parents, term custom fields and primary categories

Installing:

  1. Download the wp-helper-plugin directory from the Typeroll repository and create a ZIP archive from it.
  2. In WordPress: Plugins → Add New → Upload Plugin
  3. Activate the plugin
  4. Go to Settings → Typeroll Helper and generate an API key
  5. Give the agent the site URL and configure the key through its secure credential mechanism. Keep the key out of shared prompts and documentation.

Helper 0.4.0 and later accept the key only in the X-Typeroll-Key request header, never as a ?key= URL parameter. The plugin exports published items of public post types only; orders, coupons, form submissions and other non-public plugin data are never exposed. Password-protected posts are listed with their title and URL but without content or custom fields; the importer skips them (see Server-side migration workflow). Deleting the plugin in WordPress removes its stored key.

Image transfers use a persistent lookup for each source URL, so repeated imports reuse verified media. Transfers overlap within limits for memory and each source host; temporary throttling slows requests down. A failed required file stops content import with an error; retry after resolving source or storage access. Verified files already transferred are reused. Keep the WordPress source available until all required media and references are verified.

With Core 0.1.93 and an updated shared build engine, imported originals also queue private background image preparation. Media shows progress. The Organization’s selected build provider performs encoding; the CMS does not publish draft images. See large libraries and first publication for setup, limits and recovery.

With Core 0.1.97, Typeroll sets up a small transfer Worker in your organization’s connected Cloudflare account. It downloads originals from WordPress directly into your private R2 bucket and verifies the copied bytes before Typeroll updates references. File bodies do not pass through the Typeroll Cloud portal or the MCP server. This is independent of whether GitHub or Cloudflare builds your site.

The Media storage card shows transfer setup status. If an existing Cloudflare connection needs an additional permission, select Allow media transfers in Cloudflare, approve, and return. Your R2 keys remain in place. Advanced token connections need Workers Scripts: Edit as well as the documented R2 access.

Progress is saved per source file. Interrupted copies retain their media identity and can be retried from Publishing without duplicating completed imports. Typeroll preserves source URLs until verified copies are ready. Keep the source site available until the import and reference checks finish. Originals can be up to 25 MB each; responsive variants are prepared separately by the selected build provider.

The same storage prerequisite applies to self-hosted installations using these import tools. Configuring the operator’s draft bucket does not satisfy it: connect the organization’s own storage in Publishing.

Verify the design before importing in bulk

Section titled “Verify the design before importing in bulk”

Ask the agent to read the shared tr-migration-evidence skill before applying one template to many Pages. It starts with the original site’s fonts, colors, header, hero, card grids and article/sidebar geometry. A partially migrated Typeroll site is not the authoritative design reference. Use the source for preserved design; use approved prototypes for renewed design. Review text separately against its own preserve/renew choice; ask when either choice is missing before dependent writes.

First verify one saved prototype for each active layout: home, archive, long and short articles, downloads and any special template overrides. Compare matching viewports and screenshots, including lower-page content, mobile menus, scrolled contents lists, anchor landings and long links. Read saved block fields back and measure the output; a field that is stored but ignored is not working support. Missing native capability must be reported before bulk conversion.

The evidence record identifies source and target URLs, publication, actual screen width, screenshot state, expected/actual measurements, reviewer and intentional changes. Keep PASS, FAIL and UNVERIFIED separate for routing, visual quality, content, files and interactions. HTTP 200, all-native blocks and no horizontal scrolling do not prove visual fidelity. Responsive video that fixes source overflow is a useful deliberate change; losing a brand panel or changing a four-card grid without a reason is a regression. Updated templates or themes require a fresh comparison. Fidelity checkboxes record review, not automated screenshot analysis.

Check PDF/download links and historical image URLs separately from successful file transfer. Use redirects only for relevant, reviewed destination mappings; a source 404 is not permission to discard a URL. Classify contact forms, lead flows, affiliate links and partner embeds separately for each market. Test conversions only with authorized synthetic data and safe recipients. Delivery that cannot be tested remains unverified. Import completion, verified preview, publication and domain cutover are distinct milestones.

Visual coverage is separate from publication

Section titled “Visual coverage is separate from publication”

Before conversion, inventory all source routes and whole-page regions, including archive pagination, headers, footers and heroes outside the article’s main. Compare every in-scope route at mobile and desktop, then check each distinct component and state at its actual breakpoints. An open menu, unique embed or footer omitted from the comparison remains unverified.

Keep source/target screenshots, content and template revisions, the reviewer and separate results for appearance, content, link membership, link order, keyboard behavior and delivery. Shared template or theme changes invalidate dependent comparisons. Technical publication success does not constitute visual approval. Intentional changes need explicit before/after evidence and an accepted benefit. The agent skill tr-migration-evidence is the shared contract for WordPress, URL, Astro and multisite work; its coverage starts unverified and requires no uncovered surfaces or unexplained regressions before visual signoff.

Preserve media positions when converting HTML

Section titled “Preserve media positions when converting HTML”

Import does not turn that HTML into blocks. The agent must preserve media order while reconstructing the content with block tools; changing the Page mode is not a conversion.

Work from the raw source and keep the original response for QA. Parsing and serializing malformed WordPress markup before reconstruction can move images across heading boundaries. Inspect the browser’s actual source layout as well as the markup. Restore lazy images before deciding that media is missing.

Rebuild image-only heading wrappers as native image blocks in their original body position, rather than empty headings or image entries in the generated table of contents. Preserve meaningful heading IDs and avoid duplicating noscript image fallbacks. These are checks the agent must perform, not automatic conversion features.

Compare the ordered sequence of headings, text, media and CTAs, not just counts or image presence. Include malformed heading wrappers, lazy images, related-content boundaries and images after several sections. For an already migrated site, repair affected block positions against the raw source and review the generated page; do not reimport over subsequent edits.

An address/area banner that continues to a quote page is separate from the final submission integration. Migrate its inputs and service links even if the final provider is deferred. Navigation inputs and tabs can carry explicitly accepted defaults within the same browser tab and origin, without adding addresses to URLs or creating a submission. Test collapsed/open mobile states, switching services, keyboard navigation and storage denial.

Also compare cards with missing thumbnails and the footer’s actual link-row spacing. Configure shared card placeholders and compact navigation settings; do not add fake featured images or shrink text to compensate for a tall link box. Verify a mixed row of real and missing thumbnails, wrapped footer links, and both preview and static output.

Preserve originals before retiring WordPress

Section titled “Preserve originals before retiring WordPress”

The starter’s workflows/source-media.md separates unused-source archiving from CMS import. Inventory drafts, old attachments and print originals as well as published-page references. Agree a private destination, verify copied bytes and a restore, and retain a manifest before approving old-host retirement. An object ETag is not universally an MD5 checksum. Archiving does not preserve public URLs; verify those independently through the migration inventory.

From MCP 0.45.80, scripts/typeroll/prepare_image.py provides optional local ICC-aware conversion to sRGB JPEG (Pillow/ImageCms required). It keeps the original untouched and does not upload or edit content. Missing CMYK profiles must be resolved instead of guessed; transparent or multi-page sources require a reviewed separate workflow. Compare colour and framing visually before using the derivative. Keep source files and reports in the starter’s ignored private folders. See the generated script README for commands and limits.