问题描述

我遇到了一个奇怪的问题。

说你访问一个随机 url,三个或更多的层次:

http://example.com/a/b/c
http://example.com/a/b/c/d
...

那么 is_404()true 。到现在为止还挺好。但是由于某些原因,最后的帖子被查询。

$wp_query->request

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
    FROM wp_posts
    WHERE 1=1
        AND wp_posts.post_type = 'post'
        AND (
            wp_posts.post_status    = 'publish'
            OR wp_posts.post_status = 'private'
            )
    ORDER BY wp_posts.post_date DESC
    LIMIT 0, 5

那当然这使得 have_posts()返回 true 等等。有人可以解释一下吗

我发现到目前为止

只有三点或更多级别深入的原因是,在 WP 查找帖子和附件之前,这些结果会导致其他一些行为。

似乎即使 WP 在一点上将该请求识别为 404,然后获取最新的帖子。在 @kaiser@G.M. 的帮助下,我已经将其跟踪到了/wp-includes/class-wp.php:608 的某个地方

最佳解决方案

你可能会惊讶,但没有什么奇怪的。

首先让我们澄清一下,在 WordPress 中,当您访问前端 URL 时,您将触发查询。总是。

该查询只是一个标准的 WP_Query,就像通过以下方式运行的那样:

$query = new WP_Query( $args );

只有一个区别:$args 变量由 WordPress 使用 WP::parse_request()方法生成。该方法的作用是查看 URL,并重写规则,并将 URL 转换为参数数组。

但是,由于 URL 是 non-valid,那个方法不能做到这一点呢?查询 args 只是一个这样的数组:

array( 'error' => '404' );

(来源 herehere) 。

所以将该数组传递给 WP_Query

现在尝试做:

$query = new WP_Query( array( 'error' => '404' ) );
var_dump( $query->request );

您是否惊讶于查询完全是 OP 中的查询?我不是。

所以,

  1. parse_request()构建一个带有错误键的数组

  2. 该数组被传递给 WP_Query,它只是运行它

  3. 在查询后运行的 handle_404(),查看'error'参数,并将 is_404()设置为 true

所以 have_post()is_404()是无关的。问题是 WP_Query 在出现错误时没有向 short-circuit 询问系统,所以一旦对象被建立,传递一些参数就可以运行查询。

编辑:

有两种方法来克服这个问题:

  • 创建 404.php 模板; WordPress 将加载 404 网址,您不需要检查 have_posts()

  • 强制 $wp_query 在 404 上为空,类似于:

    add_action( 'wp', function() {
        global $wp_query;
        if ( $wp_query->is_404() ) {
            $wp_query->init();
            $wp_query->is_404 = true; // init() reset 404 too
        }
    } );
    

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。