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, true
etc. ¿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
Respuestas:
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:Solo hay una diferencia: las
$args
variables son generadas por WordPress usando elWP::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:
(Fuente aquí y aquí ).
Entonces esa matriz se pasa a
WP_Query
.Ahora intenta hacer:
¿Te sorprende que la consulta sea exactamente la de OP? No soy.
Entonces,
parse_request()
construye una matriz con una clave de errorWP_Query
, eso solo lo ejecutahandle_404()
que se ejecuta después de la consulta, mira el'error'
parámetro y se estableceis_404()
en verdaderoEntonces,
have_post()
yis_404()
no están relacionados. El problema es queWP_Query
no 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:
404.php
plantilla; WordPress cargará eso en las URL 404 y allí no tiene que buscarhave_posts()
Forzar
$wp_query
a estar vacío en 404, algo como:fuente
$wp->matched_rule
), pero la consulta todavía está pasando por los movimientos porque no presta atención a eso.WHERE 1=0
en sql porque no puede detener la consulta, así que fuerce una consulta que no devuelva nada ... @Rarstis_404()
verificación adicional .