/ (rompen en prod). * - Traducciones con enlaces relativos // (rompen en local, falta /fea). * - Enlaces que apuntan a un artículo en otro idioma (los re-apunta a la * traducción del MISMO idioma de la carta si existe). * * Para CADA : si el slug resuelve a un post del sitio, se reescribe al * permalink absoluto del post en el idioma de la página (fallback: el que haya). * Si el slug NO resuelve a ningún post (legacy .html, externos), se deja intacto. * * Uso (dentro del contenedor, con WP cargado): * php fix_carta_links.php -> DRY-RUN (no escribe nada) * APPLY=1 php fix_carta_links.php -> aplica y guarda backup en /tmp/fix_links_bak/ */ if (!defined('ABSPATH')) { require getenv('FEA_WP_LOAD') ?: '/var/www/html/wp-load.php'; } global $wpdb; $APPLY = getenv("APPLY") === "1"; $BAKDIR = "/tmp/fix_links_bak"; if ($APPLY) @mkdir($BAKDIR, 0777, true); // Conjunto de trabajo: posts ES con localhost:8081 + todas sus traducciones. $es_ids = $wpdb->get_col( "SELECT ID FROM wp_posts WHERE post_type='post' AND post_status IN ('publish','draft') AND post_content LIKE '%localhost:8081%'" ); $targets = []; foreach ($es_ids as $id) { $targets[$id] = true; foreach (pll_get_post_translations($id) as $tid) $targets[$tid] = true; } $targets = array_keys($targets); /** Extrae el slug candidato de un href, o null si no parece interno. */ function slug_from_href($href) { $href = html_entity_decode(trim($href)); if ($href === '' || $href[0] === '#') return null; if (preg_match('~^(mailto:|tel:|javascript:)~i', $href)) return null; if (stripos($href, '.html') !== false) return null; // legacy Joomla if (stripos($href, 'feadulta.com') !== false) return null; // dominio viejo if (strpos($href, '%') !== false) return null; // placeholders [unsubscribe] // Quitar querystring / fragment $href = preg_replace('~[?#].*$~', '', $href); // Quitar esquema+host si los hay $path = preg_replace('~^https?://[^/]+~i', '', $href); if ($path === '') return null; if ($path[0] !== '/') return null; // relativo raro -> no tocar if (stripos($path, '/category/') !== false) return null; // categorías, no posts if (stripos($path, '/wp-') === 0) return null; // Quitar /fea y prefijo de idioma $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 null; // solo // de un nivel return $segs[0]; } $total_posts = 0; $total_links = 0; $samples = 0; foreach ($targets as $pid) { $post = get_post($pid); if (!$post) continue; $lang = pll_get_post_language($pid) ?: 'es'; $content = $post->post_content; $changes = 0; $new = preg_replace_callback('~href="([^"]*)"~i', function($m) use ($lang, &$changes, $wpdb) { $href = $m[1]; $slug = slug_from_href($href); if ($slug === null) return $m[0]; $found = $wpdb->get_var($wpdb->prepare( "SELECT ID FROM wp_posts WHERE post_name=%s AND post_type='post' AND post_status='publish' LIMIT 1", $slug)); if (!$found) return $m[0]; // no es un post -> intacto // Resolver a la traducción del idioma de la página $target = pll_get_post((int)$found, $lang); if (!$target) $target = (int)$found; $url = get_permalink($target); if (!$url || $url === $href) return $m[0]; $changes++; return 'href="' . esc_url($url) . '"'; }, $content); if ($changes > 0) { $total_posts++; $total_links += $changes; echo sprintf("#%d [%s] «%s» — %d enlace(s) reescrito(s)\n", $pid, $lang, mb_substr($post->post_title, 0, 40), $changes); if ($APPLY) { file_put_contents("$BAKDIR/$pid.html", $content); $wpdb->update($wpdb->posts, ['post_content' => $new], ['ID' => $pid]); clean_post_cache($pid); } } } echo "\n"; echo ($APPLY ? "APLICADO" : "DRY-RUN") . ": $total_links enlaces en $total_posts posts.\n"; if (!$APPLY) echo "Para aplicar: APPLY=1 php fix_carta_links.php (backup en $BAKDIR)\n";