fix(portada): artículos por idioma y enlace evangelio del día (#132)

Bug 2: fea_carta_section_posts parsea SIEMPRE la carta ES (el parser solo
reconoce cabeceras en español) y mapea cada artículo a su traducción
Polylang del idioma de la portada. Antes EN/FR/IT/PT caían al fallback
'últimos por categoría' y mostraban artículos incorrectos.

Bug 1: el enlace 'evangelio del día' resuelve la traducción del idioma
actual con pll_get_post (get_posts usa suppress_filters=true y devolvía
siempre la página ES).

Desplegado y verificado en prod (wp-nuevo) 2026-06-22.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 08:30:18 -04:00
parent 66ee943da4
commit 9ac857b027
2 changed files with 562 additions and 45 deletions
@@ -124,20 +124,7 @@ function fea_resolve_links_in_html($html) {
function fea_url_to_post_id($url) {
global $wpdb;
if (preg_match('~(?:^|/)fea/([a-z0-9\-]+)/?(?:[?#]|$)~i', $url, $m)) {
$slug = $m[1];
if (in_array($slug, ['wp-admin','wp-content','category','tag','author','page','en','fr','it','pt'], true)) {
return null;
}
$pid = $wpdb->get_var($wpdb->prepare(
"SELECT ID FROM {$wpdb->posts}
WHERE post_name=%s AND post_status='publish' AND post_type='post'
ORDER BY post_date DESC LIMIT 1",
$slug
));
if ($pid) return (int) $pid;
}
// Joomla legacy: /item/<k2id>-...html
if (preg_match('~/item/(\d+)-[^/"]+\.html~i', $url, $m)) {
$k2 = (int) $m[1];
if ($k2 > 0) {
@@ -147,9 +134,36 @@ function fea_url_to_post_id($url) {
));
if ($pid) return (int) $pid;
}
return null;
}
return null;
// Enlace interno WP: deriva el slug del path, relativo al home. Agnóstico al
// entorno → funciona en local (home en .../fea) y en prod (home en la raíz).
// No depende de un prefijo /fea/ hardcodeado (issue #91).
$host = wp_parse_url($url, PHP_URL_HOST);
$home_host = wp_parse_url(home_url(), PHP_URL_HOST);
if ($host && $home_host && strcasecmp($host, $home_host) !== 0) {
return null; // host externo → no es un artículo nuestro
}
$path = (string) wp_parse_url($url, PHP_URL_PATH);
if ($path === '') return null;
$home_path = rtrim((string) wp_parse_url(home_url('/'), PHP_URL_PATH), '/');
if ($home_path !== '' && strpos($path, $home_path . '/') === 0) {
$path = substr($path, strlen($home_path));
}
$seg = explode('/', trim($path, '/'));
$slug = $seg[0] ?? '';
if ($slug === '' || in_array($slug, ['wp-admin','wp-content','category','tag','author','page','en','fr','it','pt'], true)) {
return null;
}
$pid = $wpdb->get_var($wpdb->prepare(
"SELECT ID FROM {$wpdb->posts}
WHERE post_name=%s AND post_status='publish' AND post_type='post'
ORDER BY post_date DESC LIMIT 1",
$slug
));
return $pid ? (int) $pid : null;
}
/**
@@ -157,13 +171,31 @@ function fea_url_to_post_id($url) {
* o array vacío si no hay carta o no hay links resueltos en esa sección.
*/
function fea_carta_section_posts($section_slug, $lang = null) {
$lang = $lang ?: (function_exists('fea_current_lang') ? fea_current_lang() : 'es');
// El parser de secciones reconoce las cabeceras SOLO en español
// (fea_extract_sections_from_html). Las cartas traducidas tienen las
// cabeceras en su idioma → 0 secciones. Por eso parseamos SIEMPRE la
// carta ES y luego mapeamos cada link a su traducción del idioma destino.
$carta_id = fea_get_current_carta_id($lang);
if (!$carta_id) return [];
$sections = fea_parse_carta_sections($carta_id);
$carta_es = $carta_id;
if ($lang !== 'es' && function_exists('pll_get_post')) {
$es = pll_get_post($carta_id, 'es');
if ($es) $carta_es = (int) $es;
}
$sections = fea_parse_carta_sections($carta_es);
$ids = $sections[$section_slug] ?? [];
if (!$ids) return [];
$posts = [];
foreach ($ids as $pid) {
// Mapear el artículo ES a su traducción del idioma de la portada.
// Si no hay traducción, se mantiene el ES (degradación elegante).
if ($lang !== 'es' && function_exists('pll_get_post')) {
$tr = pll_get_post((int) $pid, $lang);
if ($tr) $pid = (int) $tr;
}
$p = get_post($pid);
if ($p && $p->post_status === 'publish') $posts[] = $p;
}