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

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 las últimas publicaciones.

$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 cual, por supuesto, have_posts()devuelve, trueetc. ¿Alguien puede explicar esto?

Lo que descubrí hasta ahora:

La razón por la que solo entra en tres o más niveles de profundidad es que antes de que WP busque 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 404 en un punto, luego obtiene las publicaciones más recientes. Con la ayuda de @kaiser y @GM , he rastreado esto en algún lugar desde /wp-includes/class-wp.php:608

Kraftner
fuente
Si no agrega el código de la página, será difícil ayudarlo
Tomás Cot
3
Esto no es específico de mi código. Se comporta así en una nueva instalación con todos los temas predeterminados también.
kraftner
¿Puedes nombrar al menos un tema, en mi tema personalizado no funciona? ¿Estás usando parámetros específicos? has cambiado las babosas? ¿Qué versión de WP estás usando?
Tomás Cot
Realmente cualquiera. Pero prueba Twenty Eleven si quieres.
kraftner
Perdón por toda la pregunta, pensé que las publicaciones se mostraban.
Tomás Cot

Respuestas:

9

Puede que se sorprenda, pero no hay nada extraño allí.

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

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

$query = new WP_Query( $args );

Solo hay una diferencia: las $argsvariables son generadas por WordPress usando el WP::parse_request()método. Lo que hace ese método es simplemente 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í ).

Entonces esa matriz se pasa a WP_Query.

Ahora intenta hacer:

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

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

Entonces,

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

Entonces, have_post()y is_404()no están relacionados. El problema es que WP_Queryno tiene un sistema para hacer un cortocircuito en la consulta cuando algo sale mal, así que una vez que se construye el objeto, pasa algunos argumentos y la consulta se ejecutará ...

Editar:

Hay 2 formas de superar este problema:

  • Crea una 404.phpplantilla; WordPress cargará eso en las URL 404 y allí no tiene que buscarhave_posts()
  • Forzar $wp_querya estar 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
        }
    } );
    
gmazzap
fuente
44
Agregaría que la razón por la que esto no sucede normalmente es que 404 es generalmente el resultado de una consulta . Pero en este caso es el resultado de una regla de reescritura sin igual ( $wp->matched_rule), pero la consulta todavía está pasando por los movimientos porque no presta atención a eso.
Rarst
+1. Sí, la consulta no le presta atención, y con el código actual no puede prestarle atención, porque no hay forma de detenerlo. Como ejemplo cuando se consulta una taxonomía no válida, WordPress se configuró WHERE 1=0en sql porque no puede detener la consulta, así que fuerce una consulta que no devuelva nada ... @Rarst
gmazzap
Está bien, ahora lo entiendo. Entonces, la verdadera pregunta que queda es por qué demonios WP_Query asume una consulta predeterminada para obtener publicaciones cuando no se pasan argumentos razonables cuando solo devolver nada tendría más sentido.
kraftner
2
@kraftner como dijo WordPress no puede evitar que se ejecute la consulta, y cuando no hay argumentos razonables hay 2 opciones: ejecutar una consulta que seguro no devuelve nada (como cuando se consulta una taxonomía no válida, ver comentario arriba) o ejecutar consulta predeterminada . ¿Por qué en este caso WP elegir este último es una Q que se debe pedir a los desarrolladores principales :)
gmazzap
@ TomásCot Claro, pero si falla, me gustaría que realmente fallara y no devolviera algo totalmente ajeno. De todos modos, las cosas se aclararon ahora y solo necesito hacer una is_404()verificación adicional .
kraftner