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$2
', $b, -1, $c5) ?? $b; if ($c5) { $log[] = "$c5 nackte Textabsaetze gekapselt"; } $b = preg_replace('#]*)>\s*View products?\s*#i', 'View products', $b, -1, $c6) ?? $b; if ($c6) { $log[] = "$c6 View-products-Links normalisiert"; } if ($b !== $o) { echo " #{$r['uid']} {$r['path_segment']}: " . implode(', ', $log) . "\n"; if ($apply) { $upd->execute([$b, $now, $r['uid']]); } } } /* ------------------------------------------------------------------ */ echo "\n10. News-Zeiger-Records (type=1) -> Inhalt der alten Seite uebernehmen\n"; $allowedTags = ''; $stripAttrs = static function (string $html): string { // keep href/target on links, drop everything else (style, class, ids) $html = preg_replace_callback('#]*)>#i', static function (array $m): string { preg_match('/href="([^"]*)"/i', $m[1], $h); preg_match('/target="([^"]*)"/i', $m[1], $t); return ''; }, $html) ?? $html; return preg_replace('#<(p|h[2-4]|ul|ol|li|strong|em|b|i|blockquote|br)\b[^>]*>#i', '<$1>', $html) ?? $html; }; $collectContent = null; $collectContent = static function (int $pid, int $parent, array &$texts, array &$imageRefs) use ($pdo, &$collectContent, $allowedTags, $stripAttrs): void { $st = $pdo->prepare("SELECT uid, CType, bodytext, header FROM tt_content WHERE pid = ? AND tx_container_parent = ? AND deleted = 0 AND hidden = 0 ORDER BY colPos, sorting"); $st->execute([$pid, $parent]); foreach ($st->fetchAll() as $el) { $ctype = (string)$el['CType']; if (str_starts_with($ctype, 'vitec_container') || str_starts_with($ctype, 'vitec_cols')) { $collectContent($pid, (int)$el['uid'], $texts, $imageRefs); continue; } if (in_array($ctype, ['image', 'textpic', 'textmedia'], true)) { $refs = $pdo->prepare("SELECT uid FROM sys_file_reference WHERE tablenames = 'tt_content' AND uid_foreign = ? AND fieldname IN ('image', 'assets', 'media') AND deleted = 0 AND hidden = 0 ORDER BY sorting_foreign"); $refs->execute([(int)$el['uid']]); foreach ($refs->fetchAll() as $ref) { $imageRefs[] = (int)$ref['uid']; } } if (in_array($ctype, ['text', 'textpic', 'textmedia'], true)) { $t = trim((string)$el['bodytext']); if ($t !== '') { $texts[] = $stripAttrs(strip_tags($t, $allowedTags)); } continue; } if ($ctype === 'html') { $raw = (string)$el['bodytext']; if (preg_match('#\s*]*>(.*?)#is', $raw, $s)) { $cite = trim(strip_tags($s[1])); } $texts[] = ']*>(.*?)#is', $raw, $q)) { $cite = ''; if (preg_match('#
'; continue; } if (stripos($raw, '' . trim(strip_tags($q[1])) . '
' . ($cite !== '' ? '' . $cite . '
' : '') . '