82ca122a4e
Reports internal links whose language prefix/slug doesn't match the target post's actual language (SIN_TRADUCIR / MISMATCH), so link bugs like the silence/silence-2 cross-language mixup on carta 734 get caught before they reach prod.
145 lines
5.3 KiB
PHP
145 lines
5.3 KiB
PHP
<?php
|
|
/**
|
|
* verify_carta_lang_links.php
|
|
*
|
|
* QA de una carta traducida: para cada idioma (en/fr/it/pt), revisa TODOS los
|
|
* enlaces internos de feadulta.com y comprueba que apuntan a contenido en ese
|
|
* mismo idioma (prefijo /en/, /fr/, /it/, /pt/ y slug correcto).
|
|
*
|
|
* Detecta dos tipos de fallo:
|
|
* - SIN_TRADUCIR: el link apunta al artículo en español porque nunca se
|
|
* tradujo/creó su equivalente en ese idioma.
|
|
* - MISMATCH: el link tiene prefijo de idioma pero el slug no es el
|
|
* correcto (p.ej. suffix -2 divergente entre local y prod), y resuelve a
|
|
* contenido de OTRO idioma o a nada.
|
|
*
|
|
* Solo reporta, no modifica nada (a diferencia de repoint_carta_links.php).
|
|
*
|
|
* Uso:
|
|
* FEA_WP_LOAD=/web/wp-load.php CARTA=54254 php verify_carta_lang_links.php
|
|
* CARTA=54254 php verify_carta_lang_links.php (usa /var/www/html/wp-load.php, para Docker local)
|
|
*/
|
|
|
|
require getenv('FEA_WP_LOAD') ?: '/var/www/html/wp-load.php';
|
|
|
|
$CARTA = (int)(getenv('CARTA') ?: 0);
|
|
if (!$CARTA) {
|
|
fwrite(STDERR, "Falta CARTA=<id del post en español>\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);
|