Datapath stories, grid repairs, menu v2 pure, hero placeholders, fec test

Batch of 2026-10-28/29 plus 2026-11-03:

- NEW vitec:import-datapath-stories: 22 story packages from the agency
  dump (docx + Links/ assets) as usecase records with content, quotes,
  images, customer logos, download cards; --repair-quotes normalizes
  attribution lines; asset backfill for existing stories
- /products grid incident repaired (fix_products_grid, fix_graphics_grid,
  check_grid_page): containers unhidden, 46 duplicate cards soft-deleted,
  section order restored; BuildProductPortfolio and
  ImportProductCategoryPages now GUARD against re-runs on pages that
  already carry vitec_cols_% containers
- ' double-encoding fixed: render-pipeline importers write literal
  apostrophes (ENT_NOQUOTES), fix_double_entities literalizes existing rows
- ticket quick wins (ticket_quickwins_20261028), broadcast market page
  cleanup, AttachCardImages market-card handling, SubmarketWorkbook
  META REPAIR, story content/video fixes (fix_story_*)
- ProvideProductCatalog: transitional v1 fields removed (categories
  uid/link, legacyGroupFields, item products teaser) - pure v2 shape
  (ticket 0024-FE); search renderer keeps its teaser
- BuildProductOverviews: heroes get the numbered placeholder background
  (placeholders/pages/<uid>-01.png, wide grey fallback) - backfill on
  existing pages with empty hero_bgimage, attached at creation for new
  pages; existing references always win (ticket 0026-FE); 40 placeholder
  PNGs shipped to fileadmin (not tracked)
- AttachPageMedia: --depth=3 with sysfolders as pass-through parents for
  the overview pages' -08 menu tiles
- NEW migrations/fec_isolation_test.sh: two-user live test proving
  fe_comment ticket isolation (backend verified tight, cross-user
  sighting traced to the FE page-JSON cache, ticket 0027-BE)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
orascheandClaude Fable 5 committed 2026-11-03 18:29:56 +01:00
1 parent 9211c8a395
commit 77661bf0b6
22 files changed
+2103 -63

No files matched your search

+81
View File
@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
/**
* Ticket 0014-FE Punkt 2: doppelt kodierte HTML-Entities in tt_content
* (z. B. "VITEC&amp;apos;s" im JSON). Ursache: die Produkt-Importer
* escapten mit ENT_QUOTES|ENT_HTML5 (' -> &apos;), die RTE-Persistenz
* escapte das & erneut. Die Importer schreiben seit 2026-10-28 literal
* (ENT_NOQUOTES); dieses Skript repariert den Bestand um EINE
* Escaping-Stufe: &amp;apos; -> &apos; usw.
*
* Plain PDO (Muster migrations/check_bg.php).
*
* Usage: php migrations/fix_double_entities.php (Scan/Report)
* php migrations/fix_double_entities.php --apply
*/
error_reporting(E_ALL);
ini_set('display_errors', '1');
// Stufe 1: doppelt kodierte Entities um eine Stufe reduzieren.
// Stufe 2 (Befund 2026-10-28: Scan fand KEINE Doubles in der DB - die DB
// traegt &apos; EINFACH kodiert, erst die Render-Pipeline escapet das &
// erneut): Apostroph-Entities literal machen, dann kann nichts mehr doppeln.
const PATTERNS = ['&amp;apos;', '&amp;quot;', '&amp;#039;', '&amp;amp;', '&amp;nbsp;', '&apos;', '&#039;'];
const REPLACEMENTS = ['&apos;', '&quot;', '&#039;', '&amp;', '&nbsp;', "'", "'"];
$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");
}
$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]
);
echo ($apply ? 'APPLY' : 'SCAN') . "\n";
$like = implode(' OR ', array_map(static fn(string $p): string => "bodytext LIKE '%" . $p . "%'", PATTERNS));
$rows = $pdo->query(
"SELECT c.uid, c.pid, p.slug, c.CType, c.bodytext FROM tt_content c
LEFT JOIN pages p ON p.uid = c.pid
WHERE c.deleted = 0 AND ($like) ORDER BY p.slug, c.uid"
)->fetchAll();
$fixed = 0;
foreach ($rows as $row) {
$new = str_replace(PATTERNS, REPLACEMENTS, (string)$row['bodytext']);
$hits = [];
foreach (PATTERNS as $pattern) {
$n = substr_count((string)$row['bodytext'], $pattern);
if ($n > 0) {
$hits[] = $pattern . 'x' . $n;
}
}
printf("#%-6d %-28s %-45s %s\n", $row['uid'], $row['CType'], (string)$row['slug'], implode(' ', $hits));
if ($apply) {
$pdo->prepare('UPDATE tt_content SET bodytext = ?, tstamp = UNIX_TIMESTAMP() WHERE uid = ?')
->execute([$new, (int)$row['uid']]);
$fixed++;
}
}
echo "\n" . count($rows) . " Element(e) betroffen" . ($apply ? ", $fixed repariert. Danach: vendor/bin/typo3 cache:flush" : ". Mit --apply reparieren.") . "\n";
if (!$apply && $rows !== []) {
echo "HINWEIS: Ersetzt wird genau EINE Escaping-Stufe (&amp;apos; -> &apos; usw.).\n";
}