diff --git a/scripts/verify_carta_lang_links.php b/scripts/verify_carta_lang_links.php new file mode 100644 index 0000000..06e8d54 --- /dev/null +++ b/scripts/verify_carta_lang_links.php @@ -0,0 +1,144 @@ +\n"); + exit(1); +} + +$LANGS = ['en', 'fr', 'it', 'pt']; + +function resolve_post_from_href($href) { + if (preg_match('~[?&]p=(\d+)~', $href, $m)) { + return (int)$m[1]; + } + $path = preg_replace('~^https?://[^/]+~i', '', $href); + $path = preg_replace('~[?#].*$~', '', $path); + $path = preg_replace('~^/fea~', '', $path); + $path = preg_replace('~^/(en|fr|it|pt|es)(/|$)~', '/', $path); + $segs = array_values(array_filter(explode('/', $path), 'strlen')); + if (count($segs) !== 1) { + return 0; // categorías, home, rutas multi-segmento: no aplica + } + $p = get_page_by_path($segs[0], OBJECT, ['post', 'page']); + return $p ? $p->ID : 0; +} + +function href_lang_prefix($href) { + $path = preg_replace('~^https?://[^/]+~i', '', $href); + $path = preg_replace('~^/fea~', '', $path); + if (preg_match('~^/(en|fr|it|pt)(/|$)~', $path, $m)) { + return $m[1]; + } + return null; +} + +$translations = pll_get_post_translations($CARTA); +if (empty($translations)) { + fwrite(STDERR, "El post $CARTA no tiene grupo de traducciones Polylang.\n"); + exit(1); +} + +echo "Verificando enlaces de la carta ES=$CARTA\n"; +echo "Traducciones: " . json_encode($translations) . "\n\n"; + +$total_sin_traducir = 0; +$total_mismatch = 0; +$total_rotos = 0; + +foreach ($LANGS as $lang) { + if (empty($translations[$lang])) { + echo "[$lang] SIN TRADUCCIÓN DE LA CARTA (no existe post en este idioma)\n\n"; + continue; + } + $pid = $translations[$lang]; + $post = get_post($pid); + if (!$post) { + echo "[$lang] post $pid no encontrado\n\n"; + continue; + } + + // Captura cualquier href absoluto http(s) — funciona tanto en local (dominio + // Tailscale) como en prod (www.feadulta.com); resolve_post_from_href() ya + // descarta lo que no resuelva a un post interno (externos, mailto, etc.). + preg_match_all('~href="(https?://[^"]+)"~i', $post->post_content, $m); + $hrefs = array_values(array_unique($m[1])); + + $issues = []; + foreach ($hrefs as $href) { + $target_id = resolve_post_from_href($href); + if (!$target_id) { + continue; // home, categorías, rutas no resolubles a un post concreto + } + $target_lang = pll_get_post_language($target_id) ?: 'es'; + $prefix = href_lang_prefix($href); + + if ($target_lang === $lang && $prefix === $lang) { + continue; // todo correcto + } + + // Averiguar el ES de origen del contenido apuntado, para buscar la traducción correcta + if ($target_lang === 'es') { + $es_id = $target_id; + } else { + $tr = pll_get_post_translations($target_id); + $es_id = $tr['es'] ?? null; + } + + $correct_id = $es_id ? pll_get_post($es_id, $lang) : null; + + if ($correct_id && $correct_id != $target_id) { + $correct_url = get_permalink($correct_id); + $issues[] = [ + 'tipo' => 'MISMATCH', + 'detalle' => "href=\"$href\" resuelve a post $target_id (lang=$target_lang) — correcto: $correct_url (post $correct_id)", + ]; + $total_mismatch++; + } elseif ($correct_id && $correct_id == $target_id && $prefix !== $lang) { + // resuelve al post correcto pero con URL/slug distinta a la actual (permalink cambió) + $correct_url = get_permalink($correct_id); + $issues[] = [ + 'tipo' => 'MISMATCH', + 'detalle' => "href=\"$href\" no coincide con el permalink actual: $correct_url (post $correct_id)", + ]; + $total_mismatch++; + } elseif (!$correct_id && $target_lang !== $lang) { + $issues[] = [ + 'tipo' => 'SIN_TRADUCIR', + 'detalle' => "href=\"$href\" -> post $target_id (lang=$target_lang) sin traducción en '$lang'", + ]; + $total_sin_traducir++; + } + } + + echo "[$lang] post $pid — " . count($hrefs) . " enlaces internos, " . count($issues) . " con problemas\n"; + foreach ($issues as $issue) { + echo " {$issue['tipo']}: {$issue['detalle']}\n"; + } + echo "\n"; +} + +echo "RESUMEN: $total_sin_traducir sin traducir, $total_mismatch mismatch de idioma/slug\n"; +exit(($total_sin_traducir + $total_mismatch + $total_rotos) > 0 ? 2 : 0);