← 返回个人博客
个人博客WordPress网站迁移ElementorWoodMartWooCommerce

WordPress 网站迁移怎么做才稳?别再直接用 SQL 替换域名

解释普通 SQL 替换为何会破坏 Elementor、WoodMart 等序列化设置,并给出备份、WP-CLI、Better Search Replace、WooCommerce 切换与回滚步骤。

这篇文章以前写得太省事了。

旧版的思路是:打包文件、导出数据库、上传到新服务器,再用几条 SQL 把旧域名换成新域名。前面几步没有大问题,最后那几条 REPLACE() 却不应该继续推荐。

原因也不复杂。现在的 WordPress 很少只是文章和图片。Elementor、WoodMart、WooCommerce 以及不少表单、缓存和多语言插件,都会把配置存在 wp_optionswp_postmeta 或自己的数据表里,其中有些还是 PHP 序列化数据。普通 SQL 只会替换文字,不知道这些数据还有长度信息,换完域名以后可能直接读不出来。

所以这次把文章重写一遍。不是把步骤写得更多,而是把真正容易出问题的地方讲清楚。

旧办法为什么会把主题设置弄丢

先看一个简化后的序列化值:

text已剪下 ✓
a:1:{s:7:"siteurl";s:23:"https://old.example.com";}

s:23 表示后面的字符串长度是 23。假如直接执行 SQL:

sql已剪下 ✓
UPDATE wp_options
SET option_value = REPLACE(
  option_value,
  'https://old.example.com',
  'https://shop.example.com'
);

域名已经变长了,s:23 却不会跟着更新。PHP 再反序列化这条记录时就可能失败。

这类问题很容易让人误判。网站通常不会彻底白屏,而是出现一些看似无关的现象:

WordPress 官方迁移文档也专门提醒过序列化问题。换域名时应该使用能识别序列化结构的工具,而不是对 SQL 文件或数据库做普通文本替换。

先分清楚:你到底需不需要换 URL

这一步能省掉很多没必要的操作。

只是换服务器,域名不变

例如 https://example.com 从一台云服务器搬到另一台,域名、HTTPS 和 WordPress 所在目录都没变。这种情况通常不需要替换数据库里的 URL

把文件和数据库复制过去,改好新服务器的数据库连接,然后在自己电脑的 hosts 文件里临时加入:

text已剪下 ✓
203.0.113.20 example.com www.example.com

只有你的电脑会访问新服务器,其他访客仍在旧站。因为浏览器地址仍然是真实域名,Cookie、绝对链接和 HTTPS 都能按上线后的状态测试。

测试通过后再切 DNS。这个办法比把站点临时改成 IP 地址或测试域名干净得多,也不会制造第二轮 URL 替换。

域名、协议或目录发生变化

下面这些情况才需要做数据库替换:

这时应该用 WP-CLI 的 search-replace,或者使用明确支持序列化数据的迁移工具。

搬之前,先把能恢复的备份做好

WordPress 的完整备份有两部分:数据库和网站文件。只备份其中一个都不够。

数据库里有文章、订单、用户和绝大多数设置;文件里有上传图片、主题、插件、wp-config.php.htaccess 和定制代码。WordPress 的官方备份说明也建议把两者当作同一套备份保存。

有 WP-CLI 时,可以这样导出数据库:

bash已剪下 ✓
cd /var/www/example.com
wp db export ~/backups/example-before-migration.sql --add-drop-table

没有 WP-CLI 也可以用 MySQL:

bash已剪下 ✓
mysqldump \
  --single-transaction \
  --quick \
  --default-character-set=utf8mb4 \
  -u OLD_DB_USER -p OLD_DB_NAME \
  > ~/backups/example-before-migration.sql

用 phpMyAdmin 导出 WordPress 数据库

文件可以打包:

bash已剪下 ✓
cd /var/www/example.com
tar -czf ~/backups/example-files.tar.gz .

打包 WordPress 完整网站文件

这里有两个常被忽略的细节:

  1. wp-content/uploads 之外可能还有插件自己创建的存储目录;
  2. 备份文件存在不代表能恢复,至少要确认压缩包能打开、SQL 不是空文件,重要站点最好在临时环境导入一次。

迁移前也顺手记下 PHP、MySQL、WordPress、主题和插件版本。新服务器少了某个 PHP 扩展时,表现出来可能像迁移失败,其实只是运行环境不同。

把文件和数据库放到新服务器

小站用压缩包上传没有问题。文件较多时我更推荐 rsync,因为第一次复制完之后还能再执行,只同步有变化的文件:

bash已剪下 ✓
rsync -a --info=progress2 \
  old-server:/var/www/example.com/ \
  /var/www/example.com/

源目录最后的 / 不要漏,它表示复制目录里的内容。

新数据库不需要和旧数据库同名。这是旧文里的另一个错误。WordPress 最终只看 wp-config.php

php已剪下 ✓
define('DB_NAME', 'new_wordpress');
define('DB_USER', 'new_wordpress_user');
define('DB_PASSWORD', '使用独立强密码');
define('DB_HOST', 'localhost');

只要目标数据库已经创建,直接导入即可:

bash已剪下 ✓
mysql -u NEW_DB_USER -p NEW_DB_NAME \
  < ~/backups/example-before-migration.sql

或者:

bash已剪下 ✓
wp db import ~/backups/example-before-migration.sql

将数据库备份导入新服务器

不要为了让数据库同名而全局编辑 SQL 文件。普通 mysqldump OLD_DB_NAME > backup.sql 通常并不要求导入到同名数据库。

文件复制后再按服务器实际用户修正权限。不要用 chmod -R 777 解决问题,那只是把权限问题变成安全问题。

换域名时,用 WP-CLI 做安全替换

下面的命令先在新服务器上运行,而且第一遍一定保留 --dry-run

bash已剪下 ✓
wp search-replace \
  'https://old.example.com' \
  'https://new.example.com' \
  --all-tables-with-prefix \
  --skip-columns=guid \
  --precise \
  --recurse-objects \
  --report-changed-only \
  --dry-run

先看它准备改哪些表、命中多少条。如果结果合理,再去掉最后一行执行正式替换:

bash已剪下 ✓
wp search-replace \
  'https://old.example.com' \
  'https://new.example.com' \
  --all-tables-with-prefix \
  --skip-columns=guid \
  --precise \
  --recurse-objects \
  --report-changed-only

这几个参数不是为了让命令显得复杂:

WP-CLI 的官方命令文档明确说明它会处理 PHP 序列化数据。

为什么要跳过 GUID?因为它是文章或附件的稳定标识,不是给访客点击的链接。换域名不等于内容变成了一篇新文章。直接修改 GUID 可能让 RSS 阅读器重新识别旧内容。

旧站如果同时用过 HTTP、HTTPS、带 www 和不带 www,不要图省事只替换 old.example.com。先分别 dry-run,确认每种完整 URL 的命中范围,再逐个处理。搜索词太短,很容易碰到邮箱、日志或本来不该改的文本。

执行后可以查一次残留:

bash已剪下 ✓
wp db search 'old.example.com' --all-tables-with-prefix

查到旧域名也不要立刻全改。历史订单备注、日志、GUID 和第三方回调记录有时就应该保留。

Elementor 和 WoodMart 还要再做什么

数据库替换正确,不代表页面构建器生成的文件和缓存也已经更新。

Elementor

换域名后进入 Elementor > Tools > Replace URL,填入完整的旧 URL 和新 URL。然后执行 Regenerate Files & Data,重新生成 CSS 和数据文件。

接着检查:

Elementor 的官方迁移故障说明也把更新 URL、重建 CSS/Data 和清理缓存列为迁移后的主要处理步骤。

WoodMart

WoodMart 搬家前,最好先到 Theme Settings > Import / Export / Reset 手动创建并导出一份主题设置。这个备份不能代替完整数据库,但在主题选项意外回到默认值时很有用。

迁移后重点看 Header Builder、商店页、商品页、移动端导航、自定义 CSS/JS 和字体。WoodMart 与 WoodMart Core 插件的版本也要对应,原站用 Elementor 还是 WPBakery,目标站不能选错。

WoodMart Theme Settings 文档说明了设置导入导出的位置,备份文档则提醒恢复操作会覆盖当前主题设置。所以不要一看到样式不对就反复 Reset,先保留数据库和现场。

除此以外,支付、SMTP、OAuth、验证码、地图、CDN、对象存储等配置通常还存在第三方后台。数据库换完域名,并不会自动替你修改这些平台上的回调地址。

WooCommerce 站点不能只导出一次数据库

普通展示站在迁移期间多一篇评论,影响不算大。WooCommerce 漏掉的是订单、付款和库存,处理方式不能一样。

比较稳妥的做法是分两次:

第一次在旧站继续营业时,把文件和数据库复制到新服务器,完成主题、插件、支付沙盒、邮件和性能测试。

正式切换时,再让旧站短暂进入维护或只读状态,停止下单、注册和表单写入。重新导出最新数据库,用 rsync 补一次上传文件,然后在新站导入最终数据库。确认订单号、库存和支付回调正常后再切 DNS。

不要让新旧两台服务器同时接收真实订单。两边数据库一旦各自新增内容,后面没有一条简单 SQL 可以把它们安全合并。

上线前至少测试这些项目:

业务完全不能停写时,应该使用支持增量同步的托管迁移服务,或者单独设计数据库复制方案,而不是照搬普通博客教程。

固定链接、缓存和 HTTPS

如果迁移后首页正常、内页全部 404,先检查 Web 服务器规则。

Nginx 根目录安装常见配置是:

nginx已剪下 ✓
location / {
    try_files $uri $uri/ /index.php?$args;
}

Apache 则要确认 .htaccess 已复制,mod_rewriteAllowOverride 正常。之后进 设置 > 固定链接 保存一次即可。不要一遇到 404 就去改数据库。

缓存要从里面往外清:Elementor 或主题生成文件、WordPress 页面缓存、Redis/Memcached、服务器缓存、CDN,最后才是浏览器。只清浏览器,服务器仍然可能继续发旧 HTML。

HTTPS 也不要等 DNS 切完才处理。尽量提前准备证书,并在 hosts 测试时检查混合内容、字体、图片和第三方脚本。

切 DNS 之前,我会实际点一遍这些地方

只看首页没有意义。至少要检查:

换域名时,旧网址应该逐路径 301 到对应的新网址,不要把所有旧页面都扔到新首页。站点地图、搜索引擎站长平台、广告链接和第三方回调也要一起更新。

出问题时,先停手,不要继续“试几个设置”

迁移最重要的不是永远不出错,而是出错后能回去。

旧服务器不要切完 DNS 就删除。先保留为只读状态,观察订单、邮件、队列和日志,至少经过一个完整业务周期。切换前也要明确什么情况必须回滚,例如付款失败、订单丢失、核心页面持续 500 或主题设置无法恢复。

一旦达到回滚条件:先停止新站写入,再把流量切回旧站,恢复成套备份,然后处理切换窗口内可能产生的数据。不要一边让用户继续下单,一边在生产数据库里反复替换。

没有 WP-CLI:用 Better Search Replace

如果主机没有开放 SSH,或者你不习惯命令行,Better Search Replace 是一个比较实际的替代方案。它不是在后台直接执行一条粗暴的 SQL REPLACE(),而是会识别并重新写入序列化数据。Elementor、WoodMart、Widget 和不少插件把设置存成序列化数组,这一点很重要。

插件可以从 WordPress 后台的插件市场安装,认准名称 Better Search Replace,作者是 WP Engine。WordPress 官方插件目录列出的免费版已经支持序列化数据、指定数据表和 dry run,普通的域名替换不需要先买 Pro。

第一步:备份后再安装

先导出一份当前数据库,而且要确认这个 SQL 文件能下载、能打开。数据库很重要的站点,我还会在主机面板再做一个快照。

然后进入 插件 > 安装插件,搜索 Better Search Replace,安装并启用。启用后进入 工具 > Better Search Replace。有些中文翻译会把页面直接显示成“搜索/替换”。

最好在已经复制到新服务器的站点上操作。WooCommerce、会员站和论坛在正式执行前要暂停下单、注册和评论,避免替换过程中又写入新数据。只是换服务器、域名完全没变时,不要为了“保险”多跑一次替换。

第二步:填写完整的旧地址和新地址

假设原地址是:

text已剪下 ✓
https://old.example.com

新地址是:

text已剪下 ✓
https://new.example.com

就在“搜索”中填第一行,在“替换为”中填第二行。两边都使用完整协议,结尾都不要随手多加 /。如果旧站曾同时出现下面几种地址,要把它们分成几次处理,每次都先 dry run:

text已剪下 ✓
http://old.example.com
https://old.example.com
https://www.old.example.com

不要只搜索 old.example.com,也不要把搜索词缩短成 old。搜索范围越含糊,误改邮箱、日志、API 参数和普通文字的可能性越高。

第三步:选对数据表

表格列表支持多选。Windows 按住 Ctrl,macOS 按住 Command,再点击需要处理的表。

独立 WordPress 数据库通常可以选择当前站点的全部表,包括 Elementor、WoodMart、WooCommerce 和其他插件创建的表。它们不一定都叫 wp_ 开头,实际前缀以 wp-config.php 里的 $table_prefix 为准。

如果一个数据库里放了多个网站,只选择当前站点对应前缀的表,不要顺手全选。多站点安装也要先确认本次是只迁一个子站,还是整个 Network;拿不准时宁可用 WP-CLI 或主机迁移工具,不要在生产库里试。

第四步:三个选项怎么勾

Better Search Replace 的搜索替换和 dry run 设置

截图里的三个选项,域名迁移时我通常这样设置:

插件官方文档也特别提醒,WordPress 通常不建议修改 GUID。只有从未正式上线的临时开发站,才可能有修改 GUID 的例外情况。普通搬家不要把这个例外当成默认操作。

第五步:先跑一次 dry run

确认搜索值、替换值和表格以后,保持 Run as dry run 勾选,点击“运行搜索/替换”。完成后先看这三件事:

  1. 命中的表是不是本次迁移的表;
  2. 命中数量是不是大致合理;
  3. 有没有完全没想到会出现旧域名的表。

命中为零时不要立刻改成模糊搜索。先检查协议、www、结尾斜线和数据库表是否选对。命中数大得离谱,也先停下来,检查是不是把搜索内容写得太短。

免费版会给出各表的命中和更新数量,Pro 版可以进一步查看具体变更。普通迁移不必为了正式执行而升级,但无论什么版本,都不能用 dry run 代替备份。

第六步:正式替换

dry run 的结果没有问题后,再核对一次数据库备份,然后取消勾选 Run as dry run,其他内容保持不变,重新点击“运行搜索/替换”。这一次才会真正写库。

执行时不要关闭页面,也不要同时开另一个窗口重复点击。数据库较大时可能需要更久。如果遇到超时或 500,不要默认它“完全没执行”,也不要立刻从头再跑。先重新做一次 dry run 查看还剩哪些命中;数据量很大时按表分批处理,或者改用 WP-CLI。无法判断数据库已经改到哪一步时,最稳妥的办法仍然是恢复刚才的备份再来。

第七步:替换完成后检查残留

正式执行后,用旧地址再做一次 dry run。残留不一定都是错误:GUID、历史订单备注、日志和第三方回调记录有时本来就应该保留。先看它在哪张表、属于什么数据,再决定是否处理。

接下来还要做迁移后的常规收尾:

Better Search Replace 的官方操作说明列出了搜索值、表格选择、GUID 和 dry run 的含义;WordPress 官方插件页也说明它支持所有表中的序列化数据。它确实比手写 SQL 安全,但“支持序列化”不等于“随便填什么都不会出错”,搜索内容、数据表和备份仍然要自己负责。

不建议把来历不明的数据库替换 PHP 脚本长期放在公开目录。它能改 WordPress 数据,也意味着一旦被别人访问,可能改掉或读取整套数据库。

几个常见问题

只换服务器,需要执行 search-replace 吗?

域名、协议和安装目录都不变时通常不需要。用 hosts 文件测试新服务器,确认后切 DNS 即可。

wp_options 里的 home 和 siteurl 不就行了吗?

这只能让 WordPress 知道入口地址,文章、媒体、Widget、Elementor 和插件数据里的旧 URL 仍然存在。它可以用来临时恢复后台,不是完整迁移方案。

WordPress 表前缀不是 wp_ 会影响 WP-CLI 吗?

不会。WP-CLI 会读取 wp-config.php 里的 $table_prefix--all-tables-with-prefix 也会按实际前缀工作。

WoodMart 设置已经变成默认值,还能救吗?

先别继续保存主题设置。检查迁移前的数据库和 WoodMart 导出备份,再确认 WoodMart Core 版本、页面构建器和缓存。继续保存默认值,反而可能覆盖还能恢复的数据。

什么时候可以关掉旧服务器?

等 DNS 缓存基本结束、订单和外部回调正常、日志没有持续报错,并且确认备份真的能恢复之后。电商站宁可多保留几天只读旧站,也不要急着释放服务器。

最后说一句

WordPress 搬家真正麻烦的不是复制文件,而是数据库里那些看不见的配置,以及切换期间仍在发生的写入。

同域名迁服务器时少做一点,往往更安全;换域名时则应该用序列化感知工具,先 dry-run,再执行。Elementor、WoodMart 和 WooCommerce 各自还有一轮检查,不能指望几条 SQL 包办所有事情。

迁移前可以再对照 WordPress 官方迁移指南WP-CLI search-replace 文档。命令并不难,真正需要谨慎的是替换范围、停写时间和回滚路径。