WordPress 固定链接 404 怎么排查?重写规则与伪静态修复
WordPress 固定链接 404 最容易被一句“去后台重新保存固定链接”带过去,但这个动作只适合重写规则没有刷新这一类问题。如果真正断在 Nginx、Apache、页面层级、旧 slug 或缓存,反复保存设置并不会修好,甚至可能掩盖故障发生在哪一层。
我更习惯先用同一篇文章的“美化 URL”和 ?p=文章ID 做对照,再判断是单个地址、WordPress 内部规则,还是 Web 服务器转发出了问题。下面这套流程适合文章和页面打开 404、迁移后伪静态失效,以及插件注册的新内容类型突然无法访问等场景。
先判断:到底是哪一种 404
不要一上来改配置。先找一篇确定已经发布的文章,分别请求它的正常链接和 Plain Permalink:
curl -I https://example.com/sample-post/
curl -I "https://example.com/?p=123"
| 现象 | 优先怀疑 | 下一步 |
|---|---|---|
美化 URL 404,?p=123 正常 | 服务器重写或 WordPress rewrite rules | 检查固定链接结构、重写规则和服务器配置 |
| 只有一篇文章或一个页面 404 | slug、父级页面、发布状态或路径冲突 | 核对对象本身,不要先动全站规则 |
| 文章、页面、分类等美化 URL 全部 404 | Nginx/Apache 没把请求交给 WordPress | 检查 try_files、.htaccess 和站点根目录 |
| 前台同时出现 500、白屏或 PHP 报错 | 已不是单纯固定链接问题 | 转到错误日志与插件、主题排查 |
| 只有图片 URL 404 | uploads 文件、旧域名或缩略图路径 | 按媒体迁移链路检查 |
如果问题只出现在图片,不要把它当成固定链接故障。可以按我之前整理的 WordPress 迁移后图片不显示排查流程,继续检查 URL、磁盘文件和附件记录。若同时有 500 或白屏,则先看 WP_DEBUG 与错误日志的安全排查方法。
检查 WordPress 固定链接结构和内部重写规则
有 SSH 和 WP-CLI 时,先只读查看当前结构,不要直接执行 flush:
wp option get permalink_structure
wp rewrite list --match=sample-post --fields=match,query,source --format=table
wp rewrite list --format=count
第一条应该返回类似 /%postname%/ 的结构。第二条用于确认某个请求能匹配到哪条规则;第三条只是快速判断规则列表是否为空,数量本身没有统一的“正常值”,因为插件和自定义文章类型都会增加规则。
本站在本次只读检查中使用 WordPress 7.0.4、PHP 8.4.10 和 Nginx,固定链接结构为 /%postname%/,当前注册了 287 条 rewrite rules。用一篇已发布文章的 slug 测试时,WP-CLI 同时匹配到了页面与文章规则,而公开 URL 返回 200,说明 WordPress 内部规则与服务器转发链路当前都是连通的。这个数字只作为本次环境基线,不能复制到别的网站当标准答案。
后台“固定链接”页面能修什么,不能修什么
WordPress 官方文档说明,访问“设置 → 固定链接”页面本身就会触发 rewrite rules 刷新,并不一定要为了刷新而改动结构或反复点击保存。它可以处理插件启用、自定义文章类型改动或迁移后,数据库里的规则没有及时重建这类问题。
但它不能自动修复下面这些情况:
- Nginx 的站点配置没有把不存在的静态路径交给
index.php; - Apache 没有启用
mod_rewrite,或站点根目录不允许读取.htaccess; - WordPress 实际安装目录、
home与 Web 服务器的root不一致; - 页面的 slug、父级路径、语言前缀或自定义文章类型 rewrite 发生冲突;
- CDN、整页缓存或旧重定向仍在返回之前的 404。
因此,刷新后应该立刻复测原 URL。如果现象没有变化,就继续往服务器和对象本身查,不要把“再保存一次”当成新的诊断步骤。
Nginx 站点为什么没有 .htaccess
这是客户项目里很常见的误区:教程要求修改 .htaccess,但服务器根目录根本找不到这个文件。如果站点使用独立 Nginx,这通常是正常现象。Nginx 没有 Apache 那种目录级 .htaccess 机制,WordPress 也不能替你修改 Nginx 的服务器配置。
WordPress 官方 Nginx 示例的核心是让不存在的文件和目录回落到 index.php:
location / {
try_files $uri $uri/ /index.php?$args;
}
这只是单站点、安装在域名根目录时的典型写法。使用子目录、多站点、反向代理或主机商面板时,真实配置可能不同。修改前应备份配置并执行 nginx -t,确认语法通过后再由有权限的管理员平滑重载;共享主机没有权限时,应把“美化 URL 404、Plain Permalink 正常”的对照结果交给主机商处理。
Apache 站点重点检查 .htaccess 与 mod_rewrite
Apache 环境中,Pretty Permalinks 通常依赖 mod_rewrite 和 WordPress 根目录下的 .htaccess。如果 Plain Permalink 正常而所有美化 URL 都 404,重点核对:
.htaccess是否位于当前 WordPress 对外提供访问的根目录;- 文件中 WordPress 标记区块是否完整,而不是被部署或安全工具覆盖;
- Apache 是否加载
mod_rewrite; - 站点目录是否允许
AllowOverride使用重写规则; - WordPress/PHP 运行用户是否在需要更新时具备合理权限。
不要为了让后台显示“可写”就把文件或整个站点目录改成 777。权限问题应该按所有者、用户组和最小可写范围处理;如果规则已经正确,继续放宽权限不会解决 404,只会扩大安全风险。
只有一个 URL 404 时怎么查
全站其他文章正常,说明服务器转发和大部分 rewrite rules 已经工作。此时优先检查对象本身:
- 状态:文章是否已发布,是否被设为私密、定时或草稿;
- slug:当前 slug 与浏览器访问路径是否一致,是否刚改过但缓存还在;
- 层级:页面的父级是否改变,父页面 slug 是否也在 URL 中;
- 冲突:是否同时存在同名页面、分类基础、自定义文章类型或插件 endpoint;
- 旧地址:迁移或改 slug 后是否需要 301,而不是让旧链接继续 404;
- 缓存:源站已恢复,但 CDN、Nginx fastcgi_cache 或缓存插件仍保存旧响应。
还可以用 WP-CLI 确认对象和规则,而不是只看后台标题:
wp post get 123 --fields=ID,post_status,post_type,post_name,post_parent,url
wp rewrite list --match=sample-post --fields=match,query,source --format=table
什么时候才执行 wp rewrite flush
确认服务器转发正常、对象也存在,但规则列表缺失或插件注册规则刚发生变化时,才考虑刷新:
wp rewrite flush
先做数据库备份,并在低流量时执行一次即可。wp rewrite flush --hard 会尝试更新服务器重写文件,是否有效取决于环境;Nginx 不会因为这个参数自动生成可用的站点配置。更不要把 flush 放进每次请求、主题模板或高频定时任务里,规则刷新是维护动作,不是正常页面渲染的一部分。
一套可复用的 WordPress 固定链接 404 排查顺序
- 记录失败 URL、发生时间和 HTTP 状态,不先改设置。
- 用同一内容的美化 URL 与
?p=ID做对照。 - 确认是单个对象、某类内容,还是所有 Pretty Permalinks 失败。
- 只读检查
permalink_structure和匹配到的 rewrite rules。 - 访问固定链接设置页触发一次规则刷新,然后立即复测。
- 根据服务器类型检查 Nginx
try_files或 Apache.htaccess/mod_rewrite。 - 单 URL 故障继续查状态、slug、父级、冲突和旧地址重定向。
- 源站恢复后定向清理该 URL 与相关归档缓存,再复测外部访问。
- 确认日志、站点地图和内部链接没有继续引用错误地址。
总结
处理 WordPress 固定链接 404,关键不是“刷新几次”,而是先判断请求断在对象、WordPress rewrite rules、Web 服务器还是缓存层。美化 URL 404而 ?p=ID 正常,是最有用的第一条证据;Nginx 没有 .htaccess 也不是异常。按层排查后只修对应环节,通常比停插件、改权限或反复保存固定链接更快,也更容易回滚。
参考资料:WordPress.org《Customize permalinks》、WordPress.org《Settings Permalinks screen》、Developer.WordPress.org《wp rewrite》、Developer.WordPress.org《Nginx》




