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' );
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,
-
parse_request()
constrói uma matriz com uma chave de erro - Esse array é passado para
WP_Query
, que apenas o executa -
handle_404()
que executa após a consulta, analisa o parâmetro'error'
e defineis_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á verificarhave_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 } } );