Por que o loop não está vazio em alguns 404s?

10

Eu me deparei com um problema estranho.

Digamos que você acesse um URL aleatório com três ou mais níveis de profundidade:

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

Em seguida, is_404() é true . Por enquanto, tudo bem. Mas, por algum motivo, os últimos posts são consultados.

$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

Que então, é claro, faz have_posts() return true e assim por diante. Alguém pode explicar isso?

O que eu descobri até agora:

A razão pela qual só entra em campo em três ou mais níveis é que, antes disso, o WP procura postagens e anexos que, de alguma forma, resultam em algum outro comportamento.

Parece que, embora o WP reconheça a solicitação como um 404 em determinado momento, ele busca as postagens mais recentes. Com a ajuda de @kaiser e @ GM Eu rastreei isso em algum lugar de / wp-includes / class-wp.php: 608

    
por kraftner 12.09.2014 / 13:31

1 resposta

9

Você pode se surpreender, mas não há nada estranho lá.

Antes de mais nada, vamos esclarecer que no WordPress, quando você visita um URL frontend, você aciona uma consulta. Sempre.

Essa consulta é apenas um WP_Query padrão, assim como os executados por meio de:

$query = new WP_Query( $args );

Existe apenas uma diferença: as variáveis $args são geradas pelo WordPress usando o WP::parse_request() método. O que esse método faz é observar a URL e as regras de reconfiguração e converter a URL em uma matriz de argumentos.

Mas o que acontece quando esse método não consegue fazer isso porque o URL não é válido? A consulta args é apenas uma matriz como esta:

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

(Fonte aqui e here ).

Então essa matriz é passada para WP_Query .

Agora tente fazer:

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

Você está surpreso que a consulta seja exatamente a do OP? Eu não sou.

Então,

  1. parse_request() constrói uma matriz com uma chave de erro
  2. Esse array é passado para WP_Query , que apenas o executa
  3. handle_404() que executa após a consulta, analisa o parâmetro 'error' e define is_404() como true

Portanto, have_post() e is_404() não estão relacionados. O problema é que WP_Query não tem nenhum sistema para curto-circuito na consulta quando algo está errado, então uma vez que o objeto é construído, passe alguns argumentos para ele e a consulta será executada ...

Editar:

Existem duas maneiras de superar esse problema:

  • Crie um modelo 404.php ; O WordPress carregará isso em URLs 404 e você não precisará verificar have_posts()
  • Força $wp_query a estar vazia em 404, algo como:

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