随拍黄叶

wp import迁移WordPress遇到的坑

Posted onCategories技术文章

前言

最近的任务重心是协助公司另外的团队做 WordPress 站点的迁移。因为有之前合并两个站内容到一个站的经验,这个任务倒不困难。只不过距离上次迁移已经几个月了,当时只是操作,很多踩过的坑都在记忆里。这次觉得还是写点什么,把一些显著的坑和对应解决办法记录下来。

处理的站点的数据库咋一看挺吓人的大几百万条,冷静下来一分析,原来老站点运营多年,还用了一个论坛插件叫 bbPress。这尼玛老版本n久未更新,原来的老版本居然没有验证码。然后 wp_posts 表里绝大部分都是机器人塞的垃圾信息。满奇葩的,把这事和产品,IT 沟通后,一致认为可以砍掉。遂清理数据库,这样一来数据表马上降到了数十万条了。

喏,这么个东西。它不自己去建表,偏偏建了3种 post type 叫 reply,topic,forum。真是无聊。个人认为有经验的开发者还是应该把自己的插件做成独立的表结构之类的,防止污染主要的表。

bbPress

当然还有其他很多名目繁多的清理工作,这里就不一一展开。网上看到别人整理的这个 WordPress database clean up queries 有部分参考意义。

从老站导出xml

导出过程相对比较简单。用到两个东西,一个叫 wp-cli, 算是 WordPress 瑞士军刀了。强大的命令行工具不多解释。另一个是基于 wp-cli 的 wp export 命令, 这个不需要装任何插件,直接用就是了。命令行下进入站点目录,运行 wp export, 稍等片刻就会生成若干个 xml 文件,每个文件大小在15M样子。

这个命令还有很多其他参数,比如控制到处的 post 起始和结束时间等等,可以用 –help 参数查看所有支持的参数。

将xml导入新站

导入也是基于 wp-cli 的命令,跟 wp export 对应,叫 wp import。只是需要安装下面这个额外插件

WordPress Importer

装完该插件并激活就可以使用 wp import 命令了。使用 wp import 需要点小技巧,因为我们要处理多个xml文件,可以在命令行下写个简单的循环并且记录日志到/tmp下。

for i in $(ls ~/export); 
    do sudo -u www-data wp import ~/export/$i > /tmp/$i.log
done

当然直接用上面的命令在做的话有两个缺点,

  1. 线性执行,耗时长。
  2. 命令行超时容易中断。

这里就必须用另外一个 linux 命令叫做 screen。不展开说 screen 了,否则没完没了。用了 screen 后可以多个 screen 下同时运行导入任务并且不用担心去喝咖啡的时候进程超时挂了。

Okay,上面铺垫了一大堆,终于到重点了,列一下会遇到的坑。

坑一:自定义post type 处理

WordPress 有个概念叫 post type,你的老站有可能用了各种插件产生了各种自定义的 post type。如果你的新站没这些 post type,额对不起这些内容是导不进去的。解决方案很简单,在新战点把这个 post type 建出来先。

参考 How to Import and Export Custom Post Types in WordPress 后知道有这么个插件能派上用场。装上后去后台直接添加该 post type。

Custom Post Type UI

本篇主要讲如何导入,导入后的自定义 post type 内容如何在新站展示,那又是一个新话题需要把老站的功能迁移一部分过来。也不深入展开了,否则这篇文章真写不完。大写的囧。

坑二:导入失败处理

okay,到这里真刀真枪开始导入。恩大部分 xml 都顺利导进去了,然而你去查看日志会发现有好几个日志里就空空的一句话

Error: Cannot create a user with an empty login name.

我第一次见的时候也莫名其妙,仔细检查了 xml 里所有关于 login name 的信息,并没有所谓的 empty login name。根据经验判断这个出错信息是挂羊头卖狗肉,跟用户信息无关。那么跟什么有关呢,不知道。先看看这个 xml 是否合法。一测果真 xml 格式有问题。

关于如何在命令行下测试 xml 合法性也不继续展开了。一个传送门: quick-way-to-validate-xml-identify-point-of-brokenness

wp-import-failure

如上图所示,命令行下只能告诉我这个 xml 有问题,但是没能告诉我具体哪一行出了问题。这个比较讨厌,我相信应该有相关的工具,但是目前我还不知道。但是我用了一个折中的办法:直接把 xml 扔给 chrome 浏览器。如下图,chrome 非常聪明的告诉了我在325710行有错误的编码字符!

wp-import-find-line-in-chrome

这就好办多了,谢谢 chrome。直接编辑 xml 找到对应行一看,莫名其妙的 ^X^Y^Z 完全不知道是什么东西,当初小编是怎么输入到 WordPress 里的。真是神了。

wp-import-checking-line-325710

特殊字符怎么产生的已经不可考,不管它,简单粗暴删除之。

wp-import-checking-db-record

删除干净后保存,再次运行 wp import,完美运行了!

wp-import-success

2017-08-11更新

找到一个命令行下工具叫做 xmlstartlet 会直接告诉你哪一行字符出来错误,完美!免去了把xml扔Chrome的低效率做法。

$ xmlstarlet val -e xxx.wordpress.2017-08-10.002.xml
xxx.wordpress.2017-08-10.002.xml:238745.29: Input is not proper UTF-8, indicate encoding !
Bytes: 0x18 0x19 0x1A 0x26: Bytes: 0x18 0x19 0x1A 0x26

Camera ID: &
 ^
xxx.wordpress.2017-08-10.002.xml - invalid

坑三:导入过程巨慢处理

文章上面提到 screen 的地方说到了多开几个 screen 同时导入。恩理想是丰满的现实却是相当骨感。我下面开了6个 screen 同时导入。结果等了1小时都没全部走完。这尼玛忍不了。

wp-import-screen-ls

查看 mysql在干些啥呢。原来 wp import 自作聪明的把所有老的站点的域名一个个替换成新的域名。

mysql> show full processlist;
  Update wp_posts SET post_content = REPLACE(post_content, old_url, new_url);

wp-import-show-full-processlist

我们的数据有几十万条,这个一条条更新实在效率太低,并且多个进程容易写等待。解决方案是停掉这些更新语句,等全部运行完成后,自己运行 wp search-replace 命令来替换老域名。

搜索了一下 wordpress_importer 插件的代码,在 wordpress-importer.php 里找到 WP_Importer::import 方法,注释掉下面的语句, 导入过程会变的飞快。

// $this->backfill_attachment_urls();

wp-import-WP_Import-method

当然导完后别忘记了运行 wp search-replace 命令来手动更新域名。一旦导入完成后我们可以反激活 wordpress-importer 插件,它的使命就终止了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注