The Counterintuitive Truth About Moving Custom Post Types From WordPress to EmDash

Discover why migrating custom post types from WordPress to EmDash is a schema translation project, not just a data export.

By Central
The migration requires mapping field types and restructuring data, not just moving bytes.
Highlights
  • WordPress stores custom post type fields as serialized PHP or HTML in post meta, while EmDash uses typed JSON.
  • A WordPress site with 12 custom post types and 8 fields each means 96 field definitions to reconcile.
  • EmDash's content type system is more powerful because it enforces a schema understood by editor, API, and front end.

You can export every post, page, and custom field from WordPress in about 90 seconds. The WXR file lands in your downloads folder. EmDash’s import tool accepts it. The data moves.

That is not the problem. The problem is that WordPress stores content as HTML strings in the database, while EmDash uses portable text — structured JSON with typed blocks and inline metadata. A custom post type in WordPress is a loose collection of meta fields and raw HTML. A content type in EmDash is a defined schema with typed fields, relationships, and machine-readable structure. You are not migrating data. You are migrating the meaning of that data.

You are not migrating data. You are migrating the meaning of that data.

This reframes everything. The technical steps matter less than the conceptual shift. Let’s walk through what that actually means.

What Makes Custom Post Types Different in EmDash

WordPress ships with two content types: posts and pages. Everything else requires a plugin. Advanced Custom Fields (ACF) became the de facto standard for adding fields to custom post types. But ACF stores field values as post meta — key-value pairs in the wp_postmetacodecodecode table, where the value is often a serialized PHP array or HTML blob.

EmDash flips this. Content types are native to the system. You define them in the admin interface or, ideally, as code. Each field has a type — text, image, rich text, relation, repeater — and the data is stored as structured JSON, not as a flat meta table. The editor renders fields based on their declared type, not on a the_content()codecodecode call that dumps everything through a single filter.

The practical difference: a WordPress “project” post type with a client name, project date, description, and gallery link stores all of that in four meta rows plus the post content field. An EmDash “project” content type stores it as a single JSON object where each field is queryable, filterable, and renderable independently.

The WordPress-to-EmDash Migration Path

Step 1: Map Your Content Types

Before you touch the import button, list every custom post type in your WordPress site. Products, staff, events, portfolios, case studies, whatever you built with ACF or Custom Post Type UI.

For each one, decide what its EmDash counterpart looks like. You are not looking for a 1:1 field match. You are looking for a field-type match. WordPress stores a WYSIWYG editor field as HTML. EmDash uses portable text — a block-based JSON format. WordPress stores a date picker as a timestamp string. EmDash stores it as an ISO date string.

This mapping step is where most migrations stall. A WordPress site with 12 custom post types and 8 fields each means 96 field definitions to reconcile. Do the work upfront.

Step 2: Run the WXR Import

Export your WordPress site as a WXR file. Tools → Export → All Content. Upload it to EmDash’s import page under the admin panel. Or install the EmDash WordPress export plugin for a direct connection.

The import handles posts, pages, media, and custom post types. It reads Yoast SEO fields if present and maps them to EmDash’s built-in SEO fields. Custom field data comes through as raw key-value pairs. This is where the structured content gap shows up.

Step 3: Rebuild the Schema

After the import, your custom post types exist in EmDash as content types, but their fields may be flattened. Open each content type in the admin panel — Admin → Content Types → select the type.

Add fields that match what ACF provided. A text field for the client name. A portable text field for the description. An image field for the featured project image. A relation field if the project links to team members.

The critical detail: EmDash allows you to define fields inline, but these definitions live in the database by default. For production sites, define content types as code in the Astro configuration. This keeps your schema version-controlled and deployable alongside your theme.

Step 4: Remap the Content

The imported content still references fields by their WordPress meta keys. You need to tell EmDash which meta key maps to which field. This is manual. There is no automated ACF-to-EmDash field mapper in version 0.1.0.

For each imported entry, open it in the editor. The raw meta fields appear as a section. Drag them into the corresponding structured field, or copy the values and paste them into the correct editor blocks.

This is slow. A site with 200 custom posts and 10 fields each takes hours. But the result is content that the system understands at the field level — not HTML that the front end has to parse.

Handling Complex Content

Repeater Fields

ACF repeater fields store repeating groups of sub-fields. In EmDash, portable text supports nested blocks. A project timeline with dates, titles, and descriptions becomes a block group inside the portable text editor. The migration requires unwinding the serialized repeater data and reconstructing it as blocks.

Relationships

Post-to-post relationships in WordPress are stored as post meta with the related post ID. EmDash supports relation fields, but the import does not auto-link them. After migration, you manually reconnect each relation by selecting the target entry from the relation field picker.

Media Attachments

Featured images and gallery attachments transfer during the WXR import. EmDash stores media in R2 (or local storage on a self-hosted Node.js server). The import preserves the file references. You do not need to re-upload everything.

What Does Not Migrate

The import tool does not transfer plugins, themes, custom functionality, WooCommerce stores, membership systems, or SEO configurations that depend on third-party plugins. Your custom post type content arrives, but anything that relied on a plugin’s rendering logic — a specific ACF field template, a custom taxonomy filter, a front-end display loop — must be rebuilt as EmDash components or themes.

The WXR export also does not include user roles, comment moderation settings, or site configuration. Those are set up fresh in EmDash.

Post-Migration Verification

After the import and field remapping, verify three things:

  1. Field integrity. Open a dozen entries across each content type. Confirm that text fields display text, image fields show the correct media, and portable text blocks render without broken HTML.
  1. URL structure. EmDash allows custom URL patterns per content type. Match them to your WordPress permalink structure if SEO continuity matters. The import does not auto-generate redirects for changed URLs. You configure those manually under the Redirects section.
  1. Front-end rendering. The default Astro theme renders basic blog and page layouts. For custom content types, you write Astro components that read the structured fields and render them. A “project” type with a client name, description, and gallery needs a Project.astrocodecodecode component that pulls data.clientNamecodecodecode, data.descriptioncodecodecode, and data.gallerycodecodecode and outputs them in the desired layout.

The Migration Is a Restructuring

The import tool moves the bytes. It does not move the structure. That is the counterintuitive truth that changes how you plan this work. A WordPress site with 15 custom post types built over 4 years is not a database export problem. It is a schema translation project. Every field that ACF stored as serialized PHP or HTML must be re-expressed as typed JSON.

EmDash’s content type system is more powerful than WordPress’s post type + ACF combination. But that power comes from structure, not from flexibility. You trade the anything-goes meta table for a schema that the editor, the API, and the front end all understand equally. That trade is worth making. Just do not underestimate the work of making it.

Questions answered
  • What makes custom post types different in EmDash compared to WordPress?WordPress stores custom post type fields as key-value pairs in post meta, often serialized PHP or HTML. EmDash uses structured JSON with typed fields, making data queryable and renderable independently.
  • What is the first step in migrating custom post types from WordPress to EmDash?List every custom post type in your WordPress site and map each to an EmDash content type, focusing on field-type matches rather than 1:1 field matches.
Share This Article