WordPress 404 处理:页面模板、插件与伪静态失效
404 有两种。一种是链接真的失效了,返回 404 是对的;另一种是页面明明在,访问却是 404,那就是配置问题。这两种要分开处理,混在一起查会绕远路。
判断方法很简单:后台「页面」或「文章」列表里能找到这篇内容,前台访问却 404,属于配置;后台也找不到,属于内容没了。前者查伪静态和固定链接,后者查 301 和 404 页面。
先确认 404 是谁返回的
看页面长相就知道。如果页面是自己主题的 404 模板,有导航、有搜索框,说明请求已经进了 WordPress,是 WP 自己判断 is_404;如果页面是 nginx 或 Apache 的默认错误页,白底黑字写着 Not Found,说明请求根本没到 PHP,rewrite 没生效。这两种往完全不同的方向查。
| 现象 | 常见原因 | 处理 |
|---|---|---|
| 所有内页 404,首页正常 | 伪静态规则没写,或写了但没生效 | nginx 加 try_files;Apache 检查 .htaccess 与 AllowOverride |
| 新发布的文章 404,老文章正常 | 固定链接规则未刷新,或缓存没清 | 进「设置 → 固定链接」直接点保存 |
| 改过 slug 之后 404 | 旧地址失效,没做 301 | 旧地址 301 到新地址 |
| 文章第二页 /page/2/ 404 | 文章总数不足两页,或分页参数被查询覆盖 | 核对每页篇数与 $wp_query->max_num_pages |
| 分类页 /category/xxx/ 404 | 分类别名与页面 slug 撞车,或自定义文章类型的 rewrite 冲突 | 改掉其中一个 slug,再刷新固定链接 |
固定链接规则没生效
WordPress 的固定链接不是真实目录,全靠 rewrite 规则。规则存在数据库 wp_options 的 rewrite_rules 字段里,切换主题、迁移站点、换 web 服务器、换域名,都可能让它失效。最直接的修复是进「设置 → 固定链接」,什么都不改,直接点「保存更改」,WordPress 会重新生成一遍规则。
保存后还是 404,就看服务器层。nginx 需要这一段,放在 server 块里:
location / {
try_files $uri $uri/ /index.php?$args;
}
Apache 需要 .htaccess 里这段,同时虚拟主机的 AllowOverride 必须是 All,否则 .htaccess 会被完全忽略,文件写得再对也没用:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
再补一个判断:用 ?p=123 这种朴素链接访问同一篇文章。能打开说明 WordPress、数据库、主题都正常,问题 100% 在 rewrite;打不开说明是内容本身或权限问题,别再折腾伪静态。另外,如果站点放在子目录,RewriteBase 要跟着改,很多人从这里开始错。
还有一种容易被忽略的情况:服务器前面挂了 CDN 或反向代理,源站规则是对的,但 CDN 缓存了一条 404 响应,清缓存之前怎么改都是 404。这类问题看响应头里的缓存命中标记就能确认。
页面真被删了,和翻页 404
内容被删好办,后台回收站里找,30 天内都能还原。要注意的是「改 slug」等于删掉了旧地址,搜索引擎和外部链接都会打到 404。有外链的文章改完 slug 之后,一定补一条 301。
翻页 404 是老问题。WordPress 默认 /page/2/ 只在文章数超过「设置 → 阅读 → 博客页面至多显示」时才存在。每页 10 篇、只有 8 篇,访问 /page/2/ 就是 404,这是正确行为,不用修。另一种是模板里的自定义循环用了 offset 或者自己写了 posts_per_page,导致分页计算和实际查询对不上,第 2 页开始全 404。检查方法是在模板里打印两个值:
echo $wp_query->max_num_pages;
echo $wp_query->found_posts;
两个值不一致,说明查询被改过。用 pre_get_posts 调整主查询,不要用 query_posts,那会破坏全局分页状态,翻页 404 大半是它造成的。
分类页 404 多发生在两种场景:分类的 slug 和某个页面的 slug 完全相同,或者注册自定义文章类型时 rewrite 的 slug 和已有分类撞车。改掉其中一个,再刷新固定链接即可。整站 404 通常出现在迁移之后,多半是数据库里的旧域名没替换,或者新服务器的 rewrite 规则没同步,可以对照 迁移搬家 的检查清单过一遍。
还有两类容易被误判成「伪静态坏了」的 404。一是中文别名:WordPress 允许文章别名写中文,真实 URL 会被百分号编码,复制粘贴时被二次编码或者被聊天工具截断,访问就是 404,这类地址建议统一改成英文或拼音。二是大小写:Linux 服务器区分大小写,/About/ 和 /about/ 是两个地址,别名里带大写字母时,别人手打小写就 404,需要额外加一条忽略大小写的重定向规则。末尾斜杠也是同理,/about 和 /about/ 在部分服务器配置下只有一种能通,固定链接结构定好后不要中途改带不带斜杠。
404 页面模板怎么做
主题根目录的 404.php 就是 404 模板。没有的话 WordPress 会退回 index.php,页面看起来完全正常,很容易让人误判成「没配 404」。做一个合格的 404 页要满足三点:
- 返回真正的 404 状态码,不要 301 跳首页。跳首页叫软 404,搜索引擎会认为这个地址长期有效,最后把一堆无效 URL 都算成首页的重复内容。
- 给出搜索框、热门文章、分类入口,让人能继续往下走,而不是直接关掉。
- 记录被访问的 URL,方便事后补重定向。
if ( is_404() ) {
status_header( 404 );
nocache_headers();
}
有些 SEO 插件会接管 404 页面,提供自定义内容、404 日志、自动重定向。装了插件就不要在主题里再写一套,两边同时输出会打架。选插件时优先看它会不会把 404 状态码改成 200,这一点比页面长什么样重要得多,软 404 对收录的伤害是长期的。相关判断标准可以对照 SEO 优化 里的收录一节。
用 404 日志找失效链接
404 页面好看是次要的,能从日志里捞出失效链接才是主要价值。三种拿数据的方式,按成本从低到高:
- 服务器日志:直接从 access.log 里筛状态码 404,按 URL 聚合排序,出现次数最多的就是最该修的。
- 插件记录:多数 SEO 插件的 404 监控会把 URL、来源、命中次数存表,后台能直接看,还能一键加重定向。
- 搜索引擎后台的页面索引报告,能看到外部链接打过来的 404,这类链接往往价值最高。
grep " 404 " access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20
awk '{print $9, $7}' access.log | grep "^404" | head -50
拿到列表后分三类处理:内容还在但换了地址的,做 301;内容确实删了的,让它保持 404,不要硬跳首页;被垃圾外链乱打的,忽略即可。批量重定向用插件或 nginx map 都行,规则超过几十条建议放在服务器层,每条都过一次 PHP 不值得。
防复发
- 改 slug、改分类结构之前,先导出旧 URL 列表,改完批量加 301。
- 迁移、换域名、换服务器之后,第一件事刷新固定链接,第二件事抽查 20 个内页。
- 把 404 命中数加进监控。一周内突然上涨,通常意味着某次改版打断了链接。
- 固定链接结构定下来就别频繁改。/archives/%post_id% 和 /%postname%/ 之间来回切一次,所有外链都要重做。
- 主题更新后确认 404.php 还在,有些主题更新会把这个模板改名,页面立刻退回 index.php。
固定链接的选型和规则细节看 固定链接设置;如果 404 是整站性的、连首页都打不开,那更可能是 网站打不开 那一类故障,白屏和 404 的处理路径不一样,不要混着查。