这篇文章也可以在我的博客中查看
关于本文
WordPress虽然有比较完善的404处理机制,但有时候我们需要手动返回404,这篇文章就来探讨一下这个问题。
何时返回404
根据mdn,404用作示意客户端找不到相应的资源,这可能是:
- 资源不存在
- 资源不应该被访问
- 与403相比:403指的是可被访问但强调用户"无权"
第一种情况WordPress会为我们处理,但第二种情况,往往需要我们手动驳回
Core是怎么做的?
先来看看WordPress Core是怎么做的,方便抄作业
在class-wp.php
中的handle_404()
中可以看到以下逻辑:
随版本更新文件和函数内容可能有变,此是2023-8-12的内容
php
handle_404()
{
...
$wp_query->set_404();
status_header( 404 );
nocache_headers();
...
}
- 首先使用全局变量$wp_query设置404
- 然后设置响应头代码为404
- 最后设置响应头为:不添加缓存处理(no-cache-headers)
- 它会将
Cache-Control
从响应头中移除
所以入乡随俗,我们也应该这么做
远古做法
在WordPress Hook还没成熟之前,习惯在WordPress处理完404之后的第一个钩子继续进行404处理
因此会选择在'wp'
钩子手动返回404:
php
add_action('wp', function () {
if (/* contidtion */) {
global $wp_query;
$wp_query->set_404();
status_header(404);
nocache_headers();
}
});
nocache_headers()
是可选的,但core做了,我就跟着做了
新做法
后来WordPress给了一个pre_handle_404
,在WordPress本身的handle_404()
真正执行之前
这个filter
hook需要返回一个单值:
- 为
false
时继续执行handle_404()
- 否则将短路
handle_404()
的执行
这给了我们一个手动处理404的机会
php
add_filter('pre_handle_404', function ($_, $wp_query) {
if (/* contidtion */) {
//设置404
$wp_query->set_404();
status_header(404);
nocache_headers();
}
return false;
}, 10, 2);
至于是否需要短路handle_404()
的执行
就我们这个例子而言不需要
因为我们手动设置了404,而handle_404()
会在已经是404的情况下自动短路
因此无论是return false
还是return
其它,handle_404()
都不会执行
问题修复
阴差阳错之间让我发现一个小问题
如果在主查询有结果的情况下(have_posts() === true
)返回404,整个主循环(main loop
)还是有效的,但事实上我们返回错误时不希望主循环生效,因此我们可以考虑手动清空主循环:
php
add_filter('pre_handle_404', function ($_, $wp_query) {
if (/* contidtion */) {
//清空文章
$wp_query->posts = [];
unset($wp_query->post);
$wp_query->post_count = 0;
//设置404
$wp_query->set_404();
status_header(404);
nocache_headers();
}
return false;
}, 10, 2);
主要是清空了posts本身,和计数器