web-dev-qa-db-fra.com

Pourquoi la boucle n'est-elle pas vide sur certains 404?

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

10
kraftner

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' );

(Source ici et ici ).

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,

  1. parse_request() construit un tableau avec une clé d'erreur
  2. Ce tableau est passé à WP_Query, qui l'exécute simplement
  3. handle_404() qui exécute after la requête, examine le paramètre 'error' et définit is_404() sur true

Donc, 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:

  • Créez un modèle 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
        }
    } );
    
9
gmazzap