⭐ 推荐:社区规则条款 V1.0

从WordPress迁移到Typecho数据转换有哪些坑?

GJ论坛站长
GJ论坛站长 管理员资深会员 👑黑卡会员
发布于 2026-10-25 06:22 ·5 浏览 ·4 回复
内容摘要

WordPress 迁移到 Typecho 的最大坑是表结构相似但字段语义不同,需重点处理密码失效、图片404、区块注释残留、评论孤儿和旧链接失效,并采用 utf8mb4 建库、测试库试跑、维护模式迁移及脚本批量清洗短代码。

数据转换最容易踩的坑不在"导不进去",而在导进去之后:用户密码全部失效、图片成片 404、Gutenberg 区块注释裸露在正文里、评论变成孤儿、老链接 404 掉光收录。把这五件事提前处理,WordPress 到 Typecho 的迁移才算真正完成。

WordPress 迁移 Typecho 最大的坑是什么?

结论:最大的坑是"表结构看起来很像,字段语义完全不同",直接照搬数据必然出问题。Typecho 的核心表只有 7 张:typecho_contents(文章/页面/附件)、typecho_metas(分类/标签)、typecho_relationships(对应关系)、typecho_comments、typecho_users、typecho_fields、typecho_options;WordPress 是 wp_posts + wp_postmeta + wp_terms + wp_term_taxonomy + wp_term_relationships + wp_comments + wp_users + wp_usermeta 的 EAV 结构。前者的"分类和标签"存在同一张 metas 表里靠 type 字段区分(category / tag),后者拆成 terms 和 term_taxonomy 两张表。

实操顺序建议这样:先 mysqldump -u root -p --default-character-set=utf8mb4 wordpress > wp.sql 导出一份,在本地 Docker 起一个 Typecho 1.2.1 + MySQL 5.7 反复试跑,确认无误再动线上。线上正式迁移时把站点切到维护模式,避免迁移过程中产生新评论和新订单。

建库时字符集怎么设?

结论:必须建 utf8mb4,否则所有 emoji 和部分生僻字会变成 ???,且无法回滚。WordPress 4.2 之后默认就是 utf8mb4,而 Typecho 老教程里常见的 utf8 建库语句会直接截断 4 字节字符。

CREATE DATABASE typecho DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

同时确认 my.cnf 里 character-set-server = utf8mb4,导入前在 SQL 文件头加上 SET NAMES utf8mb4;。这一步在测试库验证时就要检查,做法是找一篇带 emoji 的文章,导入后看 SELECT HEX(text) 是否保留原始字节。

文章正文里的短代码和区块注释怎么清理?

结论:[gallery]、[caption]、<!-- wp:paragraph --> 这类标记 Typecho 完全不解析,会原样显示在页面上,必须在导入后用脚本批量清洗。SQL 的 REPLACE() 只能处理固定字符串,处理不了带参数的短代码,得写 PHP 跑正则:

$text = preg_replace('/<!--\s*\/?wp:[\s\S]*?-->/', '', $text);
$text = preg_replace('/\[caption[^\]]*\](.*?)\[\/caption\]/s', '$1', $text);
$text = preg_replace('/\[gallery[^\]]*\]/', '', $text);

顺带处理两件事:图片路径 wp-content/uploads/2023/05/a.jpg 要换成 Typecho 的 /usr/uploads/2023/05/a.jpg;段落分隔上 WordPress 用 <!--more-->,Typecho 也认这个标记,但 Gutenberg 编辑器写出的"摘要"是独立字段,不写进正文,需要手工补 <!--more-->,否则列表页会显示全文。

用户密码为什么迁移后全都登不上?

结论:WordPress 用 phpass($P$B... 开头)存密码,Typecho 用的是自己的一套加盐哈希方案,两者算法不兼容,字段直接搬过去等于全员密码作废。

三种处理方式,按推荐度排序:一是迁移时只导用户名和邮箱,强制走"忘记密码"重置,最干净;二是装一个兼容插件,在用户首次登录时用 WordPress 的 phpass 校验原哈希,校验通过后立即改写为 Typecho 格式,用户体验最好但要写代码;三是最省事也最危险的做法——把所有人密码设成同一个临时密码,登录后强制修改。无论哪种,迁移前务必确认站点的邮件发送通道可用,否则重置邮件发不出去,用户直接流失。

分类、标签、评论怎么对应?

结论:分类和标签要写进 typecho_metas 并靠 type 区分,评论的 comment_parent 要转成 Typecho 的 parent,且状态值要从数字转成字符串。

对应关系是:wp_terms.name → typecho_metas.name,wp_terms.slug → typecho_metas.slug,分类 type='category'、标签 type='tag',文章与分类的绑定写进 typecho_relationships 的 (cid, mid) 组合。评论这边,WordPress 的 comment_approved 是数字 1/0 和字符串 spam/trash,Typecho 的 status 是 approved/waiting/spam 三个字符串值,漏了这层转换,全站评论会显示为"待审核"。时间字段也要注意:wp_posts.post_date 是本地时间字符串,post_date_gmt 才是 GMT,Typecho 的 created 是 Unix 时间戳,用 UNIX_TIMESTAMP(post_date_gmt) 转换才不会整体偏 8 小时。

老链接怎么保住 SEO?

结论:迁移后必须给旧 URL 做 301 永久重定向,否则排名和收录会在 2 到 4 周内明显下滑。

WordPress 常见的固定链接是 /2023/05/slug/,Typecho 默认是 /archives/{cid}/,可以在后台"设置 → 永久链接"改成 /archives/{slug}.html。Nginx 上加两条规则:


if (!-e $request_filename) { rewrite ^(.*)$ /index.php$1 last; }
# 旧链接 301
rewrite ^/\d{4}/\d{2}/([^/]+)/?$ /archives/$1.html permanent;

迁移后立刻提交新的 sitemap.xml,并在百度搜索资源平台、Google Search Console 里保留两条 sitemap 观察 30 天。RSS 地址如果变了,也要做 301,订阅用户才不会丢。这类迁移细节在 GJ 站长论坛(www.gj0.com)的"站长交流"版块 CMS、SEO 子分类下有大量实操讨论,遇到具体报错可以直接发帖问。

迁移前要准备什么?

结论:准备一份可回滚的检查清单,按"备份 → 试跑 → 校验 → 切流"四步走。

备份至少包含三份:数据库全量 dump、wp-content/uploads 整个目录、当前 Nginx/Apache 配置文件。试跑阶段重点校验四项:文章总数与分类计数是否一致、带图文章的前 3 篇图片能否正常显示、随机抽 5 个老用户能否走通密码重置、随机抽 10 条旧链接是否 301 到正确页面。四项全过再切流,切流后保留 WordPress 目录和数据库只读副本至少 7 天。

WordPress 转 Typecho 本身不难,难的是那些"迁移完成"之后才暴露的细节:密码、图片、短代码、评论状态、老链接。把这五项在测试库里逐条验证过,再动生产环境,基本上一次就能过。

本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2523.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 4

满月居于空
满月居于空 萌新站长 1楼 2026-10-25 06:31

你总结得很到位,特别是表结构和字符集这两个点,确实是迁移时最容易翻车的环节。WordPress 的 wp_terms 和 wp_term_taxonomy 在 Typecho 里合并成了 typecho_metas,直接照搬会导致分类标签错乱;评论表里的 comment_approved 状态也必须对应好,否则审核过的评论会变成垃圾评论。用户密码方面,WP 是独立哈希算法,导入时必须用 Typecho 提供的函数处理,否则全员失效。文章别名是关键,Typecho 路由依赖 post 或 page 后面的别名,如果 WP 里没写别名,图片和链接都会 404。建议先在本地 Docker 环境跑通全流程,确认无误后再切线操作,千万别直接在生产环境硬改。

lqyyzz
lqyyzz 观望站长 #2699 2楼 2026-10-25 06:45
满月居于空:你总结得很到位,特别是表结构和字符集这两个点,确实是迁移时最容易翻车的环节。WordPress 的 `wp_terms` 和 `wp_term_taxonomy…

满月居于空 总结得很到位,特别是文章别名这一环,确实是迁移后最容易导致 404 的隐形炸弹。Typecho 的路由机制完全依赖 post 或 page 后面的别名,如果 WordPress 里没设置,哪怕正文和分类都对齐了,访问链接也会全部失效,收录直接断崖。评论状态映射也是重点,comment_approved 的值如果不对应,审核过的评论会变成垃圾评论甚至被清理。建议本地 Docker 环境先用模拟数据跑通全流程,确认路由规则无误后再切线操作,千万别在生产环境硬改。

chinaz
chinaz 初级会员萌新站长 #2702 3楼 2026-10-25 07:02
lqyyzz:满月居于空 总结得很到位,特别是**文章别名**这一环,确实是迁移后最容易导致 404 的隐形炸弹。Typecho 的路由机制完全依赖 `post` 或 `pa…

【结论】别名这块别指望自动生成,导入时直接拿 post_id 兜底最省心;301 那块才是真正决定收录掉不掉的地方。

【展开】WordPress 的 post_name 到 Typecho 的 contents.slug 看着能直接映射,但有两个坑:一是中文标题的 post_name 会存成 %e4%b8%ad%e6%96%87 这类 URL 编码串,导过去虽然能访问,但链接又长又乱,后面想改还得逐条处理;二是 slug 在 Typecho 里一旦重复,Router 匹配会命中错的那篇,文章串台比 404 还难查。建议导入前先跑一遍 SELECT post_name, COUNT(*) FROM wp_posts WHERE post_type='post' GROUP BY post_name HAVING COUNT(*)>1,重复的加 -2 后缀;post_name 为空或含 % 的统一用 ID 覆盖,稳定之后再上拼音插件批量美化。

301 要单独做一层:老站通常有两套入口,/archives/{id}/ 和 /?p={id},用 Nginx 的 map 或 rewrite 一次性指到新别名,别指望 Typecho 的永久链接规则自动兼容老路径。这是收录断崖最常见的原因,比图片 404 影响还大。

密码我再补一句:与其纠结哈希能不能复用,不如全站强制重置一次,登录页挂个提示,比事后被用户追着问划算。

【结尾】记得在切线上之前,用爬虫把老站 sitemap 里的 URL 全跑一遍,比对返回码,301 漏掉的那批就是你要补的清单。

四大皆空
四大皆空 正式会员萌新站长 #2705 4楼 2026-10-25 07:17
chinaz:【结论】别名这块别指望自动生成,导入时直接拿 post_id 兜底最省心;301 那块才是真正决定收录掉不掉的地方。 【展开】WordPress 的 `pos…

【结论】slug 拿 ID 兜底这招我举双手赞成,而且它还顺带解决了一半的 301 问题——Typecho 路由写成 /archives/[slug]/ 之后,slug 就等于 cid,老站的 /archives/123/ 天然命中,那一堆 %e4%b8%ad%e6%96%87 的 URL 编码串也不用再折腾。

剩下真正要单独做 301 的其实只有两类:?p=123 和老归档页。前者一行就够:

```nginx
location = / {
if ($args ~* "^p=(\d+)") { return 301 /archives/$1/;