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>
This commit is contained in:
Executable → Regular
+61
-5
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* Plugin Name: Fe Adulta — Homepage
|
||||
* Description: Portada con selección editorial via ACF.
|
||||
* Version: 1.4
|
||||
* Version: 1.5
|
||||
*/
|
||||
|
||||
// ── Flush rewrite rules una sola vez tras cambios de configuración ────────
|
||||
@@ -1407,13 +1407,69 @@ add_shortcode('fea_noticia_centro', function() {
|
||||
});
|
||||
|
||||
// ── Reescribir links internos al idioma activo (Polylang) ─────────────────
|
||||
|
||||
/**
|
||||
* Resuelve un enlace interno a un ID de entrada, con coste acotado.
|
||||
*
|
||||
* NO usa url_to_postid(). Esa función termina construyendo una WP_Query a partir
|
||||
* de las reglas de reescritura, y cuando la URL no encaja en ninguna (enlaces
|
||||
* legacy de Joomla, rutas de idioma, .html sueltos) la query se queda sin cláusula
|
||||
* que la acote y se trae las ~32.000 entradas CON su contenido: 256 MB de memoria
|
||||
* y un 500. Reventaba 36 URLs —9 cartas × los 4 idiomas traducidos— desde el
|
||||
* cutover del 3-ago.
|
||||
*
|
||||
* La estructura de enlaces es /%postname%/, así que basta con el último segmento
|
||||
* del path. Una consulta con LIMIT 1 no puede degenerar por mucho que la URL sea
|
||||
* rara, y el resultado se cachea por petición: las cartas traen ~40 enlaces y
|
||||
* muchos se repiten.
|
||||
*/
|
||||
function fea_href_a_post_id(string $href): int {
|
||||
static $cache = [];
|
||||
if (isset($cache[$href])) return $cache[$href];
|
||||
|
||||
$path = (string) parse_url($href, PHP_URL_PATH);
|
||||
$segmentos = array_values(array_filter(explode('/', $path), 'strlen'));
|
||||
if (!$segmentos) return $cache[$href] = 0;
|
||||
|
||||
$ultimo = (string) end($segmentos);
|
||||
// Las URLs viejas de Joomla acaban en .html y nunca son un post_name.
|
||||
if (substr($ultimo, -5) === '.html') return $cache[$href] = 0;
|
||||
|
||||
// El slug puede venir percent-encoded en el href (introducci%C3%B3n-...).
|
||||
$candidatos = array_values(array_unique(array_filter([
|
||||
$ultimo,
|
||||
rawurldecode($ultimo),
|
||||
sanitize_title(rawurldecode($ultimo)),
|
||||
], 'strlen')));
|
||||
if (!$candidatos) return $cache[$href] = 0;
|
||||
|
||||
// El orden reproduce a quién sirve WordPress esa misma URL:
|
||||
// - con la estructura /%postname%/ las páginas de primer nivel ganan al post
|
||||
// homónimo (reglas verbosas de reescritura); hay 4 slugs así.
|
||||
// - hay 58 slugs compartidos por dos entradas —duplicados del import de
|
||||
// Joomla— y WP resuelve el name por post_date DESC. Ordenar por ID daría
|
||||
// la vieja y traduciríamos el enlace equivocado.
|
||||
global $wpdb;
|
||||
$marcas = implode(',', array_fill(0, count($candidatos), '%s'));
|
||||
$id = (int) $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT ID FROM {$wpdb->posts}
|
||||
WHERE post_name IN ($marcas)
|
||||
AND post_status = 'publish'
|
||||
AND post_type IN ('post','page')
|
||||
ORDER BY (post_type = 'page' AND post_parent = 0) DESC, post_date DESC, ID DESC
|
||||
LIMIT 1",
|
||||
$candidatos
|
||||
));
|
||||
|
||||
return $cache[$href] = $id;
|
||||
}
|
||||
|
||||
add_filter('the_content', function($content) {
|
||||
if (!function_exists('pll_current_language') || !function_exists('pll_get_post')) return $content;
|
||||
$lang = pll_current_language();
|
||||
if (!$lang || $lang === 'es') return $content;
|
||||
// Los archivos de cartas pueden contener cientos de enlaces. Resolver cada uno
|
||||
// con url_to_postid() en un listado agota memoria; la reescritura solo aporta
|
||||
// valor al mostrar el contenido completo de una entrada o página.
|
||||
// La reescritura solo aporta valor al mostrar el contenido completo de una
|
||||
// entrada o página, no en los listados.
|
||||
if (!is_singular()) return $content;
|
||||
|
||||
return preg_replace_callback(
|
||||
@@ -1423,7 +1479,7 @@ add_filter('the_content', function($content) {
|
||||
$home = home_url();
|
||||
if (strpos($href, $home) === false) return $m[0];
|
||||
|
||||
$post_id = url_to_postid($href);
|
||||
$post_id = fea_href_a_post_id($href);
|
||||
if (!$post_id) return $m[0];
|
||||
|
||||
$translated_id = pll_get_post($post_id, $lang);
|
||||
|
||||
Reference in New Issue
Block a user