Je suis tombé sur un problème étrange.
Supposons que vous accédiez à une URL aléatoire de trois niveaux ou plus:
http://example.com/a/b/c
http://example.com/a/b/c/d
...
Alors is_404()
est true
. Jusqu'ici tout va bien. Mais pour une raison quelconque, les derniers messages sont interrogés.
$wp_query->request
est
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
Ce qui fait bien sûr have_posts()
return true
et ainsi de suite. Quelqu'un peut-il expliquer cela?
Ce que j'ai découvert jusqu'à présent:
La raison pour laquelle on n'intervient qu'à trois niveaux ou plus, c'est qu'avant WP, il recherchait les publications et les pièces jointes, ce qui entraînait un autre comportement.
Il semble que même si WP reconnaît la demande en tant que 404 à un moment donné, il récupère ensuite les publications les plus récentes. Avec l'aide de @ kaiser et @ G.M. J'ai repéré cela quelque part entre /wp-includes/class-wp.php:608
Vous pouvez être surpris, mais il n'y a rien d'étrange là-bas.
Tout d’abord, précisons que dans WordPress, lorsque vous visitez une URL frontale, vous déclenchez une requête. Toujours.
Cette requête est juste un WP_Query
standard, tout comme ceux exécutés via:
$query = new WP_Query( $args );
Il n'y a qu'une différence: les variables $args
sont générées par WordPress à l'aide de la méthode WP::parse_request()
. Cette méthode ne fait que regarder l'URL et les règles de réécriture, puis convertir l'URL en un tableau d'arguments.
Mais que se passe-t-il lorsque cette méthode ne peut pas le faire parce que l'URL n'est pas valide? La requête args est juste un tableau comme celui-ci:
array( 'error' => '404' );
Donc, ce tableau est passé à WP_Query
.
Maintenant, essayez de faire:
$query = new WP_Query( array( 'error' => '404' ) );
var_dump( $query->request );
Etes-vous surpris que la requête soit exactement celle de OP? Je ne suis pas.
Alors,
parse_request()
construit un tableau avec une clé d'erreurWP_Query
, qui l'exécute simplementhandle_404()
qui exécute after la requête, examine le paramètre 'error'
et définit is_404()
sur trueDonc, have_post()
et is_404()
ne sont pas liés. Le problème est que WP_Query
n'a pas de système pour court-circuiter la requête quand quelque chose ne va pas, donc une fois que l'objet est construit, passez-lui quelques arguments et la requête sera exécutée ...
Modifier:
Il y a 2 façons de surmonter ce problème:
404.php
; WordPress chargera cela sur 404 URL et vous n'avez pas besoin de vérifier have_posts()
Forcer $wp_query
à être vide sur 404, quelque chose comme:
add_action( 'wp', function() {
global $wp_query;
if ( $wp_query->is_404() ) {
$wp_query->init();
$wp_query->is_404 = true; // init() reset 404 too
}
} );