干了十多年CMS建站,和WordPress打交道比和老婆还熟,你说is_archive?那不就是个判断归档页的函数吗?谁不会用,可就是这看似简单的小玩意儿,当年差点让我把客户的项目搞砸,今天把这几个坑给你摆出来,省得你到时候拍大腿。
先说第一个坑,也是我印象最深的,有一次给一个做旅行博客的客户改主题,他想要分类页和标签页显示不同的布局,我心想这还不简单,在archive.php里用is_category()和is_tag()一判断,各套各的模板头,当时本地测试好好的,结果上线第二天客户就微信炸了:打开标签页,页面不但错乱,还变成了404,我远程一看,代码逻辑没问题啊,is_tag()明明返回的是true,为什么走了分类的模板?后来打开调试模式看查询,才发现是后台一个SEO插件偷偷调用了query_posts(),把全局$wp_query给覆盖了,那插件在pre_get_posts钩子里干了一堆事,又用query_posts重设了主循环,结果is_archive()倒是返回了true,可is_tag()却返回false——因为全局查询已经变成了一个分类归档。
痛定思痛,我给所有客户定了一条铁律:拒绝query_posts(),这函数就是个坑,它直接替换全局查询变量,相当于把你的手脚绑住再去跑步,要自定义查询,一律用WP_Query,或者在pre_get_posts钩子里改主查询的条件,比如你要在某个分类归档页只显示5篇文章,正确做法是:
function my_archive_posts_per_page($query) {
if(!is_admin() && $query->is_main_query() && $query->is_archive()){
$query->set('posts_per_page', 5);
}
}
add_action('pre_get_posts', 'my_archive_posts_per_page');
注意这里一定得加$query->is_main_query(),不然连后台的列表页都给你改成5篇,那才叫欲哭无泪。

WordPress is_archive 踩坑记,别让这个条件标签毁了你的归档页
另一个坑是is_archive()对自定义文章类型的支持,你注册了一个“作品”类型,设置了'has_archive' => true,然后你高高兴兴在archive.php里写:
if (is_archive()) { echo '这是归档页'; }
结果打开作品归档页,这行字死活不显示,为什么?因为自定义文章类型的归档页,需要用is_post_type_archive('作品')来判断,而is_archive()虽然也会返回true,但在某些主题的模板层级里,它会优先命中tag.php或category.php,根本没有走到archive.php,别问我怎么知道的,那是一次深夜上线,我盯着屏幕上的白屏,差点以为服务器被黑客日了。
所以我的经验是:在模板里做归档类型判断,要按具体条件来,别偷懒只用一个is_archive(),而且顺序有讲究,先查定制,再查分类,最后再往回兜底:
if (is_post_type_archive()) {
// 自定义文章类型归档
} elseif (is_category()) {
// 分类
} elseif (is_tag()) {
// 标签
} elseif (is_date() || is_author()) {
// 日期或作者
}
说真的,is_archive()只适合做粗粒度判断,比如你想在归档页统一显示一个“所有文章”的标题,那用它没问题,可一旦牵扯到具体细分,就得一个个拆开,别嫌麻烦。
再说说调试工具,我推荐装一个Query Monitor插件,它能在后台直观看到当前页面命中了哪些条件标签,全局查询是什么,那些钩子改了查询参数,上次那个SEO插件的问题,就是用它一眼盯出来的,装了这个,你踩坑的概率至少降一半。
最后给点儿长期维护建议,第一,主题functions.php里别堆太多代码,尽量拆成模块或独立插件,方便排查,第二,每次WordPress大版本更新前,去后台跑一遍归档页、分类页、标签页,看看is_archive相关的判断有没有异常,第三,永远别在模板里直接调用全局$wp_query再拿它判断,因为你不知道哪个插件会在你前面动它,第四,别迷信“查询次数”越少越好,正确性永远排在性能前面——即使一个归档页查了三次数据库,只要结果对,慢一点客户能等;要是结果错了,客户能把你等死。
就这,别问我怎么知道这么多,反正你照着做,能少掉很多头发。
发表评论