Supported fields
Every field a column can be mapped to, and exactly what the importer accepts in it.
Header names in the "Recognised headers" column are what the auto-mapper looks for. Matching ignores case, spaces, underscores and hyphens, so Post Title, post_title, POST-TITLE and posttitle are all the same header.
Post fields
| Field | Recognised headers | Accepts | Notes |
|---|---|---|---|
| Post ID | id, post_id | Integer | Used only to match an existing post. A row never creates a post with a chosen ID. If the ID does not exist, or belongs to a different post type, the row is treated as unmatched. |
| Title | title, post_title, name, headline, subject | Any text | Stored as-is. HTML in a title is escaped by WordPress on output. |
| Content | content, post_content, body, description, text | Any text, including HTML and shortcodes | Stored verbatim. Shortcodes are not executed at import time; they render normally on the front end. Block markup (<!-- wp:paragraph -->) is preserved. |
| Excerpt | excerpt, post_excerpt, summary, teaser | Any text | |
| Slug | slug, post_name, permalink | Text | Sanitised into a URL slug by WordPress. If two rows produce the same slug, WordPress appends -2, -3 and so on. |
| Status | status, post_status, state | See below | Defaults to publish on creation when the column is absent or empty. |
| Date | date, post_date, published, created_at | See below | Sets both the local and GMT date. When absent, WordPress uses the current time. |
| Author | author, post_author, user, creator | User ID, login, email, or nicename | Tried in that order. An unmatched author falls back to the user who started the import, and the preview warns first. |
| Parent | parent, post_parent, parent_id | Post ID or slug | Only offered for hierarchical post types. The parent must already exist and be the same post type. Unmatched parents import at the top level with a warning. |
| Menu order | menu_order, order, sort, position | Integer | Only offered for hierarchical post types. Non-numeric values become 0. |
| Password | password, post_password | Text | A non-empty value makes the post password protected. |
| Comment status | comments, comment_status | Boolean-ish | open, 1, yes, true, on, enabled mean open. Anything else means closed. |
| Ping status | pings, ping_status, trackbacks | Boolean-ish | Same rules as comment status. |
Status values
Registered status slugs are accepted directly: publish, draft, pending, private, future, trash, plus any status another plugin has registered.
These synonyms are also accepted:
| You write | You get |
|---|---|
published, public, live, 1, yes, true | publish |
unpublished, 0, no, false | draft |
scheduled | future |
trashed, deleted | trash |
A status label is also accepted, so an export that wrote "Pending Review" resolves correctly.
Anything unrecognised produces a warning and the row falls back to the default status rather than failing.
Date formats
With the date format left on Detect automatically, the importer tries in this order:
| Input | Interpreted as |
|---|---|
1719792000 (9–11 digits) | Unix timestamp, seconds |
1719792000000 (12–14 digits) | Unix timestamp, milliseconds |
2024-07-01, 2024-07-01 14:30:00, 2024-07-01T14:30:00+02:00 | ISO 8601 |
25/07/2024 (first part > 12) | Day/month/year |
07/25/2024 (second part > 12) | Month/day/year |
03/04/2024 (ambiguous) | Month/day/year, with a warning |
3 March 2024, March 3, 2024, Mon, 03 Mar 2024 10:00:00 +0000 | Free text, via PHP's date parser |
Ambiguous numeric dates are the one case worth attention. If your file came from a European system, add the Parse date transform to the column and set the source format to European / DD/MM/YYYY. That removes the guess entirely.
Dates are interpreted in your site's timezone, not the server's, and stored as both local and GMT. An unparseable date produces a warning and the row imports with the current date. It does not fail.
Taxonomies
Every taxonomy registered for the chosen post type is offered, including custom ones.
The auto-mapper recognises the taxonomy slug, its plural label and its singular label, so a column named Categories, category or cat all map to the built-in category taxonomy, and Tags or tag map to post tags.
Multiple terms are separated by commas:
News, Product updates, Company
A term containing a comma must be quoted, exactly as anywhere else in a CSV:
"Reports, quarterly", News
Hierarchical paths use >:
Fiction > Crime > Nordic
That assigns the row to Nordic, creating Fiction, Crime and Nordic in that nesting if they do not exist. In a flat taxonomy such as post tags, > is not a separator — the whole string becomes one term name.
Two settings govern the behaviour, both on the mapping step:
- Existing terms on an updated post: Replace swaps the post's terms in that taxonomy for the ones in the file. Keep them and add the new ones appends. Replace is the default because it is what makes a re-import idempotent.
- Create terms that do not exist yet: on by default. Turn it off and a missing term is skipped with a warning instead, which is useful when your taxonomy is curated and typos in the CSV should not become terms.
The preview marks every term that does not exist yet, so you see what a run will add to your taxonomy before it adds it.
Custom fields
Map any column to Custom field (meta key)… and type the key. Keys are restricted to letters, numbers, underscores and hyphens.
Values are stored as strings under that key with update_post_meta, replacing any existing value for the key. Serialised arrays are not built from a CSV cell — a cell is one value.
- Protected keys. A key beginning with an underscore is accepted, because plugins legitimately store data that way and importing it is sometimes exactly what you want. WordPress hides these from the custom fields box in the editor. Only use one if you know what reads it.
- Clearing a value. Set the column's empty-cell behaviour to Set empty and a blank cell deletes the key entirely rather than storing an empty string.
- Headers with a prefix. A header written as
meta:sku,meta_sku,cf:skuorcustom_field_skuis auto-mapped to the custom fieldskuwithout you doing anything. Likewisetax:genremaps to thegenretaxonomy.
Fields belonging to Advanced Custom Fields are not mapped this way. ACF stores a second row beside every value saying which field owns it, so a value written as a plain custom field is one the field cannot see — they get their own heading on the mapping screen and their own handling. The ACF reference →
Featured image
| Field | Recognised headers | Accepts |
|---|---|---|
| Featured image URL | image, image_url, featured_image, thumbnail, photo | Absolute http/https URL, protocol-relative //host/path, or root-relative /path |
| Featured image alt text | alt, alt_text, image_alt | Any text |
Behaviour:
- The image is downloaded to your media library and set as the post's featured image.
- The same URL is only ever downloaded once. The attachment records the URL it came from; a second row, or a second import, with the same URL reuses the existing attachment. This is what makes re-importing an unchanged file cheap.
- A URL that already points at your own media library is recognised and not downloaded at all.
- A failed image never fails the row. The post is saved; the failure is recorded as a warning on that row with the reason.
- The per-image timeout is set on the mapping step, defaulting to 10 seconds, so a single dead host cannot stall an import.
- Alt text is stored as
_wp_attachment_image_alton the attachment.
If a filename in the URL has no extension, the type is derived from the downloaded file itself.
Rows the importer handles rather than rejects
| Situation | What happens |
|---|---|
| Row has fewer columns than the header | Missing columns are treated as empty, with a warning |
| Row has more columns than the header | Surplus values are kept under generated names and left unmapped, with a warning |
| Row is blank | Skipped silently, not counted |
| File has no header row | Columns are named column_1, column_2… and every row is data. Detected automatically, overridable |
| Header cell is blank | That column is named column_N, with a notice |
| Two header cells have the same name | The second becomes name_2, the third name_3 |
| File is UTF-8 with a byte order mark | The mark is stripped, not imported into the first column name |
| File is Windows-1252 | Transcoded to UTF-8 as it is read |
| File contains only a header row | Accepted, with a notice that there is nothing to import |
Field limits
The importer does not impose its own length limits. WordPress's database schema does: post_title, post_name and post_excerpt are TEXT columns, and post_name is truncated to 200 characters when the slug is generated. Content length is limited only by your MySQL max_allowed_packet.