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:
| Method | Best for | What it moves |
|---|---|---|
importWxr | Portable content shared between WordPress sites without overwriting existing content | Posts, pages, custom post types, terms, authors, comments, and attachment references |
runPHP | Small, deterministic fixtures and content that needs custom logic | Anything the PHP code creates through WordPress APIs |
importWordPressFiles | Restoring a complete Playground demo | The 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.