使用 EmDash 管理后台分析 WordPress 站点、准备兼容的集合、导入内容、复制媒体并重写 URL。在导入后的站点通过验证之前,请保持 WordPress 站点可用。
开始之前
请准备以下内容:
- WordPress 数据库和
wp-content/uploads的备份。 - 如果计划复制媒体,需要一个已配置存储的 EmDash 站点。
- 一个 EmDash 管理员账户。WordPress 导入需要
import:execute权限。 - 完整的 WordPress eXtended RSS(WXR)导出文件,或在 WordPress 站点上安装的 EmDash Exporter 插件。
记录当前的固定链接结构、规范来源、重定向、菜单、启用的文章类型、分类法,以及新站点必须保留的插件自有字段。
选择导入方法
| 方法 | 适用场景 | 包含的数据 |
|---|---|---|
| WXR 上传 | 你可以通过 Tools → Export 导出 | 导出文件中包含的数据,包括文章、页面、自定义文章类型、分类法词条、可复用区块、作者和附件 URL |
| EmDash Exporter | 你控制该 WordPress 站点,并且可以安装导出器 | 需要认证才能访问的内容,以及受支持的站点设置、SEO 字段、分类法和媒体元数据;使用导出器 1.2.0 或更高版本时,还包括评论、菜单、徽标和站点图标 |
在没有导出器的情况下输入站点 URL,只会探测公开的 WordPress REST API。该探测可以检测到 WordPress,并统计公开的文章、页面和媒体数量,但无法执行直接的 REST 导入。
导出 WXR 文件
在 WordPress 中打开 Tools → Export,选择 All content,然后下载 XML 导出文件。WXR 文件指向 WordPress 来源上的媒体;它不包含附件的字节内容。
连接 EmDash Exporter
请在 WordPress 的 Plugins 页面查看导出器的版本。评论、菜单、徽标和站点图标需要导出器 1.2.0 或更高版本。使用更早的版本时,导入会在没有这些内容的情况下完成,也不会把它们报告为缺失。
使用导出器 1.2.0 或更高版本时,请在 WordPress 中打开 Tools → EmDash Migration 并生成迁移密钥。把密钥粘贴到 EmDash 导入页面中。
无论导出器是哪个版本,你都可以输入 WordPress 站点 URL。检测到导出器后,通过 WordPress 的应用程序密码页面授权 EmDash。在本地 HTTP 开发站点上,由于授权回调需要 HTTPS,请手动输入 WordPress 用户名和应用程序密码。
通过管理后台导入
-
在管理后台侧边栏中选择 Import 以打开 Import from WordPress 页面,或直接访问
/_emdash/admin/import/wordpress。 -
上传 WXR 文件、粘贴导出器的迁移密钥,或输入 WordPress URL。
-
检查分析结果。对于每个 WordPress 文章类型,确认目标集合、必填字段,以及与现有字段的兼容性。
-
将 WordPress 作者映射到 EmDash 用户。未映射的来源作者可以用访客 byline 表示,因此署名展示不依赖于是否授予其 EmDash 登录权限。
-
对于通过导出器导入的情况,选择是否导入菜单、站点标题和副标题、徽标和网站图标,以及受支持的 SEO 值。这些开关不属于 WXR 路径。
-
开始导入。EmDash 会先创建缺失的兼容集合和字段,然后再创建条目。
-
如果发现了附件,请运行媒体步骤。EmDash 会下载来源的字节内容,通过已配置的存储适配器存储,并重写匹配的内容 URL。
转换行为
状态
导入器按如下方式映射 WordPress 状态:
| WordPress | EmDash |
|---|---|
publish | published |
draft | draft |
pending | draft |
private | draft |
future、trash 或未知状态 | draft |
定时发布的日期和 WordPress 的可见性规则不会根据这些状态重建。发布之前,请检查每一篇导入的草稿。
富文本和可复用区块
Gutenberg 标记会被转换为 Portable Text。经典 HTML 由同一个转换器处理。请在渲染后的 EmDash 站点中检查复杂区块、嵌入内容、短代码、页面构建器标记以及插件定义的区块。
WordPress 在服务器端渲染的区块(例如 Latest Posts 或来自插件的区块)没有保存的标记。它们会被导入为 HTML 区块,其中包含原始的区块注释,例如 <!-- wp:latest-posts {"postsToShow":3} /-->。这些区块在站点上不显示任何内容。请在编辑器中打开该区块的 HTML 标签页,查看它原本是什么,然后重新构建或删除它。
WXR 中的 wp_block 条目会作为 sections 导入。它们不会被导入到普通的内容集合中。
集合和字段
默认的文章类型映射包括 post 映射到 posts,page 映射到 pages。自定义文章类型使用经过清理的集合 slug。准备步骤会添加分析所需的标准标题、Portable Text 内容、摘要和特色图片字段。
类型兼容的现有字段会被复用。类型不匹配会阻止该集合的映射;导入器不会把现有字段强制转换为其他类型。
自定义字段和 SEO 数据
WXR 分析会报告非内部的文章元数据键,并建议字段名称和类型,但 WXR 数据库导入写入的是标准的导入字段,而不是复制每一个任意的元数据键。请把分析结果当作可能需要单独转换的字段清单。
当目标集合具有匹配的字段时,EmDash Exporter 路径可以复制自定义元数据和 Advanced Custom Fields(ACF)的值。对于带有 “Post Type is equal to” 位置规则的 ACF 字段组,分析会为该组中的每个 ACF 字段建议一个字段:文本、数字和真/假字段会获得匹配的类型,而选择、复选框、重复器、组、关系,以及其他可以保存列表或对象的字段则会变成 JSON 字段。通过其他位置规则分配的字段组,其字段仅根据导出器报告的元数据键来建议。如果某个集合的字段是早先的导入根据元数据键创建的,它会保留这些字段,因此其重复器会按每一行和每个子字段各生成一个字段的方式导入。JSON 值保持其 WordPress 形态:关系、文章对象、用户和分类法字段按 WordPress ID 指向 WordPress 的文章、用户和术语,而不是 EmDash 条目;图片、文件和图库字段指向 WordPress 媒体文件,而不是已导入的 EmDash 媒体。存储在多篇文章上的 ACF 组子字段,也可能作为单独的字段出现在该组的 JSON 字段旁边;请保留你的模板所使用的那一份。在模板中使用这些值之前,请先检查它们。
导出器路径还可以在启用相应的导入开关后,创建并填充受支持的特色图片字段,以及 Yoast 或 Rank Math 的 SEO 字段。
作者和 byline
已映射的 WordPress 作者会成为条目的所有者。署名展示使用 byline。如果没有用户映射,EmDash 会根据 WordPress 作者的身份创建或复用访客 byline。
分类法
分类目录和标签会导入到匹配的 EmDash 分类法定义中。导出器路径可以为自定义分类法创建定义。没有匹配 EmDash 定义的 WXR 自定义分类法会被报告为缺失,其分配关系会被跳过。
媒体
媒体去重会比较已下载字节内容的 SHA-1 哈希。具有相同哈希的现有媒体行会被复用。文件名和 WordPress ID 不是去重的依据。
在 EmDash 下载附件期间,来源站点必须保持可访问。来自附件 URL 的重定向在被跟随之前会经过验证。
重试部分完成的导入
管理后台导入的设计会跳过已存在的条目,但其匹配边界很重要:
- 现有内容按集合、slug 和语言区域匹配,而不是按 WordPress ID 匹配。
- 如果来源 slug 在两次尝试之间发生了变化,请检查这两个条目并手动解决重复问题。
- 重新运行媒体步骤时,会按内容哈希复用已经存储的、字节完全相同的文件。
- 导出器流程发送的是有大小限制的分块。重新启动浏览器流程会重新运行内容页面,并根据被跳过的条目重建关系映射。
管理后台不会保存 WXR 的恢复文件。emdash import wordpress 上的 --resume 标志属于另一个将转换后的 JSON 文件写入磁盘的 CLI 工作流;它不会恢复管理后台的数据库导入。
切换上线前的验证
将导入后的站点与来源站点进行比对:
- 按文章类型和状态统计条目数量。
- 打开具有代表性的 Gutenberg、经典编辑器、短代码和页面构建器内容。
- 确认特色图片和内嵌媒体都能从 EmDash URL 解析。
- 检查作者、byline、分类目录、标签、自定义分类法和翻译。
- 如果是通过导出器导入的,测试菜单、评论、站点标识和 SEO 字段。
- 抓取旧的公开 URL,并为每一个发生变化的路由准备重定向。
- 验证未登录的访客仍然无法访问草稿。
在新站点于生产环境中成功运行、并且不再需要回滚之前,请保留备份和 WordPress 部署。
故障排除
无法解析 XML 文件
请从 Tools → Export 重新导出文件,并确认下载已完成。不要用会改变编码的工具编辑 XML。
集合被标记为不兼容
现有字段的 slug 相同,但类型不同。请在重试之前更改文章类型的映射,或在 Content Types 下调和该字段。准备步骤会添加缺失的字段,但不会更改现有字段的类型。
机器人防护拦截了导出器
Cloudflare 的机器人防护可能会用质询页面而不是导出器 API 来响应 EmDash 的请求。EmDash 随后会报告机器人防护阻止了连接。请在迁移期间放行导出器的请求:
-
使用 Super Bot Fight Mode 或其他 Cloudflare WAF 功能时,添加一条操作为 Skip 的自定义规则,并把它放在任何会发出质询的规则之上。选择 All Super Bot Fight Mode rules;如果该区域使用 I’m Under Attack 模式,还要选择 Security Level。下面的表达式可匹配启用和未启用固定链接美化时的导出器 API(包括安装在子目录中的 WordPress),以及 EmDash 下载的媒体文件:
(http.request.uri.path contains "/wp-json/emdash/v1/") or (http.request.uri.query contains "rest_route=%2Femdash%2Fv1%2F") or (http.request.uri.path contains "/wp-content/uploads/") -
Cloudflare 免费套餐上的 Bot Fight Mode 无法通过规则跳过。请在迁移期间将其关闭,并在迁移之后重新开启。
媒体 URL 下载失败
请检查来源附件是否无需 WordPress 会话即可访问。需要认证的媒体、已删除的文件,以及重定向到私有网络地址的媒体都会单独失败,并保留在媒体错误列表中。
适配主题
归档路由使用 getEmDashCollection(),slug 路由使用 getEmDashEntry()。entry.id 是路由标识符,通常就是 slug;entry.data.id 是关系辅助函数使用的已存储内容 ID。
下面的路由会渲染一篇导入的文章:
---
import { decodeSlug, getEmDashEntry } from "emdash";
import { PortableText } from "emdash/ui";
const slug = decodeSlug(Astro.params.slug);
if (!slug) return Astro.rewrite("/404");
const { entry: post, error } = await getEmDashEntry("posts", slug);
if (error) return new Response("Could not load the post", { status: 500 });
if (!post) return Astro.rewrite("/404");
---
<article>
<h1>{post.data.title}</h1>
<PortableText value={post.data.content} />
</article>
路由和组件的映射请阅读移植 WordPress 主题。端点契约和确切的重试边界请阅读内容导入。