VITEC headless v14: 5-bug fix unifies plugin renderers + cleanup

Resolves a cascade of TYPO3 v14 breaking changes that left every VITEC
plugin's JSON output silently empty:

1. `list_type` column dropped — all renderer page-discovery queries now
   filter by `CType = 'vitec_X'`.
2. `#[AsAllowedCallable]` attribute added to every public render() —
   without it v14 throws AllowedCallableException, which headless
   silently filters via its "Oops, an error occurred!" guard.
3. `$GLOBALS['TSFE']->id` is null inside JSON cObj context — page id
   now read from the `frontend.page.information` request attribute
   (TSFE fallback kept for legacy entry points).
4. page.tsconfig wizard items migrated to `CType = vitec_X` directly
   (legacy `CType=list, list_type=...` no longer exists in v14).
5. ContainerChildrenProcessor + ContentElementResolver dispatch the
   PLUGIN_RENDERERS map by CType (primary) with list_type fallback.

Beyond the bug fix this commit also contains:
- Datasheets renderer rewritten to "products with newest datasheet"
  semantics (filtered via Download.hideondatasheets).
- New vitec/card content block — multi-purpose card with backend
  preview and layout/background/aspect/alignment/border/shadow options.
- New vitec_container CType (b13 single-column container, FlexForm
  cssClass propagated into the JSON envelope).
- ContentElementResolver service for contentelement/contentelementcta
  link resolution; ContainerChildrenProcessor for nested plugin
  resolution inside b13 containers.
- Vitecset setup.typoscript: ContentElement import moved to top so
  lib.contentElement is defined before VITEC's tt_content blocks.
- Cleanup: 98 .bak.<timestamp> debugging backups removed; *.bak.* and
  /public/_assets_install/ added to .gitignore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
o-rasche
2026-06-15 14:29:17 +02:00
parent 64ea55d29d
commit 3aaf8fdad5
98 changed files with 5650 additions and 10154 deletions

View File

@@ -7,6 +7,11 @@ use Evomedien\Vitec\UserFunc\ProductListJsonRenderer;
use Evomedien\Vitec\UserFunc\ProductShowJsonRenderer;
use Evomedien\Vitec\UserFunc\UsecaseListJsonRenderer;
use Evomedien\Vitec\UserFunc\UsecaseShowJsonRenderer;
use Evomedien\Vitec\UserFunc\MarketShowJsonRenderer;
use Evomedien\Vitec\UserFunc\SolutionShowJsonRenderer;
use Evomedien\Vitec\UserFunc\DownloadcardJsonRenderer;
use Evomedien\Vitec\UserFunc\DownloadcardcollectionJsonRenderer;
use Evomedien\Vitec\UserFunc\DatasheetsJsonRenderer;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -70,6 +75,11 @@ final class ContainerChildrenProcessor implements DataProcessorInterface
'vitec_productshow' => [ProductShowJsonRenderer::class, 'product'],
'vitec_usecaselist' => [UsecaseListJsonRenderer::class, 'usecases'],
'vitec_usecaseshow' => [UsecaseShowJsonRenderer::class, 'usecase'],
'vitec_marketshow' => [MarketShowJsonRenderer::class, 'market'],
'vitec_solutionshow' => [SolutionShowJsonRenderer::class, 'solution'],
'vitec_downloadcard' => [DownloadcardJsonRenderer::class, 'downloadcard'],
'vitec_downloadcardcollection' => [DownloadcardcollectionJsonRenderer::class, 'downloadcardcollection'],
'vitec_datasheets' => [DatasheetsJsonRenderer::class, 'datasheets'],
];
public function process(
@@ -171,13 +181,17 @@ final class ContainerChildrenProcessor implements DataProcessorInterface
*/
private function resolvePluginData(array $record, array &$data): void
{
// v14: plugins are their own CType; legacy elements still carry list_type.
$cType = (string)($record['CType'] ?? '');
$listType = (string)($record['list_type'] ?? '');
if ($listType === '' || !isset(self::PLUGIN_RENDERERS[$listType])) {
$key = isset(self::PLUGIN_RENDERERS[$cType]) ? $cType
: (isset(self::PLUGIN_RENDERERS[$listType]) ? $listType : null);
if ($key === null) {
return;
}
try {
[$rendererClass, $jsonKey] = self::PLUGIN_RENDERERS[$listType];
[$rendererClass, $jsonKey] = self::PLUGIN_RENDERERS[$key];
$renderer = GeneralUtility::makeInstance($rendererClass);
if (!method_exists($renderer, 'renderForRecord')) {