Align product records with sitemap V2; product family model; CLI workbook import
- vitec:migrate-product-structure: exact V2 titles, Milestone typo fix (incl. slug), QTX100 stray VSN category removed, Aligo record moved to its own category with slug /product/aligo, new Aligo Workstation record takes over /product/aligo-workstation - product families (sitemap column K) are ordinary content pages now: vitec:remove-family-records deletes the interim landing records again, reset_subproduct_flags.php clears the misused subproduct flag (the list renderer has always excluded subproduct=1) - vitec:import-product-workbook: non-interactive counterpart of the module import (same reader, mapping and DataHandler path); Arqa imported, Aligo re-applied with the corrected capabilities markup - ProductXlsxReader: new :copy cell selector (Body Copy with CTA fallback) absorbs the agency's column drift; default teaser mapping uses it - ProductListJsonRenderer: selected categories now match their whole subtree, results ordered by category tree position, sheet order within a category - read-only diagnostics: check_product_structure.php, check_productlist_ces.php
This commit is contained in:
1 parent
7833e1b668
commit
5499ca54af
12 files changed
+1186
-121
No files matched your search
@@ -170,6 +170,22 @@ final class ProductXlsxReader
|
||||
);
|
||||
}
|
||||
|
||||
// Drift-proof copy selector: the agency fills text sometimes into
|
||||
// "Body Copy" (D), sometimes into "CTA / Card Copy" (E) - Aligo's
|
||||
// hero one-liner sits in D, Arqa's in E. `copy` reads body and
|
||||
// falls back to cta, so one stored mapping fits every delivery.
|
||||
$copy = trim((string)($component['body'] ?? ''));
|
||||
if ($copy === '') {
|
||||
$copy = trim((string)($component['cta'] ?? ''));
|
||||
}
|
||||
if ($copy !== '') {
|
||||
$groups['Components'][] = $this->entry(
|
||||
'c:' . $name . '#' . $component['occurrence'] . ':copy',
|
||||
$name . $suffix . ' · Copy (Body, sonst CTA)',
|
||||
$copy
|
||||
);
|
||||
}
|
||||
|
||||
// Section-intro rows ("... — H2") additionally as ONE ready RTE
|
||||
// value: heading plus paragraph in the exact markup the finished
|
||||
// MGW-Diamond product stores in `textrelatedproducts` - imported
|
||||
@@ -250,10 +266,18 @@ final class ProductXlsxReader
|
||||
$value = $parsed['seo'][substr($selector, 2)] ?? null;
|
||||
return is_string($value) && $value !== '' ? $value : null;
|
||||
}
|
||||
if (str_starts_with($selector, 'c:') && preg_match('/^c:(.+)#(\d+):(title|body|cta)$/', $selector, $m)) {
|
||||
if (str_starts_with($selector, 'c:') && preg_match('/^c:(.+)#(\d+):(title|body|cta|copy)$/', $selector, $m)) {
|
||||
foreach ($parsed['components'] ?? [] as $component) {
|
||||
if ((string)$component['component'] === $m[1] && (int)$component['occurrence'] === (int)$m[2]) {
|
||||
$value = (string)($component[$m[3]] ?? '');
|
||||
if ($m[3] === 'copy') {
|
||||
$value = trim((string)($component['body'] ?? ''));
|
||||
if ($value === '') {
|
||||
$value = trim((string)($component['cta'] ?? ''));
|
||||
}
|
||||
$value = trim((string)preg_replace('/\|\s*CTA:.*$/su', '', $value));
|
||||
} else {
|
||||
$value = (string)($component[$m[3]] ?? '');
|
||||
}
|
||||
return $value !== '' ? $value : null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user