用 WordPress Playground 做演示站、主题预览或测试夹具时,内容从哪来?官方 Playground Handbook 2026 年 9 月 30 日那篇指南给了三条路:WXR XML 导入(importWxr)、 PHP 代码生成(runPHP)、 ZIP 快照恢复(importWordPressFiles)。官方在 Apple M4 Pro 上用 100 篇文章实测过一轮,ZIP 恢复中位数 320 毫秒,WXR 导入 2.21 秒,PHP 生成 2.78 秒——最快和最慢之间差了近 9 倍。但选哪个不取决于速度,取决于你要搬的是内容、数据还是整个站点。
三种方式速查
| 方法 | 最适合 | 实际搬运的东西 |
|---|---|---|
importWxr | 站点间共享可移植内容,且不想覆盖目标站已有内容 | 文章、页面、自定义文章类型、分类标签、作者、评论、附件引用 |
runPHP | 小而确定的测试夹具,或内容需要自定义逻辑生成 | PHP 代码通过 WordPress API 创建的任何东西 |
importWordPressFiles | 完整还原一个 Playground 演示站 | 数据库 + ZIP 里存在的 WordPress 文件(插件、主题、 uploads) |
选择逻辑其实一句话就能说完:只要文章和标签 → WXR;内容是生成出来的或依赖安装配置 → PHP;数据库、媒体、插件、主题、设置必须一起恢复 → ZIP 快照。
方式一:WXR XML 导入
WXR 就是 WordPress 自带的「工具 → 导出」生成的 XML 格式。把它放到 blueprint.json 同目录,然后在 blueprint 里引用:
{
"$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"
}
]
}
几个关键参数值得单独说:
fetchAttachments设为true时会下载 WXR 引用的媒体文件。网络传输往往主导总耗时,所以官方基准测试里把它关掉了。authorsMode可以把导入的作者映射到本地已有用户、或者创建新用户。rewriteUrls用于把旧站点的 URL 批量替换成新站点地址——从别的域名搬内容时必开。
如果 XML 放在线上而不是随包分发,把 bundled 换成 url 资源引用即可。
优点与代价
优点很实在:用的是 WordPress 官方标准交换格式,文章类型、分类、 post meta 、作者、评论和内容关系都能保住;可以拉附件、重写旧 URL;内容与目标站的核心、插件、主题、设置是分离的;源文件是纯文本 XML,任何编辑器里都能看、能进版本控制、能手工改。
代价集中在五点:
- 它不是整站克隆。插件、主题、插件自定义表、 options,以及 WXR 表达不了的文件,都得另配 blueprint 步骤。
- 附件导入要联网,且依赖旧媒体 URL 仍然可访问。
- 大 XML 的解析时间和内存开销都高于直接恢复一个现成的 SQLite 数据库。
- 重复导入是「累加」不是「同步」。导入器只创建找不到的分类标签,从不删除已有内容;只有当标题、作者、日期三项都匹配时才会跳过某篇文章。这意味着跑第二遍会得到重复内容。
- blueprint 会自动安装 WordPress Importer 依赖,在 WXR 导入开始前就多出一段安装时间。
runPHP 并在代码里先查存在再建。方式二:用 runPHP 生成内容
runPHP 直接调 WordPress API 。关键是必须先加载 /wordpress/wp-load.php,否则 wp_insert_post() 之类的函数根本不存在。官方基准里生成 100 篇文章的完整代码长这样:
{
"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}"
}
代码量最大的真实例子就是官方这段——把 JSON 里的 PHP 写成单行转义字符串,可读性基本为零。官方的建议是:程序大一点就把代码放进一个小插件里,或者拆成多个聚焦的步骤,别在 blueprint 里维护一条几千字符的长字符串。
什么时候值得
runPHP 的真正价值不是「快」或「慢」,而是它能表达另外两种方式表达不了的东西:
- 完全控制生成的数据及其相互关系(标签层级、菜单结构、指定作者、指定时间序列);
- 不需要内容文件,不需要联网;
- 可以在同一次操作里配置 options 、 post meta 、用户、分类法乃至插件专属数据;
- 写成代码就能做幂等——插入前先查一遍。
但它也有清晰的代价:blueprint 是受信任输入,只跑你信任来源的 PHP;脚本得自己处理报错、重跑、依赖和部分失败;代码可能和某个插件的 API 、数据库模型耦合;逐条创建记录会触发 WordPress hooks 和数据库写入,数据量大时性能会线性下降;比起「导出现有编辑内容」,写自定义 PHP 啰嗦得多。
用 WP API 而不是直接写数据库表
官方明确建议用 WordPress API,而不是直接操作数据库表——这样 hooks 、缓存和数据校验才照常运行。这个建议在 Playground 里尤其重要:很多人在本地用 wpdb 硬插数据觉得快,结果 hook 不触发、缓存不刷新、元数据不自增,排查时间比老老实实用
wp_insert_post() 长得多。
另一个容易被忽略的边界:runPHP 能做的远不止「造内容」。它可以覆盖 options 、可以改数据库、可以装东西。把它当「内容生成器」用很安全,当「任意代码执行器」用就要格外小心来源。
方式三:ZIP 快照恢复
这一步不是「导入内容」,而是整站恢复。它从 ZIP 里解出顶层 WordPress 文件,替换新实例里对应的路径。用 Playground 的「 Download as zip 」导出的文件,包含 wp-content、 SQLite 数据库、 uploads,以及一份用于调整 Playground scope URL 的 manifest 。
{
"$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" }
}
]
}
ZIP 里可以只有 wp-content、可以是一个完整的 WordPress 目录、也可以是套了一层外壳的目录。归档里有多个站点时,或者自动探测根目录不够用,用 pathInZip 显式指定。
它快的原因是显而易见的——没有逐条导入,只是把一份准备好的 SQLite 数据库放回去。 50.5 KiB 的输入换来 320 毫秒中位耗时,对比 WXR 的 106.0 KiB / 2.21 秒。
- 版本对齐。确认源和目标实例的 WordPress 、 PHP 、主题、插件版本兼容。这一步会升级导入的数据库并调整 Playground scope URL,但它不是面向任意生产环境迁移的通用工具。
- 只信自己的快照。ZIP 里可能含可执行 PHP 和整个数据库。只从可信来源恢复,别从别人分享的 demo 快照直接跑起来。
- 记住它是覆盖不是合并。ZIP 里存在的顶层路径会被替换,可能覆盖你已有的站点状态,而不是合并进去。
- 别指望挑着导入。它不适合往已有站点里挑几篇文章塞进去——要这个效果请用 WXR 。
- 附件多时优先 ZIP 。基准里 WXR 关掉了附件下载,所以 2.21 秒这个数字不含媒体传输成本。如果你的内容依赖大量附件,自包含的 ZIP 才是实际最快的选择。
官方基准数据怎么看
| 方法 | 输入体积 | 中位数 | 最小 | 最大 | 相对最快 |
|---|---|---|---|---|---|
ZIP / importWordPressFiles | 50.5 KiB | 320 ms | 318 ms | 322 ms | 1.00x |
XML / importWxr | 106.0 KiB | 2.21 s | 2.16 s | 2.25 s | 6.90x |
PHP / runPHP | 生成代码 | 2.78 s | 2.76 s | 2.80 s | 8.68x |
官方对这组数字的免责声明写得很实在:把它当单台机器上的参考,不要当通用排名。数据形态很关键——附件多的场景偏向自包含 ZIP,WordPress hooks 复杂的项目会拖慢 runPHP,而 WXR 的可移植性可能比绝对速度更值钱。
其他内容来源
Blueprint 还能用两条路拿到内容:importThemeStarterContent 导入主题注册的 starter content,wp-cli 步骤执行 wp post generate 这类命令。当主题自身的 starter content 或 WP-CLI 命令就是演示数据的权威来源时,这两条比三种导入方式都更直接。
相关阅读
- WordPress Playground 接入 WebMCP——让 AI 智能体直接在浏览器里操作你的演示站。
- WordPress 区块主题入门——用 theme.json 和站点编辑器看懂全站编辑时代。
- Gutenberg 24.1 发布——块编辑器近期变更速览。
- WordPress HTML API——处理生成内容时的标记解析与安全。
只想导入 10 篇文章做主题演示,选哪种?
为什么我重复导入 WXR,文章数量翻倍了?
runPHP,在代码里先查后建实现幂等。runPHP 报「 undefined function wp_insert_post 」怎么办?
/wordpress/wp-load.php。runPHP 不会自动加载 WordPress 核心,第一行必须是 require_once '/wordpress/wp-load.php';,然后才能调 wp_insert_post() 这类函数。ZIP 恢复能把内容导入到已有的 Playground 实例吗?
importWordPressFiles 会替换 ZIP 里存在的顶层路径,是覆盖语义不是合并。而且它会把快照和当时的 WordPress 、 PHP 、主题、插件、数据库版本绑得更死。要往已有站点加内容,请用 WXR 。








评论 (0)