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

10

Je suis tombé sur un problème étrange.

Supposons que vous accédiez à une URL aléatoire d'au moins trois niveaux:

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 articles 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 seule raison pour laquelle nous n'intervenons qu'à trois niveaux ou plus, c'est qu'avant que WP recherche des publications et des pièces jointes entraînant 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 de @ GM Je l’ai retrouvé quelque part dans / wp-includes / class-wp.php: 608

    
posée kraftner 12.09.2014 - 13:31

1 réponse

9

Vous serez peut-être surpris, mais il n'y a rien d'étrange ici.

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 du 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 n'est pas capable de 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 );

Êtes-vous surpris que la requête soit exactement celle de OP? Je ne le 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 après la requête, examine le paramètre 'error' et définit is_404() sur true

Ainsi, 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 s’exécutera ...

Modifier:

Il existe deux façons de résoudre ce problème:

  • Créez un template 404.php ; WordPress chargera cela sur 404 URL et vous ne devrez pas vérifier have_posts()
  • Forcer $wp_query à être vide sur 404, par exemple:

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

Lire d'autres questions sur les étiquettes