Skip to main content

Importing content into WordPress with Blueprints

A new WordPress Playground site starts with basic content. A Blueprint can help fill that gap from a WordPress export file, generate content with WordPress APIs, or restore a Playground ZIP snapshot.

This guide focuses on choosing a Blueprint content import method and presents a small benchmark comparing three approaches. Importing data can be useful for theme starter content, test fixtures, educational content, and other demo-building strategies. For more options, see Providing content for your demo with Playground.

These approaches solve different problems:

MethodBest forWhat it moves
importWxrPortable content shared between WordPress sites without overwriting existing contentPosts, pages, custom post types, terms, authors, comments, and attachment references
runPHPSmall, deterministic fixtures and content that needs custom logicAnything the PHP code creates through WordPress APIs
importWordPressFilesRestoring a complete Playground demoThe database and any WordPress files present in the ZIP, such as plugins, themes, and uploads

If you only need posts and terms, start with WXR. If the content is generated or depends on setup logic, use runPHP. If the database, media, plugins, themes, and settings must be restored together, use a ZIP snapshot.

Import a WordPress XML export with importWxr

WordPress calls its XML export format WordPress eXtended RSS, or WXR. Create one from Tools > Export in an existing WordPress site, then pass it to the importWxr step.

This example expects content.xml next to blueprint.json in a Blueprint bundle:

{
"$schema": "https://playground.wordpress.net/blueprint-schema.json",
"landingPage": "/wp-admin/edit.php",
"preferredVersions": {
"php": "8.3",
"wp": "latest"
},
"login": true,
"steps": [
{
"step": "importWxr",
"file": {
"resource": "bundled",
"path": "/content.xml"
},
"fetchAttachments": false,
"rewriteUrls": true,
"importComments": false,
"authorsMode": "default-author",
"defaultAuthorUsername": "admin"
}
]
}

For a hosted file, replace the bundled resource with a url resource. Set fetchAttachments to true when the importer must download the media files referenced by the WXR file. Network transfer can dominate the total setup time, so the benchmark later in this guide disables attachment fetching.

importWxr can also map imported authors to local users, create users, and apply explicit URL replacements. See the importWxr options before importing content from another domain.

Pros

  • Uses WordPress's standard, portable content exchange format.
  • Preserves post types, taxonomies, post meta, authors, comments, and content relationships represented in the export.
  • Can fetch attachments and rewrite old content URLs for the new site.
  • Keeps content separate from the destination's WordPress core, plugins, themes, and most site settings.
  • Is easy to inspect, version, and edit manually in any text editor because the source is XML.

Cons

  • Does not clone the whole site. Plugins, themes, plugin tables, options, and files that are not represented in WXR need separate Blueprint steps.
  • Attachment imports require network access and depend on the old media URLs remaining available.
  • Large XML files use more parsing time and memory than restoring an existing SQLite database.
  • Re-importing is additive, not a synchronization. The importer creates terms it cannot find and never removes existing content; it only skips a post when an existing one matches its title, author, and date.
  • The Blueprint installs the WordPress Importer dependency automatically, which adds setup work before the WXR import starts.

Generate content with runPHP

The runPHP step can call WordPress APIs directly. Always load /wordpress/wp-load.php before calling functions such as wp_insert_post().

The following example creates the 100 posts used by the benchmark:

{
"$schema": "https://playground.wordpress.net/blueprint-schema.json",
"landingPage": "/wp-admin/edit.php",
"preferredVersions": {
"php": "8.3",
"wp": "latest"
},
"login": true,
"steps": [
{
"step": "runPHP",
"code": "<?php\nrequire_once '/wordpress/wp-load.php';\n\nfor ( $index = 1; $index <= 100; $index++ ) {\n\t$result = wp_insert_post(\n\t\tarray(\n\t\t\t'post_title' => 'Benchmark post ' . $index,\n\t\t\t'post_content' => '<!-- wp:paragraph --><p>Blueprint import benchmark content.</p><!-- /wp:paragraph -->',\n\t\t\t'post_status' => 'publish',\n\t\t\t'post_type' => 'post',\n\t\t),\n\t\ttrue\n\t);\n\tif ( is_wp_error( $result ) ) {\n\t\tthrow new RuntimeException( $result->get_error_message() );\n\t}\n}"
}
]
}

For larger programs, keep the code in a small plugin or split the setup across focused steps instead of maintaining a very long JSON string. Use WordPress APIs rather than writing directly to database tables so hooks, caches, and data validation still run. Keep in mind that the code is not limited to content: runPHP can do anything PHP can, including overwriting options or modifying the database directly.

Pros

  • Provides complete control over the generated data and its relationships.
  • Requires no content file and no network access.
  • Can configure options, post meta, users, taxonomies, and plugin-specific data in the same operation.
  • Works well for small test fixtures whose source of truth should remain code.
  • Can be made idempotent by looking up existing records before creating them.

Cons

  • A Blueprint is trusted input. Only run PHP from a source you trust.
  • The script must handle errors, reruns, dependencies, and partial failures.
  • Code can become coupled to a plugin's APIs or database model.
  • Creating many records one at a time still runs WordPress hooks and database writes for every record, so performance degrades as the dataset grows.
  • Custom PHP is more verbose than exporting existing editorial content.

Restore a Playground ZIP with importWordPressFiles

The importWordPressFiles step is a site restore, not a content-only import. It unpacks top-level WordPress files from a ZIP and replaces the corresponding paths in the new instance. A ZIP created with Playground's Download as zip option includes wp-content, its SQLite database, uploads, and a manifest used to adjust Playground scope URLs.

Place the downloaded file next to blueprint.json and reference it as a bundled resource:

{
"$schema": "https://playground.wordpress.net/blueprint-schema.json",
"landingPage": "/",
"preferredVersions": {
"php": "8.3",
"wp": "latest"
},
"login": true,
"steps": [
{
"step": "importWordPressFiles",
"wordPressFilesZip": {
"resource": "bundled",
"path": "/site.zip"
}
}
]
}

The ZIP may contain wp-content only, a complete WordPress directory, or a WordPress directory nested inside a wrapper folder. Use pathInZip when the archive contains several sites or when automatic root detection is not enough.

Keep the source and destination WordPress, PHP, theme, and plugin versions compatible. The step upgrades the imported database and adjusts Playground scope URLs, but it is not a general migration tool for arbitrary production server configurations.

Pros

  • Restores the database, uploads, plugins, themes, and settings together.
  • Preserves plugin-specific tables and options that WXR cannot represent.
  • Avoids recreating every post through WordPress APIs, which can be efficient for a prepared, repeatable demo.
  • Works offline when the snapshot is bundled with the Blueprint.
  • Produces the closest copy of the source Playground instance.

Cons

  • Replaces any top-level paths present in the ZIP, so it can overwrite existing site state rather than merge content into it.
  • Is larger, opaque, and harder to review or resolve in version-control merges.
  • Couples the snapshot to its WordPress, PHP, theme, plugin, and database versions more tightly than WXR.
  • Is unsuitable for importing selected posts into an existing site.
  • Must only be restored from a trusted source; it can contain executable PHP and an entire database.

Test results for the different methods

The following test results were measured on July 13, 2026, on an Apple M4 Pro with 24 GB of memory. It used Node.js 22.16, WordPress 7.0, PHP 8.3, 100 posts, and five fresh-site rounds per method:

MethodInput sizeMedianMinimumMaximumRelative to fastest
XML / importWxr106.0 KiB2.21 s2.16 s2.25 s6.90x
PHP / runPHPGenerated code2.78 s2.76 s2.80 s8.68x
ZIP / importWordPressFiles50.5 KiB320 ms318 ms322 ms1.00x

Treat these values as a reference from one machine, not a universal ranking. The dataset shape matters: attachments favor a self-contained ZIP, complex WordPress hooks can slow runPHP, and WXR's portability may be more important than raw speed.

Other content sources

Blueprints also support importThemeStarterContent for a theme's registered starter content and the wp-cli step for commands such as wp post generate. They are useful when the theme or WP-CLI command is already the canonical source of the demo data, but they are outside this content import benchmark.