PDO::ERRMODE_EXCEPTION, ]); echo "=== Fix Numeric Author Categories ===\n"; echo $dry_run ? "[DRY RUN]\n\n" : "[LIVE RUN]\n\n"; // ------------------------------------------------------------------------- // Mapping: numeric value → author name (from K2 extra field "Autor") // ------------------------------------------------------------------------- $autor_map = [ 1 => "Fray Marcos", 2 => "José Antonio Pagola", 3 => "Enrique Martínez Lozano", 4 => "José Enrique Galarreta", 5 => "José Arregi", 6 => "Eloy Roy", 7 => "Dolores Aleixandre", 9 => "Florentino Ulibarri", 10 => "Rafael Calvo", 11 => "Julián Mellado", 12 => "Vicente Martínez", 13 => "Matilde Gastalver", 14 => "Koldo Aldai", 15 => "Sandra Hojman", 16 => "Leonardo Boff", 17 => "José M. Castillo", 18 => "Luís Alemán", 19 => "Juan José Tamayo", 20 => "José Ignacio González Faus", 22 => "José Manuel Vidal", 23 => "Isabel Gómez-Acebo", 31 => "Faustino Vilabrille", 32 => "Víctor Daniel Blanco", 33 => "Nuevo Testamento", 36 => "Gabriel Mª Otalora", 38 => "Luís García Orso", 40 => "María Teresa Sánchez Carmona", 41 => "Emma Martínez Ocaña", 45 => "Mari Patxi Ayerra", 49 => "Jesús Bastante", 52 => "J. A. Estrada", 53 => "Rafael Díaz Arias", 58 => "Susana Merino", 69 => "Asociación de teólogos y teólogas Juan XXIII", 73 => "José Ignacio Calleja", 75 => "Autor desconocido", 76 => "Gerardo Villar", 79 => "José Sánchez Luque", 83 => "Mari Paz López Santos", 84 => "Patricia Paz", 87 => "Pedro Casaldáliga", 88 => "Foro «Curas de Madrid»", 92 => "Xavier Pikaza", 96 => "Benjamín Forcano", 97 => "Ima Sanchís", 108 => "Pedro M. Lamet", 114 => "Juan G. Bedoya", 115 => "Juan Masiá", 123 => "Frei Betto", 124 => "Juan Cejudo", 125 => "Miguel Ángel Mesa", 126 => "Carlos F. Barberá", 127 => "Mariá Corbí", 129 => "Rafael Fernando Navarro", 149 => "José María Díez Alegría", 174 => "Carmen Soto", 175 => "Hans Küng", 188 => "Fidel Aizpurúa", 194 => "Pepcastelló", 208 => "Juan Yzuel", 234 => "Maite García Romero", 263 => "Gonzalo Haya", 288 => "Redes Cristianas", 303 => "Víctor Codina", 306 => "José María García-Mauriño", 312 => "Patxi Loidi", 321 => "Jesús Gil García", 323 => "John P. Meier", 325 => "Rogelio Cárdenas", 329 => "Pablo Ordaz", 345 => "Papa Francisco", 347 => "Vicky Irigaray", 357 => "Marco Antonio Velásquez Uribe", 362 => "Fernando Bermúdez López", 374 => "Pablo", 375 => "José Luis Sicre", 376 => "Miguel A. Munárriz Casajús", 382 => "Santiago Agrelo", 392 => "Felix Jiménez Tutor", 396 => "José María Alvarez", 399 => "Hechos", 404 => "Bruno Álvarez", 412 => "Luis Miguel Modino", 418 => "Varios autores", 435 => "Voces cristianas de Sevilla", 437 => "Religión Digital", 443 => "Francisco Bautista", 444 => "Yolanda Chávez", 449 => "Atrio", 450 => "Carolina Abarca", 465 => "Magdalena Bennasar", 516 => "Eclesalia", 520 => "Antonio Aradillas", 529 => "Humanismo Sin credos", 540 => "Juan Zapatero", 557 => "Marifé Ramos González", 566 => "Marta García", 570 => "María Dolores López Guzmán", 583 => "Inma Eibe", 615 => "Íñigo García Blanco", ]; // ------------------------------------------------------------------------- // Fetch all numeric categories from WordPress // ------------------------------------------------------------------------- $stmt = $pdo->query(" SELECT t.term_id, t.name, t.slug, tt.count FROM wp_terms t JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id WHERE tt.taxonomy = 'category' AND t.name REGEXP '^[0-9]+$' ORDER BY CAST(t.name AS UNSIGNED) "); $numeric_cats = $stmt->fetchAll(PDO::FETCH_ASSOC); echo "Numeric categories found: " . count($numeric_cats) . "\n\n"; $stats = ['renamed' => 0, 'merged' => 0, 'skipped' => 0, 'no_map' => 0]; foreach ($numeric_cats as $cat) { $num_val = (int)$cat['name']; $term_id = (int)$cat['term_id']; $post_count = (int)$cat['count']; if (!isset($autor_map[$num_val])) { echo " [SKIP] No mapping for value $num_val (term_id=$term_id, $post_count posts)\n"; $stats['no_map']++; continue; } $new_name = $autor_map[$num_val]; // Check if a category with this name already exists $existing = $pdo->prepare(" SELECT t.term_id, tt.count FROM wp_terms t JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id WHERE tt.taxonomy = 'category' AND t.name = ? AND t.term_id != ? "); $existing->execute([$new_name, $term_id]); $existing_cat = $existing->fetch(PDO::FETCH_ASSOC); if ($existing_cat) { // MERGE: move posts from numeric category to the existing named category $target_term_id = (int)$existing_cat['term_id']; echo " [MERGE] \"$num_val\" ($post_count posts) → \"$new_name\" (term_id=$target_term_id, existing {$existing_cat['count']} posts)\n"; if (!$dry_run) { // Get term_taxonomy_id for both $tt_stmt = $pdo->prepare("SELECT term_taxonomy_id FROM wp_term_taxonomy WHERE term_id = ? AND taxonomy = 'category'"); $tt_stmt->execute([$term_id]); $src_tt_id = (int)$tt_stmt->fetchColumn(); $tt_stmt->execute([$target_term_id]); $dst_tt_id = (int)$tt_stmt->fetchColumn(); // Move post relationships (avoiding duplicates) $pdo->prepare(" UPDATE IGNORE wp_term_relationships SET term_taxonomy_id = ? WHERE term_taxonomy_id = ? ")->execute([$dst_tt_id, $src_tt_id]); // Delete remaining relationships for source (duplicates that weren't moved) $pdo->prepare("DELETE FROM wp_term_relationships WHERE term_taxonomy_id = ?")->execute([$src_tt_id]); // Update count on target $pdo->prepare(" UPDATE wp_term_taxonomy SET count = ( SELECT COUNT(*) FROM wp_term_relationships WHERE term_taxonomy_id = ? ) WHERE term_taxonomy_id = ? ")->execute([$dst_tt_id, $dst_tt_id]); // Delete numeric category $pdo->prepare("DELETE FROM wp_term_taxonomy WHERE term_id = ? AND taxonomy = 'category'")->execute([$term_id]); $pdo->prepare("DELETE FROM wp_terms WHERE term_id = ?")->execute([$term_id]); } $stats['merged']++; } else { // RENAME: update name and slug $new_slug = sanitize_slug($new_name); echo " [RENAME] \"$num_val\" → \"$new_name\" (term_id=$term_id, $post_count posts)\n"; if (!$dry_run) { $pdo->prepare("UPDATE wp_terms SET name = ?, slug = ? WHERE term_id = ?")->execute([$new_name, $new_slug, $term_id]); } $stats['renamed']++; } } echo "\n=== Results ===\n"; echo "Renamed: {$stats['renamed']}\n"; echo "Merged: {$stats['merged']}\n"; echo "Skipped (no map): {$stats['no_map']}\n"; echo "\nDone.\n"; // ------------------------------------------------------------------------- function sanitize_slug(string $name): string { $slug = mb_strtolower($name, 'UTF-8'); $slug = str_replace( ['á','é','í','ó','ú','ü','ñ','ã','â','à','ê','ô','ç','ú','ó','ä','ö'], ['a','e','i','o','u','u','n','a','a','a','e','o','c','u','o','a','o'], $slug ); $slug = preg_replace('/[^a-z0-9\s-]/', '', $slug); $slug = preg_replace('/[\s]+/', '-', trim($slug)); $slug = preg_replace('/-+/', '-', $slug); return trim($slug, '-'); }