- vitec:import-product-images: attach staged photos (fileadmin/user_upload/ products/<slug>/, 116 files harvested from vitec.com and datapath.co.uk carousels) to image-less products via FAL/DataHandler; fill-up only. fix_image_reference_fieldname.php repairs the first run's references (TCA field is productimage, not the JSON key images) - vitec:link-product-downloads: match the download records imported on 2026-08-06 to products by title (doc-type/brand/role suffix stripping, alias table for live-site naming deviations, series rules for g45xx/e38xx/ chassis docs); 55 unique-match links added, add-only, idempotent - SEO meta: seo_meta_vitec.json + apply_seo_meta.php fill empty seotitle/ seometa from the live vitec.com product pages (11 products, fill-up only)"
76 lines
2.7 KiB
PHP
76 lines
2.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Fill empty seotitle/seometa product fields from a scraped mapping file
|
|
* (migrations/seo_meta_vitec.json - source: the live vitec.com product
|
|
* pages, 2026-09-04). Fill-up ONLY: fields that already hold a value are
|
|
* never overwritten.
|
|
*
|
|
* Dry run: php migrations/apply_seo_meta.php
|
|
* Write: php migrations/apply_seo_meta.php --apply
|
|
*/
|
|
|
|
$apply = in_array('--apply', $argv, true);
|
|
|
|
$root = null;
|
|
$dir = __DIR__;
|
|
for ($i = 0; $i < 5; $i++) {
|
|
if (is_file($dir . '/config/system/settings.php')) {
|
|
$root = $dir;
|
|
break;
|
|
}
|
|
$dir = dirname($dir);
|
|
}
|
|
if ($root === null) {
|
|
exit("Could not locate project root above " . __DIR__ . "\n");
|
|
}
|
|
|
|
$map = json_decode((string)file_get_contents(__DIR__ . '/seo_meta_vitec.json'), true);
|
|
if (!is_array($map)) {
|
|
exit("seo_meta_vitec.json missing or invalid.\n");
|
|
}
|
|
unset($map['_quelle']);
|
|
|
|
$settings = require $root . '/config/system/settings.php';
|
|
$db = $settings['DB']['Connections']['Default'];
|
|
$pdo = new PDO(
|
|
sprintf('mysql:host=%s;port=%s;dbname=%s;charset=utf8mb4', $db['host'] ?? 'localhost', $db['port'] ?? 3306, $db['dbname'] ?? ''),
|
|
$db['user'] ?? '',
|
|
$db['password'] ?? '',
|
|
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]
|
|
);
|
|
|
|
$select = $pdo->prepare("SELECT uid, title, seotitle, seometa FROM tx_vitec_domain_model_product WHERE deleted = 0 AND slug = ?");
|
|
$update = $pdo->prepare("UPDATE tx_vitec_domain_model_product SET seotitle = ?, seometa = ?, tstamp = ? WHERE uid = ?");
|
|
|
|
$written = 0;
|
|
foreach ($map as $slug => $meta) {
|
|
$select->execute([$slug]);
|
|
$product = $select->fetch();
|
|
if (!$product) {
|
|
echo "FEHLT $slug - kein Produkt\n";
|
|
continue;
|
|
}
|
|
$newTitle = trim((string)$product['seotitle']) === '' ? trim((string)($meta['seotitle'] ?? '')) : (string)$product['seotitle'];
|
|
$newMeta = trim((string)$product['seometa']) === '' ? trim((string)($meta['seometa'] ?? '')) : (string)$product['seometa'];
|
|
$changes = [];
|
|
if ($newTitle !== (string)$product['seotitle']) {
|
|
$changes[] = 'seotitle';
|
|
}
|
|
if ($newMeta !== (string)$product['seometa']) {
|
|
$changes[] = 'seometa';
|
|
}
|
|
if ($changes === []) {
|
|
echo "ok {$product['title']} - beide Felder bereits gefuellt oder keine Daten\n";
|
|
continue;
|
|
}
|
|
printf("%s %s (uid %d): %s\n", $apply ? 'WRITE ' : 'plan ', $product['title'], $product['uid'], implode(' + ', $changes));
|
|
if ($apply) {
|
|
$update->execute([$newTitle, $newMeta, time(), (int)$product['uid']]);
|
|
}
|
|
$written++;
|
|
}
|
|
printf("\n%d Produkt(e) %s.%s\n", $written, $apply ? 'geschrieben' : 'geplant', $apply ? ' Cache leeren: vendor/bin/typo3 cache:flush' : ' Mit --apply schreiben.');
|