WordPress 网站迁移怎么做才稳?别再直接用 SQL 替换域名
解释普通 SQL 替换为何会破坏 Elementor、WoodMart 等序列化设置,并给出备份、WP-CLI、Better Search Replace、WooCommerce 切换与回滚步骤。
这篇文章以前写得太省事了。
旧版的思路是:打包文件、导出数据库、上传到新服务器,再用几条 SQL 把旧域名换成新域名。前面几步没有大问题,最后那几条 REPLACE() 却不应该继续推荐。
原因也不复杂。现在的 WordPress 很少只是文章和图片。Elementor、WoodMart、WooCommerce 以及不少表单、缓存和多语言插件,都会把配置存在 wp_options、wp_postmeta 或自己的数据表里,其中有些还是 PHP 序列化数据。普通 SQL 只会替换文字,不知道这些数据还有长度信息,换完域名以后可能直接读不出来。
所以这次把文章重写一遍。不是把步骤写得更多,而是把真正容易出问题的地方讲清楚。
旧办法为什么会把主题设置弄丢
先看一个简化后的序列化值:
a:1:{s:7:"siteurl";s:23:"https://old.example.com";}s:23 表示后面的字符串长度是 23。假如直接执行 SQL:
UPDATE wp_options
SET option_value = REPLACE(
option_value,
'https://old.example.com',
'https://shop.example.com'
);域名已经变长了,s:23 却不会跟着更新。PHP 再反序列化这条记录时就可能失败。
这类问题很容易让人误判。网站通常不会彻底白屏,而是出现一些看似无关的现象:
- WoodMart 的 Header、商店布局或颜色回到默认值;
- Elementor 页面还在,但背景图、字体或生成的 CSS 不对;
- Widget、菜单位置、插件设置少了一部分;
- 后台没有明确错误,只是前台看起来像“配置没保存”。
WordPress 官方迁移文档也专门提醒过序列化问题。换域名时应该使用能识别序列化结构的工具,而不是对 SQL 文件或数据库做普通文本替换。
先分清楚:你到底需不需要换 URL
这一步能省掉很多没必要的操作。
只是换服务器,域名不变
例如 https://example.com 从一台云服务器搬到另一台,域名、HTTPS 和 WordPress 所在目录都没变。这种情况通常不需要替换数据库里的 URL。
把文件和数据库复制过去,改好新服务器的数据库连接,然后在自己电脑的 hosts 文件里临时加入:
203.0.113.20 example.com www.example.com只有你的电脑会访问新服务器,其他访客仍在旧站。因为浏览器地址仍然是真实域名,Cookie、绝对链接和 HTTPS 都能按上线后的状态测试。
测试通过后再切 DNS。这个办法比把站点临时改成 IP 地址或测试域名干净得多,也不会制造第二轮 URL 替换。
域名、协议或目录发生变化
下面这些情况才需要做数据库替换:
old.example.com换成new.example.com;- HTTP 升级为 HTTPS;
- WordPress 从
/wordpress/移到网站根目录; - 测试站迁到正式域名。
这时应该用 WP-CLI 的 search-replace,或者使用明确支持序列化数据的迁移工具。
搬之前,先把能恢复的备份做好
WordPress 的完整备份有两部分:数据库和网站文件。只备份其中一个都不够。
数据库里有文章、订单、用户和绝大多数设置;文件里有上传图片、主题、插件、wp-config.php、.htaccess 和定制代码。WordPress 的官方备份说明也建议把两者当作同一套备份保存。
有 WP-CLI 时,可以这样导出数据库:
cd /var/www/example.com
wp db export ~/backups/example-before-migration.sql --add-drop-table没有 WP-CLI 也可以用 MySQL:
mysqldump \
--single-transaction \
--quick \
--default-character-set=utf8mb4 \
-u OLD_DB_USER -p OLD_DB_NAME \
> ~/backups/example-before-migration.sql
文件可以打包:
cd /var/www/example.com
tar -czf ~/backups/example-files.tar.gz .
这里有两个常被忽略的细节:
wp-content/uploads之外可能还有插件自己创建的存储目录;- 备份文件存在不代表能恢复,至少要确认压缩包能打开、SQL 不是空文件,重要站点最好在临时环境导入一次。
迁移前也顺手记下 PHP、MySQL、WordPress、主题和插件版本。新服务器少了某个 PHP 扩展时,表现出来可能像迁移失败,其实只是运行环境不同。
把文件和数据库放到新服务器
小站用压缩包上传没有问题。文件较多时我更推荐 rsync,因为第一次复制完之后还能再执行,只同步有变化的文件:
rsync -a --info=progress2 \
old-server:/var/www/example.com/ \
/var/www/example.com/源目录最后的 / 不要漏,它表示复制目录里的内容。
新数据库不需要和旧数据库同名。这是旧文里的另一个错误。WordPress 最终只看 wp-config.php:
define('DB_NAME', 'new_wordpress');
define('DB_USER', 'new_wordpress_user');
define('DB_PASSWORD', '使用独立强密码');
define('DB_HOST', 'localhost');只要目标数据库已经创建,直接导入即可:
mysql -u NEW_DB_USER -p NEW_DB_NAME \
< ~/backups/example-before-migration.sql或者:
wp db import ~/backups/example-before-migration.sql
不要为了让数据库同名而全局编辑 SQL 文件。普通 mysqldump OLD_DB_NAME > backup.sql 通常并不要求导入到同名数据库。
文件复制后再按服务器实际用户修正权限。不要用 chmod -R 777 解决问题,那只是把权限问题变成安全问题。
换域名时,用 WP-CLI 做安全替换
下面的命令先在新服务器上运行,而且第一遍一定保留 --dry-run:
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先看它准备改哪些表、命中多少条。如果结果合理,再去掉最后一行执行正式替换:
wp search-replace \
'https://old.example.com' \
'https://new.example.com' \
--all-tables-with-prefix \
--skip-columns=guid \
--precise \
--recurse-objects \
--report-changed-only这几个参数不是为了让命令显得复杂:
--all-tables-with-prefix会把同前缀的插件表算进去;--skip-columns=guid避免修改wp_posts.guid;--precise使用更彻底但更慢的 PHP 处理;--recurse-objects会递归处理对象;--dry-run只报告,不写入。
WP-CLI 的官方命令文档明确说明它会处理 PHP 序列化数据。
为什么要跳过 GUID?因为它是文章或附件的稳定标识,不是给访客点击的链接。换域名不等于内容变成了一篇新文章。直接修改 GUID 可能让 RSS 阅读器重新识别旧内容。
旧站如果同时用过 HTTP、HTTPS、带 www 和不带 www,不要图省事只替换 old.example.com。先分别 dry-run,确认每种完整 URL 的命中范围,再逐个处理。搜索词太短,很容易碰到邮箱、日志或本来不该改的文本。
执行后可以查一次残留:
wp db search 'old.example.com' --all-tables-with-prefix查到旧域名也不要立刻全改。历史订单备注、日志、GUID 和第三方回调记录有时就应该保留。
Elementor 和 WoodMart 还要再做什么
数据库替换正确,不代表页面构建器生成的文件和缓存也已经更新。
Elementor
换域名后进入 Elementor > Tools > Replace URL,填入完整的旧 URL 和新 URL。然后执行 Regenerate Files & Data,重新生成 CSS 和数据文件。
接着检查:
- 全局字体和全局颜色;
- Theme Builder 的 Header、Footer 和 Single 模板;
- Popup、表单跳转和自定义 CSS;
- 背景图与自定义字体是否还有旧域名;
- Elementor Pro 许可证是否需要重新绑定。
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 可以把它们安全合并。
上线前至少测试这些项目:
- 创建订单、付款、退款和取消;
- 库存扣减与恢复;
- 优惠券、运费和税率;
- 订单邮件与管理员通知;
- 支付平台 Webhook;
- WooCommerce Scheduled Actions;
- 登录用户的购物车和账户页面。
业务完全不能停写时,应该使用支持增量同步的托管迁移服务,或者单独设计数据库复制方案,而不是照搬普通博客教程。
固定链接、缓存和 HTTPS
如果迁移后首页正常、内页全部 404,先检查 Web 服务器规则。
Nginx 根目录安装常见配置是:
location / {
try_files $uri $uri/ /index.php?$args;
}Apache 则要确认 .htaccess 已复制,mod_rewrite 和 AllowOverride 正常。之后进 设置 > 固定链接 保存一次即可。不要一遇到 404 就去改数据库。
缓存要从里面往外清:Elementor 或主题生成文件、WordPress 页面缓存、Redis/Memcached、服务器缓存、CDN,最后才是浏览器。只清浏览器,服务器仍然可能继续发旧 HTML。
HTTPS 也不要等 DNS 切完才处理。尽量提前准备证书,并在 hosts 测试时检查混合内容、字体、图片和第三方脚本。
切 DNS 之前,我会实际点一遍这些地方
只看首页没有意义。至少要检查:
- 登录、退出、找回密码和后台编辑;
- 文章、分类、搜索、分页和 404;
- 图片、字体、下载文件和手机端布局;
- Header、Footer、菜单、弹窗和表单;
- 商品筛选、变体、购物车和结账;
- 邮件、支付回调、计划任务和第三方接口;
- 301、canonical、robots.txt 和 sitemap;
- PHP、Nginx/Apache 日志以及浏览器控制台。
换域名时,旧网址应该逐路径 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、会员站和论坛在正式执行前要暂停下单、注册和评论,避免替换过程中又写入新数据。只是换服务器、域名完全没变时,不要为了“保险”多跑一次替换。
第二步:填写完整的旧地址和新地址
假设原地址是:
https://old.example.com新地址是:
https://new.example.com就在“搜索”中填第一行,在“替换为”中填第二行。两边都使用完整协议,结尾都不要随手多加 /。如果旧站曾同时出现下面几种地址,要把它们分成几次处理,每次都先 dry run:
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 或主机迁移工具,不要在生产库里试。
第四步:三个选项怎么勾

截图里的三个选项,域名迁移时我通常这样设置:
- Case-Insensitive:不勾。URL 应该按准确字符串替换,没有必要放宽成不区分大小写;
- Replace GUIDs:不勾。已经上线的网站不应因为换域名就改写
wp_posts.guid; - Run as dry run:第一次必须勾上。它只计算命中范围,不会写入数据库。
插件官方文档也特别提醒,WordPress 通常不建议修改 GUID。只有从未正式上线的临时开发站,才可能有修改 GUID 的例外情况。普通搬家不要把这个例外当成默认操作。
第五步:先跑一次 dry run
确认搜索值、替换值和表格以后,保持 Run as dry run 勾选,点击“运行搜索/替换”。完成后先看这三件事:
- 命中的表是不是本次迁移的表;
- 命中数量是不是大致合理;
- 有没有完全没想到会出现旧域名的表。
命中为零时不要立刻改成模糊搜索。先检查协议、www、结尾斜线和数据库表是否选对。命中数大得离谱,也先停下来,检查是不是把搜索内容写得太短。
免费版会给出各表的命中和更新数量,Pro 版可以进一步查看具体变更。普通迁移不必为了正式执行而升级,但无论什么版本,都不能用 dry run 代替备份。
第六步:正式替换
dry run 的结果没有问题后,再核对一次数据库备份,然后取消勾选 Run as dry run,其他内容保持不变,重新点击“运行搜索/替换”。这一次才会真正写库。
执行时不要关闭页面,也不要同时开另一个窗口重复点击。数据库较大时可能需要更久。如果遇到超时或 500,不要默认它“完全没执行”,也不要立刻从头再跑。先重新做一次 dry run 查看还剩哪些命中;数据量很大时按表分批处理,或者改用 WP-CLI。无法判断数据库已经改到哪一步时,最稳妥的办法仍然是恢复刚才的备份再来。
第七步:替换完成后检查残留
正式执行后,用旧地址再做一次 dry run。残留不一定都是错误:GUID、历史订单备注、日志和第三方回调记录有时本来就应该保留。先看它在哪张表、属于什么数据,再决定是否处理。
接下来还要做迁移后的常规收尾:
- 进入 设置 > 固定链接 保存一次;
- Elementor 执行 Replace URL 和 Regenerate Files & Data;
- 清理主题、页面缓存、Redis、服务器缓存和 CDN;
- 检查首页、内页、图片、菜单、表单、购物车和结账;
- 查看页面源代码和浏览器控制台,确认没有继续请求旧域名;
- 确认站点正常后停用并删除 Better Search Replace,减少后台里不常用的数据库工具。
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 文档。命令并不难,真正需要谨慎的是替换范围、停写时间和回滚路径。