Files
feadulta/docs/cutover/500-cartas-traducidas-url-to-postid.md
T
rafa 78879aef68 fea-homepage: fuera url_to_postid(), reventaba 36 cartas traducidas
36 URLs en 500 desde el cutover: las mismas 9 cartas de otras semanas en
fr/it/en/pt. En espanol iban bien, y contra CDMON las mismas URLs daban 200, o
sea que era regresion nuestra.

La reescritura de enlaces internos al idioma activo llamaba a url_to_postid()
una vez por enlace, y estas cartas traen unos 40. Cuando la URL no encaja en
ninguna regla de reescritura, la WP_Query que monta esa funcion se queda sin
clausula que la acote y se trae las 32.311 entradas CON su contenido, dos veces
por peticion. 256 MB agotados en class-wpdb.php y 500.

Se sustituye por fea_href_a_post_id(): ultimo segmento del path y una consulta
con LIMIT 1, que no puede degenerar, cacheada por peticion.

El ORDER BY reproduce a quien sirve WordPress esa misma URL, y no es cosmetico:
hay 4 slugs compartidos por una pagina de primer nivel y una entrada, donde gana
la pagina, y 58 compartidos por dos entradas -duplicados del import de Joomla-
donde gana la de post_date mas reciente. Mi primer intento ordenaba por ID ASC y
en esos 58 habria traducido el enlace equivocado.

Verificado: 116/116 cartas traducidas en 200, 200 entradas al azar en 200,
E2E 13/13, y el resolutor nuevo coincide con url_to_postid() en 461 de 461
slugs de los casos donde url_to_postid() no revienta. La consulta gorda ha
desaparecido del performance_schema.

Van dos centinelas a la suite E2E, una carta italiana y una francesa de las que
fallaban.

Nota de metodo para el futuro: esto no se reproduce con wp-cli, porque Polylang
no instancia su frontend en CLI y el filtro sale antes de tiempo. Se cazo
mirando events_statements_history_long en MySQL mientras se pedia la pagina por
HTTP.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 22:02:10 -04:00

3.6 KiB
Raw Blame History

Los 500 de las cartas traducidas (url_to_postid())

RESUELTO — 4-ago-2026, 02:00 UTC

36 URLs devolvían 500: las mismas 9 «cartas de otras semanas» en los cuatro idiomas traducidos. En español las 9 iban bien.

/fr/lumiere-et-phare/   /it/luce-e-faro/   /en/light-and-beacon/   /pt/luz-e-farol/   … ×9

Era una regresión del cutover, no algo heredado: las mismas URLs contra CDMON respondían 200.

La causa

fea-homepage.php reescribe los enlaces internos al idioma activo, y para eso llamaba a url_to_postid() una vez por enlace. Estas cartas traen unos 40.

url_to_postid() acaba construyendo una WP_Query a partir de las reglas de reescritura. Cuando la URL no encaja en ninguna, la query se queda sin cláusula que la acote y sale esto:

SELECT wp_posts.* FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' ORDER BY post_date DESC

Las 32.311 entradas con su contenido entero. Dos veces por petición. Los 256 MB de PHP se agotaban en class-wpdb.php:2322 y Apache devolvía el 500.

Encaja con el patrón observado: el filtro se salta el español (if (!$lang || $lang === 'es') return), que es justo el idioma que no fallaba, y solo actúa en is_singular().

El arreglo

Se sustituye url_to_postid() por fea_href_a_post_id(): la estructura de enlaces es /%postname%/, así que basta el último segmento del path y una consulta con LIMIT 1, que no puede degenerar por rara que sea la URL. El resultado se cachea por petición.

El orden del ORDER BY no es cosmético, reproduce a quién sirve WordPress esa misma URL:

caso cuántos criterio
página de primer nivel con el mismo slug que una entrada 4 gana la página (reglas verbosas de reescritura)
dos entradas con el mismo slug (duplicados del import de Joomla) 58 gana la de post_date más reciente

Ordenar por ID ASC, que fue el primer intento, devolvía la entrada vieja y habría traducido el enlace equivocado en esos 58 casos.

Verificación

Las 116 cartas traducidas (29 × 4 idiomas) 116/116 en 200
Muestra de 200 entradas al azar (40 por idioma) todas en 200
fea_href_a_post_id() vs url_to_postid(), 61 slugs repetidos + 400 al azar 461/461 idénticos
La consulta gorda desaparecida: la que más filas devuelve ahora son 640 de wp_options
Suite E2E 13/13 en 200
Errores PHP y 5xx tras el despliegue 0 y 0

Los enlaces se siguen reescribiendo, y algunos más que antes: url_to_postid() fallaba en URLs que sí resuelven bien por slug. Comprobado contra CDMON que los nuevos pares son de verdad la misma entrada (mismo grupo de traducción de Polylang): como-bendecir-la-mesacomment-benir-la-table, felices-6heureux, 3-temarioprogramme

Centinelas

tools/e2e/sites/www.json incorpora carta-trad-it y carta-trad-fr, dos de las que reventaban. Si esto vuelve, lo dice la suite.

⚠️ Para la próxima

url_to_postid() no es seguro con URLs arbitrarias en un sitio grande. El comentario que ya había en el fichero decía que en los listados agotaba memoria, y por eso se había acotado a is_singular(). La cura se quedó corta: el problema no era el listado, era la función.

Y una trampa de método: esto no se reproduce con wp-cli. Polylang no instancia su clase de frontend en CLI, así que el filtro sale antes de tiempo y no pasa nada. Se cazó mirando performance_schema.events_statements_history_long en MySQL mientras se pedía la página por HTTP, que muestra la secuencia real de sentencias de la petición.