web-dev-qa-db-ja.com

一部の404でループが空にならないのはなぜですか?

私は奇妙な問題に遭遇しました。

ランダムなURLにアクセスしたとしましょう。3つ以上のレベルがあります。

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を返すようにします。誰かがこれを説明できますか?

私がこれまでに見つけたこと:

3つ以上のレベルで深く入り込むだけの理由は、その前にWPが投稿や添付ファイルを探すので、どういうわけか他の振る舞いをするからです。

WPはリクエストをある時点で404として認識していますが、最新の投稿を取得しているようです。 @kaiser および @ G.Mの助けを借りて。 これを /wp-includes/class-wp.php:608 からどこかに追跡しました。

10
kraftner

あなたは驚くかもしれませんが、そこに奇妙なことは何もありません。

まず最初に、WordPressでフロントエンドのURLにアクセスしたときにクエリを起動することを明確にしましょう。常に。

そのクエリは、標準のWP_Queryです。

$query = new WP_Query( $args );

唯一の違いがあります:$args変数は WP::parse_request() メソッドを使ってWordPressによって生成されます。その方法は、URLと書き換え規則を見て、URLを引数の配列に変換するだけです。

しかし、URLが無効であるためにそのメソッドがそれを実行できない場合はどうなりますか? query argsはこのような単なる配列です。

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

(ソース ここ および ここ )。

そのため、その配列は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が何か問題が発生したときにクエリをショートするシステムを持っていないことです。オブジェクトが構築されたら、それにいくつかの引数を渡してクエリを実行します。

編集:

この問題を解決するには2つの方法があります。

  • 404.phpテンプレートを作成します。 WordPressはそれを404個のURLにロードするので、have_posts()をチェックする必要はありません。
  • 404では$wp_queryを強制的に空にします。

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