
WordPress 换域名后,首页和文章页面可能已经能通过新域名访问,但正文图片、媒体库附件、菜单链接或页面构建器里的资源仍然指向旧地址。常见表现包括图片加载失败、浏览器出现混合内容警告、旧域名仍有流量,或者停用旧域名后大量页面突然缺图。
这类问题通常不是图片文件没有搬过去,而是数据库和缓存中仍保存着旧域名。只修改后台“WordPress 地址”和“站点地址”只能改变站点入口,不能自动改写历史文章、附件字段和插件配置。下面按风险较低的顺序处理,并提供替换前检查、WP-CLI 预演、正式替换和结果验证方法。
先确认是地址残留,还是图片文件没有迁移
先在浏览器中打开一篇缺图文章,检查图片的实际请求地址。如果 img src、srcset 或 CSS 背景图仍以旧域名开头,问题主要在数据库或缓存。如果地址已经是新域名,但返回 404,则应先检查 wp-content/uploads 是否完整迁移、文件权限是否正确,以及新站点是否保留了原来的年月目录结构。
还可以在服务器上抽查媒体文件:
find wp-content/uploads -type f | head
不要一看到缺图就立即全库替换。先分清“URL 没改”和“文件不存在”,否则替换完成后仍然会得到一批指向新域名的 404 地址。
为什么只改 WordPress 地址仍然不够
WordPress 后台“设置 > 常规”中的两个地址分别对应 home 和 siteurl。它们决定前台访问地址和 WordPress 核心文件所在地址,但历史内容中的绝对链接不会因此自动变化。
旧域名通常还会出现在以下位置:
wp_posts.post_content中的图片、下载地址和站内链接;- 附件、页面构建器和插件保存的元数据;
- 主题选项、小工具、菜单和自定义 CSS;
- 响应式图片使用的
srcset; - 页面缓存、对象缓存、CDN 缓存或浏览器缓存;
- 写死在主题文件、子主题或自定义插件里的地址。
部分插件会把配置保存为 PHP 序列化数据。序列化字符串包含字符长度,直接执行普通 SQL REPLACE() 可能改了域名,却没有同步长度信息,最终导致配置无法反序列化。因此不建议把“全库 SQL 替换”作为首选方案。
操作前先备份数据库和上传目录
域名替换属于批量写操作。开始前至少保留一份数据库备份,并确认备份文件能够读取。如果这次迁移还涉及媒体文件,也应备份 wp-content/uploads。
使用 WP-CLI 可以导出数据库:
wp db export before-domain-replace.sql
同时记录当前地址,避免把新旧域名方向写反:
wp option get home
wp option get siteurl
如果站点安装在子目录,或使用反向代理、负载均衡和多站点网络,不要仅凭浏览器地址猜测替换目标,应先确认 WordPress 实际配置和数据库表范围。
先修正 home 和 siteurl
如果后台还能正常登录,可以在“设置 > 常规”中修改。无法进入后台时,可使用 WP-CLI:
wp option update home 'https://new.example.com'
wp option update siteurl 'https://new.example.com'
这里的 new.example.com 只是示例,请替换为实际新域名。若 WordPress 核心文件安装在子目录,siteurl 可能与 home 不同,不要机械地设置成相同值。
执行后重新登录后台。如果出现循环跳转,检查 HTTPS、反向代理传递的协议头、浏览器 Cookie,以及 wp-config.php 中是否写死了 WP_HOME 或 WP_SITEURL。
用 WP-CLI 预演数据库替换
正式修改前先运行 --dry-run。它只统计可能发生的替换,不写入数据库:
wp search-replace 'https://old.example.com' 'https://new.example.com' \
--all-tables-with-prefix \
--skip-columns=guid \
--precise \
--dry-run
几个参数分别解决不同问题:
--all-tables-with-prefix:检查当前 WordPress 表前缀下的全部表,包括插件创建的表;--skip-columns=guid:避免修改文章与附件的 GUID;--precise:使用 PHP 方式处理数据,速度可能更慢,但更适合包含复杂或序列化数据的站点;--dry-run:先查看命中数量,不执行写入。
预演后重点看命中的表和数量。如果结果异常大,先检查是否把短域名、测试域名或协议写得过于宽泛。建议分别处理 http://old.example.com、https://old.example.com 和可能存在的 www 版本,而不是只搜索一段不带协议的域名。
确认无误后执行正式替换
预演结果合理后,去掉 --dry-run:
wp search-replace 'https://old.example.com' 'https://new.example.com' \
--all-tables-with-prefix \
--skip-columns=guid \
--precise
如果旧站同时存在 HTTP 和 HTTPS,可以分两次执行:
wp search-replace 'http://old.example.com' 'https://new.example.com' \
--all-tables-with-prefix --skip-columns=guid --precise
wp search-replace 'https://old.example.com' 'https://new.example.com' \
--all-tables-with-prefix --skip-columns=guid --precise
多站点环境需要先确认网络结构、站点 ID 和表范围。不要在没有备份的情况下直接对整个数据库使用宽泛替换,也不要把第三方接口地址、对象存储域名或外部图片域名误改成本站域名。
清理缓存并刷新固定链接
数据库已经替换,但页面源代码仍出现旧域名,通常是缓存没有失效。依次处理:
- 清除 WordPress 缓存插件生成的页面缓存;
- 清除 Redis、Memcached 等对象缓存;
- 清除服务器端 FastCGI 或反向代理缓存;
- 刷新 CDN 缓存;
- 清除浏览器缓存或使用无痕窗口验证。
使用 WP-CLI 时,可尝试:
wp cache flush
wp rewrite flush
wp cache flush 只负责 WordPress 能访问到的对象缓存,不一定会清除 CDN、Nginx FastCGI 或缓存插件保存的静态文件。wp rewrite flush 用于刷新重写规则,它不是图片 URL 替换工具,但迁移后出现文章 404 时可以一并检查。
检查主题、插件和页面构建器中的硬编码
如果数据库搜索已经没有旧域名,页面仍继续请求旧地址,应检查代码文件和生成文件:
grep -R "old.example.com" wp-content/themes wp-content/plugins \
--exclude-dir=node_modules --exclude-dir=vendor
重点查看子主题、自定义插件、主题设置导出的 CSS,以及页面构建器生成的静态 CSS 文件。部分页面构建器提供自己的“替换 URL”或“重新生成 CSS”功能,完成数据库替换后还需要在插件工具页重新生成资源。
如果媒体文件使用对象存储或独立 CDN,旧地址不一定是错误。应先确认资源是否仍由该域名承载,再决定是否替换,避免把正常的静态资源域名改回主站。
替换完成后这样验证
不要只打开首页看一眼。至少检查以下几类页面:
- 一篇较早发布且包含多张图片的文章;
- 媒体库中的原图和缩略图;
- 使用页面构建器制作的页面;
- 菜单、侧栏、页脚和下载链接;
- 移动端页面以及带
srcset的响应式图片; - 浏览器开发者工具中的 Network 和 Console。
还可以再次执行预演,把目标地址换成一个不会实际使用的占位域名,用它统计是否仍有残留:
wp search-replace 'old.example.com' 'migration-check.invalid' \
--all-tables-with-prefix --skip-columns=guid --dry-run
如果命中数量不为零,根据报告定位具体表,再判断它是需要清理的历史地址,还是日志、备份记录和第三方配置中的正常内容。
旧域名不要立刻停用
确认新站正常后,旧域名最好保留一段过渡时间,并配置到新域名的一对一 301 跳转。这样既能承接旧链接,也方便发现遗漏资源。跳转应尽量保留原路径和查询参数,不要把所有请求都重定向到新首页。
最终可以用一个简单标准判断迁移是否完成:新域名能正常访问,旧页面能正确跳转,页面源代码和网络请求中不再出现误用的旧域名,媒体文件没有新增 404,后台编辑和上传图片也都正常。达到这些条件后,再考虑下线旧站和旧域名解析。




