PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC] ); echo $apply ? "== APPLY ==\n" : "== DRY RUN (add --apply to write) ==\n"; $now = time(); $hasRedirect = $pdo->prepare("SELECT COUNT(*) FROM sys_redirect WHERE deleted = 0 AND source_path = ?"); $insertRedirect = $pdo->prepare( "INSERT INTO sys_redirect (pid, createdon, updatedon, source_host, source_path, target, target_statuscode) VALUES (0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '*', ?, ?, 301)" ); $redirectsAdded = 0; $addRedirect = static function (string $source, string $target) use ($hasRedirect, $insertRedirect, $apply, &$redirectsAdded): void { $hasRedirect->execute([$source]); if ((int)$hasRedirect->fetchColumn() > 0) { return; } $redirectsAdded++; if ($apply) { $insertRedirect->execute([$source, $target]); } }; $pageBySlug = $pdo->prepare("SELECT uid FROM pages WHERE deleted = 0 AND hidden = 0 AND slug = ? LIMIT 1"); $productBySlug = $pdo->prepare("SELECT uid FROM tx_vitec_domain_model_product WHERE deleted = 0 AND hidden = 0 AND slug = ? LIMIT 1"); $newsBySegment = $pdo->prepare("SELECT uid FROM tx_news_domain_model_news WHERE deleted = 0 AND path_segment = ? LIMIT 1"); $targetExists = static function (string $target) use ($pageBySlug, $productBySlug, $newsBySegment): bool { if (str_starts_with($target, '/product/')) { $productBySlug->execute([substr($target, 9)]); return (int)$productBySlug->fetchColumn() > 0; } if (str_starts_with($target, '/news/article/')) { $newsBySegment->execute([substr($target, 14)]); return (int)$newsBySegment->fetchColumn() > 0; } $pageBySlug->execute([$target]); return (int)$pageBySlug->fetchColumn() > 0; }; /* ------------------------------------------------------------------ */ echo "\n1. Platzhalter-SEO-Titel/-Beschreibungen\n"; $rows = $pdo->query("SELECT uid, slug, seo_title FROM pages WHERE deleted = 0 AND (seo_title LIKE 'Title for search engines%' OR description LIKE 'Description for search engines%')")->fetchAll(); foreach ($rows as $r) { echo " #{$r['uid']} {$r['slug']}: seo_title/description geleert\n"; if ($apply) { $pdo->prepare("UPDATE pages SET seo_title = IF(seo_title LIKE 'Title for search engines%', '', seo_title), description = IF(description LIKE 'Description for search engines%', '', description), tstamp = ? WHERE uid = ?")->execute([$now, $r['uid']]); } } /* ------------------------------------------------------------------ */ echo "\n2. News mit verdoppeltem Titel / path_segment\n"; $halve = static function (string $s): ?string { $len = mb_strlen($s); if ($len < 20 || $len % 2 !== 0) { return null; } $h = mb_substr($s, 0, intdiv($len, 2)); return $h === mb_substr($s, intdiv($len, 2)) ? $h : null; }; foreach ($pdo->query("SELECT uid, title, path_segment FROM tx_news_domain_model_news WHERE deleted = 0 AND CHAR_LENGTH(title) > 40") as $r) { $newTitle = $halve((string)$r['title']); if ($newTitle === null) { continue; } $seg = (string)$r['path_segment']; $newSeg = $seg; // doubled slug: "a-b-ca-b-c" -> "a-b-c" $segLen = strlen($seg); if ($segLen % 2 === 0 && substr($seg, 0, intdiv($segLen, 2)) === substr($seg, intdiv($segLen, 2))) { $newSeg = substr($seg, 0, intdiv($segLen, 2)); } echo " #{$r['uid']}: Titel -> [$newTitle]" . ($newSeg !== $seg ? ", Slug -> $newSeg (+Redirect)" : '') . "\n"; if ($apply) { $pdo->prepare("UPDATE tx_news_domain_model_news SET title = ?, path_segment = ?, tstamp = ? WHERE uid = ?")->execute([$newTitle, $newSeg, $now, $r['uid']]); } if ($newSeg !== $seg) { $addRedirect('/news/article/' . $seg, '/news/article/' . $newSeg); } } /* ------------------------------------------------------------------ */ echo "\n3. News path_segment mit Slash\n"; foreach ($pdo->query("SELECT uid, path_segment FROM tx_news_domain_model_news WHERE deleted = 0 AND path_segment LIKE '%/%'") as $r) { $old = (string)$r['path_segment']; $new = basename($old); $newsBySegment->execute([$new]); $taken = (int)$newsBySegment->fetchColumn(); if ($taken > 0 && $taken !== (int)$r['uid']) { $new .= '-' . $r['uid']; } echo " #{$r['uid']}: $old -> $new (+Redirect)\n"; if ($apply) { $pdo->prepare("UPDATE tx_news_domain_model_news SET path_segment = ?, tstamp = ? WHERE uid = ?")->execute([$new, $now, $r['uid']]); } $addRedirect('/news/article/' . $old, '/news/article/' . $new); } /* ------------------------------------------------------------------ */ echo "\n4. Tippfehler\n"; $typos = [ 'continously' => 'continuously', 'continous' => 'continuous', 'indpendent' => 'independent', 'aircrafts' => 'aircraft', 'sponser' => 'sponsor', 'auxillary' => 'auxiliary', 'processer' => 'processor', 'accomodation' => 'accommodation', 'Accomodation' => 'Accommodation', 'Continous' => 'Continuous', ]; $typoTargets = [ 'tt_content' => ['bodytext', 'header'], 'tx_news_domain_model_news' => ['bodytext', 'teaser', 'title'], 'tx_vitec_domain_model_usecase' => ['description', 'teaser'], ]; foreach ($typos as $wrong => $right) { foreach ($typoTargets as $table => $fields) { foreach ($fields as $field) { $n = (int)$pdo->query("SELECT COUNT(*) FROM $table WHERE deleted = 0 AND $field LIKE " . $pdo->quote('%' . $wrong . '%'))->fetchColumn(); if ($n === 0) { continue; } echo " $wrong -> $right: $table.$field ($n)\n"; if ($apply) { $pdo->exec("UPDATE $table SET $field = REPLACE($field, " . $pdo->quote($wrong) . ", " . $pdo->quote($right) . "), tstamp = $now WHERE deleted = 0 AND $field LIKE " . $pdo->quote('%' . $wrong . '%')); } } } } /* ------------------------------------------------------------------ */ echo "\n5. Tote Alt-Links (zweite Welle, inkl. datapath.co.uk / utm-Varianten)\n"; $awardSeg = 'aetria-award-wins-set-the-tone-for-datapaths-best-ever-ise-week'; $newsBySegment->execute([$awardSeg]); $awardTarget = (int)$newsBySegment->fetchColumn() > 0 ? '/news/article/' . $awardSeg : '/insights/news'; $mapping2 = [ '/resource-center/legacy-products' => '/products/capture-and-graphics', '/resource-center/legacy-products/imagedp4' => '/products/image-graphics-cards', '/resource-center/legacy-products/datapath-x4' => '/products/video-wall-controllers-and-management', '/resource-center/legacy-products/datapath-dl8' => '/products/video-wall-controllers-and-management', '/legacy-products/imagedp4-plus' => '/products/image-graphics-cards', '/resource-center/get-support' => '/support', '/services/premium-service-package' => '/support/support-plans', '/services/training' => '/support/training', '/contact-sales' => '/contact/contact-form', '/aetria-use-cases/oil-and-gas-control-room' => '/markets/critical-national-infrastructure/energy-and-utilities', '/aetria-use-cases/energy-trading-and-dispatch' => '/markets/critical-national-infrastructure/energy-and-utilities', '/aetria-use-cases/cctv-for-university-campus' => '/markets/education', '/video-wall-solutions/commercial-video-walls' => '/solutions/video-wall-data-visualisation', '/video-wall-solutions/control-rooms' => '/solutions/control-room-command-centre-solutions', '/video-wall-solutions/projection-mapping' => '/solutions/video-wall-data-visualisation', '/video-wall-solutions/video-wall-for-security-suites' => '/solutions/security-surveillance-solutions', '/video-wall-solutions' => '/solutions/video-wall-data-visualisation', '/insights/success-stories' => '/success-stories', '/datapath-products' => '/products', '/datapath-products/aetria-control-room-solutions' => '/products/aetria', '/datapath-products/aetria-control-room-solutions/aetria-overview' => '/products/aetria', '/datapath-products/aetria-control-room-solutions/aetria-command-center' => '/product/aetria-command-center', '/datapath-products/aetria-control-room-solutions/aetria-workstation' => '/product/aetria-workstation', '/datapath-products/aetria-control-room-solutions/aetria-wallcontrol' => '/product/aetria-wallcontrol', '/datapath-products/video-wall-controllers/vsn-v3' => '/product/vsn-v3', '/datapath-products/video-wall-controllers/vsn' => '/products/vsn-series-video-wall-controllers', '/datapath-products/video-wall-controllers/vsn-series' => '/products/vsn-series-video-wall-controllers', '/datapath-products/video-wall-controllers/vsnmicro-600' => '/product/vsnmicro-600', '/datapath-products/video-wall-controllers/datapath-fx4' => '/product/fx4', '/datapath-products/video-distribution-kvm/aligo-4k-avoip-with-kvm' => '/products/aligo', '/datapath-products/video-distribution-kvm' => '/products/av-over-ip-and-kvm', '/datapath-products/video-capture-cards/visionsc-range/visionsc-uhd2' => '/product/visionsc-uhd2', '/datapath-products/video-capture-cards/visionsc-range/visionsc-hd4' => '/product/visionsc-hd4', '/datapath-products/video-capture-cards/visionsc-range/visionsc-s2' => '/product/visionsc-s2', '/datapath-products/video-wall-management-software/wallcontrol-10-software' => '/product/wall-control-10', '/datapath-products/graphics-products/image2k' => '/product/image-2k', '/datapath-products/components-accessories/rack-mounting-kits' => '/products', '/datapath-products/sqx-ip-capture/active-sqx' => '/product/activesqx', '/datapath-products/video-wall-control' => '/products/video-wall-controllers-and-management', '/' . $awardSeg => $awardTarget, ]; $missing = 0; foreach (array_unique(array_values($mapping2)) as $t) { if (!$targetExists($t)) { echo " !! Ziel fehlt: $t\n"; $missing++; } } if ($missing > 0 && $apply) { exit("Abbruch: Ziele fehlen.\n"); } $hostPrefix = '(?:https?://(?:www\.)?datapath(?:-us)?\.(?:co\.uk|com))?'; $linkTables = ['tx_news_domain_model_news' => 'bodytext', 'tt_content' => 'bodytext']; $linkHits = 0; foreach ($linkTables as $table => $field) { $select = $pdo->query("SELECT uid, $field AS body FROM $table WHERE deleted = 0 AND ($field LIKE '%datapath%' OR $field LIKE '%/resource-center/%' OR $field LIKE '%/services/%' OR $field LIKE '%/contact-sales%' OR $field LIKE '%/aetria-use-cases/%' OR $field LIKE '%/video-wall-solutions%' OR $field LIKE '%/insights/success-stories%' OR $field LIKE '%/legacy-products/%' OR $field LIKE '%aetria-award-wins%')"); $update = $pdo->prepare("UPDATE $table SET $field = ?, tstamp = ? WHERE uid = ?"); foreach ($select as $r) { $body = (string)$r['body']; $new = $body; foreach ($mapping2 as $old => $target) { $pattern = '#href="' . $hostPrefix . preg_quote($old, '#') . '/?(?:\?[^"]*)?"#'; $new = preg_replace($pattern, 'href="' . $target . '"', $new) ?? $new; } if ($new !== $body) { $linkHits++; echo " $table #{$r['uid']}: Links ersetzt\n"; if ($apply) { $update->execute([$new, $now, $r['uid']]); } } } } echo " Records mit ersetzten Links: $linkHits\n"; foreach ($mapping2 as $old => $target) { $addRedirect($old, $target); $addRedirect($old . '/', $target); } /* ------------------------------------------------------------------ */ echo "\n6. http://www.vitec.com./ (Punkt-Tippfehler)\n"; $n = (int)$pdo->query("SELECT COUNT(*) FROM tx_news_domain_model_news WHERE deleted = 0 AND bodytext LIKE '%www.vitec.com./%'")->fetchColumn(); echo " $n Record(s)\n"; if ($apply && $n > 0) { $pdo->exec("UPDATE tx_news_domain_model_news SET bodytext = REPLACE(REPLACE(bodytext, 'http://www.vitec.com./', 'https://www.vitec.com/'), 'https://www.vitec.com./', 'https://www.vitec.com/'), tstamp = $now WHERE deleted = 0 AND bodytext LIKE '%www.vitec.com./%'"); } /* ------------------------------------------------------------------ */ echo "\n7. Redirects fuer Record-Shells und verwaiste Produkt-URLs\n"; foreach ([ '/product' => '/products', '/news/article' => '/insights/news', '/success-stories/story' => '/success-stories', '/product/artiosign' => '/products/video-wall-management-software', '/product/artioview' => '/products/video-wall-management-software', '/product/x-view-integrated-displays' => '/products/x-view-integrated-displays', ] as $old => $target) { $addRedirect($old, $target); $addRedirect($old . '/', $target); } /* ------------------------------------------------------------------ */ echo "\n8. Meta-Description /datasheets\n"; $st = $pdo->prepare("UPDATE pages SET description = ?, tstamp = ? WHERE uid = 17 AND (description IS NULL OR description = '')"); $desc = 'Download VITEC and Datapath product datasheets: encoders and decoders, IPTV and digital signage platforms, video wall controllers, capture cards and more - searchable by product and category.'; if ($apply) { $st->execute([$desc, $now]); echo " gesetzt (" . $st->rowCount() . ")\n"; } else { echo " wird gesetzt, falls leer\n"; } /* ------------------------------------------------------------------ */ echo "\n9. WordPress-Reste in den SEO-Artikeln\n"; $seoUids = [232,234,235,236,237,238,240,241,242,243,244,245,246,247,248,249,252]; $sel = $pdo->query("SELECT uid, path_segment, bodytext FROM tx_news_domain_model_news WHERE deleted = 0 AND uid IN (" . implode(',', $seoUids) . ")"); $upd = $pdo->prepare("UPDATE tx_news_domain_model_news SET bodytext = ?, tstamp = ? WHERE uid = ?"); foreach ($sel as $r) { $b = (string)$r['bodytext']; $o = $b; $log = []; $b = preg_replace('#]*src="data:image/[^"]*"[^>]*>\s*#i', '', $b, -1, $c1) ?? $b; if ($c1) { $log[] = "$c1 Platzhalter-Bilder"; } $b = preg_replace('#

[^<]*getWR360PopupSkin[^<]*

\s*#i', '', $b, -1, $c2) ?? $b; if ($c2) { $log[] = "Script-Rest"; } $b = preg_replace('#\s+class="wp-[^"]*"#i', '', $b, -1, $c3) ?? $b; if ($c3) { $log[] = "$c3 wp-Klassen"; } $b = preg_replace('#\s+data-[a-z0-9-]+="[^"]*"#i', '', $b, -1, $c4) ?? $b; if ($c4) { $log[] = "$c4 data-Attribute"; } // bare description text between a product

and the following link $b = preg_replace('#(

)\s*([^<\s][^<]{20,}?)\s*(?=|