¿Por qué el bucle no está vacío en algunos 404s?

10

Me encontré con un problema extraño.

Supongamos que accede a una URL aleatoria, con tres o más niveles de profundidad:

http://example.com/a/b/c
http://example.com/a/b/c/d
...

Entonces, is_404() es true . Hasta ahora tan bueno. Pero por alguna razón se consultan los últimos mensajes.

$wp_query->request

es

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

Lo que, por supuesto, hace have_posts() return true y así sucesivamente. ¿Alguien puede explicar esto?

Lo que descubrí hasta ahora:

La razón por la que solo se inicia en tres o más niveles de profundidad es que antes de eso, WP busca publicaciones y archivos adjuntos que de alguna manera resultan en algún otro comportamiento.

Parece que a pesar de que WP reconoce la solicitud como un 404 en un momento dado, recupera las publicaciones más recientes. Con la ayuda de @kaiser y @ GM He rastreado esto en algún lugar de / wp-includes / class-wp.php: 608

    
pregunta kraftner 12.09.2014 - 13:31

1 respuesta

9

Puede que te sorprendas, pero no hay nada extraño allí.

En primer lugar, aclaremos que en WordPress, cuando visita una URL de frontend, inicia una consulta. Siempre.

Esa consulta es solo un WP_Query estándar, al igual que las que se ejecutan a través de:

$query = new WP_Query( $args );

Solo hay una diferencia: las variables $args son generadas por WordPress usando método WP::parse_request() . Lo que hace ese método es solo mirar la URL y las reglas de reescritura, y convertir la URL en una matriz de argumentos.

¿Pero qué sucede cuando ese método no puede hacerlo porque la URL no es válida? La consulta args es solo una matriz como esta:

array( 'error' => '404' );

(Fuente aquí y aquí ).

Para que la matriz se pase a WP_Query .

Ahora trata de hacer:

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

¿Te sorprende que la consulta sea exactamente la de OP? No lo estoy.

Entonces,

  1. parse_request() construye una matriz con una clave de error
  2. Esa matriz se pasa a WP_Query , que simplemente se ejecuta
  3. handle_404() que ejecuta después de la consulta, mira el parámetro 'error' y establece is_404() en verdadero

Entonces, have_post() y is_404() no están relacionados. El problema es que WP_Query no tiene un sistema que provoque un cortocircuito en la consulta cuando algo sale mal, por lo que una vez que se construye el objeto, pásale algunos argumentos y la consulta se ejecutará ...

Editar:

Hay 2 formas de superar este problema:

  • Crea una plantilla 404.php ; WordPress cargará eso en 404 URL y allí no tendrá que verificar have_posts()
  • Forzar $wp_query para que esté vacío en 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
        }
    } );
    
respondido por el gmazzap 12.09.2014 - 14:01

Lea otras preguntas en las etiquetas