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

10

Me deparei com uma questão estranha.

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
...

Então is_404()é true. Por enquanto, tudo bem. Mas, por algum motivo, as últimas postagens são consultadas.

$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

O que, é claro, faz have_posts()retorno truee assim por diante. Alguém pode explicar isso?

O que eu descobri até agora:

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

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

kraftner
fonte
Se você não adicionar o código da página, será difícil ajudá-lo
Tomás Cot
3
Isso não é específico para o meu código. Comporta-se assim em uma nova instalação com todos os temas padrão.
kraftner 12/09
você pode citar pelo menos um tema, no meu tema personalizado não está funcionando? você está usando parâmetros específicos? você mudou as lesmas? qual versão do WP você está usando?
Tomás Cot
Realmente qualquer. Mas tente Twenty Eleven, se quiser.
kraftner 12/09
Desculpe por toda a pergunta, achei que as postagens estavam sendo exibidas.
Tomás Cot

Respostas:

9

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

Antes de tudo, vamos esclarecer que no WordPress, quando você visita um URL de front-end, aciona uma consulta. Sempre.

Essa consulta é apenas um padrão WP_Query, assim como as executadas por:

$query = new WP_Query( $args );

Há apenas uma diferença: as $argsvariáveis ​​são geradas pelo WordPress usando o WP::parse_request()método O que esse método faz é apenas olhar para o URL e as regras de reescrita e converter o URL em uma matriz de argumentos.

Mas o que acontece quando esse método não é capaz de fazer isso porque o URL não é válido? Os argumentos da consulta são apenas uma matriz como esta:

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

(Fonte aqui e aqui ).

Portanto, 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() cria uma matriz com uma chave de erro
  2. Essa matriz é passada para WP_Query, que apenas a executa
  3. handle_404()executado após a consulta, analisa o 'error'parâmetro e define is_404()como true

Então, have_post()e is_404()não estão relacionados. O problema é que WP_Querynão há um sistema que provoque um curto-circuito na consulta quando algo der errado. Assim que o objeto for criado, passe alguns argumentos para ela e a consulta será executada ...

Editar:

Existem 2 maneiras de superar esse problema:

  • Crie um 404.phpmodelo; O WordPress carregará isso em 404 URLs e você não precisará procurarhave_posts()
  • Forçar $wp_querya ficar vazio no 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
        }
    } );
gmazzap
fonte
4
Eu acrescentaria que a razão pela qual isso não ocorre normalmente é que 404 geralmente é resultado da consulta . Mas, nesse caso, é o resultado de uma regra de reescrita inigualável ( $wp->matched_rule), mas a consulta ainda está sendo processada porque não presta atenção a isso.
Rarst 12/09/14
+1. Sim, a consulta não presta atenção a ela e, com o código atual, ela não pode prestar atenção, porque não há como parar. Como exemplo, quando uma taxonomia não válido é consultado conjunto WordPress WHERE 1=0no SQL porque não pode parar a consulta para forçar uma consulta que retorno nada ... @Rarst
gmazzap
Ok, agora eu entendi. Portanto, a verdadeira questão que resta é por que diabos o WP_Query assume uma consulta padrão de obtenção de postagens quando passado sem argumentos razoáveis, quando apenas retornando nada faria muito mais sentido?
Kraftner 12/09/14
2
O @kraftner, como disse o WordPress, não pode evitar a execução da consulta, e quando não há argumentos ressonáveis, existem duas opções: executar uma consulta que com certeza não retorna nada (como quando uma taxonomia inválida é consultada, veja o comentário acima) ou executar a consulta padrão . Porque neste caso WP escolher o último é um Q que deve ser feita para devs principais :)
gmazzap
@ TomásCot Claro, mas se falhar, quero que realmente falhe e não retorne algo totalmente não relacionado. Enfim, as coisas estão esclarecidas agora e eu só preciso fazer uma is_404()verificação adicional .
Kraftner 12/09/14