From 80f6da7949908f36e8775746c045f2032ceba9f6 Mon Sep 17 00:00:00 2001 From: Oliver Rasche Date: Tue, 27 Oct 2026 15:19:38 +0100 Subject: [PATCH] Retire the six old-taxonomy category stubs under /products - diagnosis first (migrations/check_old_stubs.php, kept): the six old-taxonomy pages (#451-454, #456, #458) were completely empty - no content elements and NO family child pages (the family workbooks were deliberately never imported), so nothing needed moving - migrations/retire_old_category_stubs.php (dry-run by default, guards against children/content) soft-deletes each stub and queues a 301 sys_redirect onto its new-taxonomy equivalent; existing redirects for a path are kept - applied and verified live: all six old paths answer with the 301 redirect envelope onto the correct new category page, and the main navigation now shows exactly the nine new categories in sitemap order Co-Authored-By: Claude Fable 5 --- migrations/check_old_stubs.php | 50 ++++++++++++++ migrations/retire_old_category_stubs.php | 85 ++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 migrations/check_old_stubs.php create mode 100644 migrations/retire_old_category_stubs.php diff --git a/migrations/check_old_stubs.php b/migrations/check_old_stubs.php new file mode 100644 index 0000000..86d6ec3 --- /dev/null +++ b/migrations/check_old_stubs.php @@ -0,0 +1,50 @@ + PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC] +); + +function tree(PDO $pdo, int $pid, int $depth): void +{ + $rows = $pdo->query("SELECT uid, title, slug, doktype, layout, hidden, nav_hide, sorting + FROM pages WHERE deleted = 0 AND pid = $pid ORDER BY sorting")->fetchAll(); + foreach ($rows as $r) { + $ce = (int)$pdo->query("SELECT COUNT(*) FROM tt_content WHERE deleted = 0 AND hidden = 0 AND pid = {$r['uid']}")->fetchColumn(); + printf("%s#%-5d dok=%d lay=%-2d hid=%d nav=%d ce=%-3d %-55s %s\n", + str_repeat(' ', $depth), $r['uid'], $r['doktype'], $r['layout'], $r['hidden'], $r['nav_hide'], $ce, $r['slug'], $r['title']); + tree($pdo, (int)$r['uid'], $depth + 1); + } +} + +foreach ([451, 452, 453, 454, 456, 458] as $stub) { + $r = $pdo->query("SELECT uid, title, slug, hidden, nav_hide FROM pages WHERE uid = $stub")->fetch(); + $ce = (int)$pdo->query("SELECT COUNT(*) FROM tt_content WHERE deleted = 0 AND hidden = 0 AND pid = $stub")->fetchColumn(); + printf("STUB #%-4d hid=%d nav=%d ce=%-3d %-50s %s\n", $r['uid'], $r['hidden'], $r['nav_hide'], $ce, $r['slug'], $r['title']); + tree($pdo, $stub, 1); + echo "\n"; +} diff --git a/migrations/retire_old_category_stubs.php b/migrations/retire_old_category_stubs.php new file mode 100644 index 0000000..d31eace --- /dev/null +++ b/migrations/retire_old_category_stubs.php @@ -0,0 +1,85 @@ + PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC] +); + +$map = [ + '/products/platforms-and-end-points' => '/products/iptv-and-digital-signage', + '/products/ip-video-streaming' => '/products/video-encoding-and-streaming', + '/products/control-room-solutions' => '/products/control-room-platforms', + '/products/avoip-distribution-kvm' => '/products/av-over-ip-and-kvm', + '/products/graphics-multi-display' => '/products/graphics-and-multi-display', + '/products/infrastructure-accessories' => '/products/infrastructure-and-accessories', +]; + +echo ($apply ? "APPLY\n" : "DRY-RUN\n"); +foreach ($map as $oldSlug => $newSlug) { + $stub = $pdo->prepare('SELECT uid, title FROM pages WHERE deleted = 0 AND slug = ?'); + $stub->execute([$oldSlug]); + $stub = $stub->fetch(); + if (!$stub) { + echo " = $oldSlug: already gone\n"; + continue; + } + $uid = (int)$stub['uid']; + $children = (int)$pdo->query("SELECT COUNT(*) FROM pages WHERE deleted = 0 AND pid = $uid")->fetchColumn(); + $content = (int)$pdo->query("SELECT COUNT(*) FROM tt_content WHERE deleted = 0 AND pid = $uid")->fetchColumn(); + if ($children > 0 || $content > 0) { + echo " !! #$uid $oldSlug has $children child page(s) / $content element(s) - SKIPPED, decide manually\n"; + continue; + } + $target = $pdo->prepare('SELECT uid FROM pages WHERE deleted = 0 AND slug = ?'); + $target->execute([$newSlug]); + $targetUid = (int)($target->fetchColumn() ?: 0); + if ($targetUid === 0) { + echo " !! target $newSlug not found - #$uid skipped\n"; + continue; + } + $stmt = $pdo->prepare('SELECT COUNT(*) FROM sys_redirect WHERE deleted = 0 AND source_path = ?'); + $stmt->execute([$oldSlug]); + $hasRedirect = (int)$stmt->fetchColumn(); + echo " ~ DELETE #$uid \"{$stub['title']}\" ($oldSlug) -> 301 to $newSlug (#$targetUid)" . ($hasRedirect ? ' [redirect exists, kept]' : '') . "\n"; + if (!$apply) { + continue; + } + $pdo->prepare('UPDATE pages SET deleted = 1, tstamp = UNIX_TIMESTAMP() WHERE uid = ?')->execute([$uid]); + if (!$hasRedirect) { + $pdo->prepare( + "INSERT INTO sys_redirect (pid, createdon, updatedon, source_host, source_path, target, target_statuscode) + VALUES (0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '*', ?, ?, 301)" + )->execute([$oldSlug, 't3://page?uid=' . $targetUid]); + } +} +echo $apply ? "Done. Flush the cache (redirects are cached).\n" : "DRY RUN - add --apply to write.\n";