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


10

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

Supposons que vous accédez à une URL aléatoire, à trois niveaux ou plus de profondeur:

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 alors bien sûr le have_posts()retour trueet ainsi de suite. Quelqu'un peut-il expliquer cela?

Ce que j'ai découvert jusqu'à présent:

La raison qui ne se déclenche qu'à trois niveaux ou plus est qu'avant que WP recherche les publications et les pièces jointes, ce qui entraîne en quelque sorte un autre comportement.

Il semble que même si WP reconnaît la demande comme un 404 à un moment donné, il récupère ensuite les messages les plus récents. Avec l'aide de @kaiser et @GM, je l'ai retrouvé quelque part dans /wp-includes/class-wp.php:608


Si vous n'ajoutez pas le code de la page, il sera difficile de vous aider
Tomás Cot

3
Ce n'est pas spécifique à mon code. Se comporte comme ça sur une toute nouvelle installation avec tous les thèmes par défaut.
kraftner

pouvez-vous nommer au moins un thème, dans mon thème personnalisé ne fonctionne pas? utilisez-vous des paramètres spécifiques? avez-vous changé les limaces? quelle version de WP utilisez-vous?
Tomás Cot

Vraiment n'importe lequel. Mais essayez Twenty Eleven si vous le souhaitez.
kraftner du

Désolé pour toute la question, je pensais que les messages étaient affichés.
Tomás Cot

Réponses:


9

Vous pourriez être surpris, mais il n'y a rien d'étrange là-bas.

Tout d'abord, clarifions que dans WordPress lorsque vous visitez une URL frontale, vous déclenchez une requête. Toujours.

Cette requête est juste une norme WP_Query, tout comme celles exécutées via:

$query = new WP_Query( $args );

Il n'y a qu'une seule différence: les $argsvariables sont générées par WordPress en utilisant la WP::parse_request()méthode. Cette méthode ne fait que regarder l'URL et les règles de réécriture et convertir l'URL en un tableau d'arguments.

Mais que se passe-t-il lorsque cette méthode n'est pas en mesure de le faire car 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.

Essayez maintenant de faire:

$query = new WP_Query( array( 'error' => '404' ) );
var_dump( $query->request );

Êtes-vous surpris que la requête soit exactement celle d'OP? Je ne suis pas.

Donc,

  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 s'exécute après la requête, examine le 'error'paramètre et prend is_404()la valeur true

Donc, have_post()et is_404()ne sont pas liés. Le problème est qu'il WP_Queryn'a pas de système pour court-circuiter la requête en cas de problème, donc une fois l'objet construit, passez-lui quelques arguments et la requête s'exécutera ...

Éditer:

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

  • Créez un 404.phpmodèle; WordPress chargera cela sur 404 URL et là, vous n'avez pas à vérifierhave_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
        }
    } );
    

4
J'ajouterais que la raison pour laquelle cela ne se produit généralement pas est que 404 est généralement le résultat d'une requête . Mais dans ce cas, c'est le résultat d'une règle de réécriture inégalée ( $wp->matched_rule), mais la requête passe toujours par les mouvements car elle n'y prête pas attention.
Rarst le

+1. Oui, la requête n'y fait pas attention, et avec le code actuel, elle ne peut pas y prêter attention, car il n'y a aucun moyen de l'arrêter. Par exemple, lorsqu'une taxonomie non valide est interrogée, WordPress est défini WHERE 1=0dans SQL car il ne peut pas arrêter la requête, alors forcez une requête qui ne renvoie rien ... @Rarst
gmazzap

Bon maintenant je comprends. Donc, la vraie question qui reste est de savoir pourquoi diable WP_Query suppose-t-il une requête par défaut pour obtenir des messages lorsqu'il ne reçoit aucun argument raisonnable alors que rien ne serait plus logique?
kraftner

2
@kraftner comme dit WordPress ne peut pas éviter les exécutions de requête, et lorsqu'il n'y a pas d'arguments résonnables, il y a 2 choix: exécuter une requête qui ne renvoie rien (comme lorsqu'une taxonomie non valide est interrogée, voir le commentaire ci-dessus) ou exécuter la requête par défaut . Pourquoi dans ce cas WP choisir ce dernier est un Q qui devrait être demandé aux développeurs principaux :)
gmazzap

@ TomásCot Bien sûr, mais s'il échoue, je voudrais qu'il échoue vraiment et ne renvoie pas quelque chose de totalement indépendant. Quoi qu'il en soit, les choses se sont éclaircies maintenant et j'ai juste besoin de faire une is_404()vérification supplémentaire .
kraftner
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.