feat: ep_products plugins are content element types of their own

Preparation for TYPO3 14, which drops list_type. The plugins are
registered as CTypes named like their former list_type values
(epproducts_product_detail etc.); the form keeps the fields of the
"list" type, with the plugin options in place of the plugin selector. As content
element types they show the E&P logo of the extension manager
(icon ep-products-plugin) instead of the generic plugin icon.

The upgrade wizard epProductsPluginListTypeToCType moves the elements
and the tt_content:list_type permissions of backend groups. Until it has
run, list_type elements render through the new types (alias block in
ext_localconf.php), so the deploy alone changes nothing. Retired plugins
stay "list" elements.

The content-only page type, the content manifest and the two container
columns limited to "list" now treat the epproducts_* types as plugins.

Crawl of 1,912 URLs identical for old code and new code before and after
the wizard; rehearsed again on the prod dump of 2026-11-01 (1,924 URLs,
API snapshot identical). Rollout and rollback SQL: .ddev/plans/PLUGINS-CTYPE-ROLLOUT.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
frommeandClaude Opus 5.5 committed 2026-11-01 14:31:35 +01:00
1 parent 518f29b160
commit 81a8013e8a
7 files changed
+238 -160

No files matched your search

@@ -32,13 +32,18 @@ call_user_func(function (): void {
);
// Column layouts, migrated from gridelements in 2026 (commit 4172ed9). colPos = 200 + 10 × layout + column
// ep_products plugins are content element types of their own since 2026-10; "list" stays for retired plugins
$plugins = implode(',', array_filter(
array_map(static fn(array $item): string => (string)($item['value'] ?? ''), $GLOBALS['TCA']['tt_content']['columns']['CType']['config']['items']),
static fn(string $cType): bool => str_starts_with($cType, 'epproducts_')
));
$menus = 'menu_abstract,menu_categorized_content,menu_categorized_pages,menu_recently_updated,menu_related_pages,menu_section_pages,menu_sitemap,menu_sitemap_pages';
$columnContainers = [
'ep_container_halves' => ['Spalten 50/50', 'Zwei gleich breite Spalten', 'halves', [[201], [202]]],
'ep_container_thirds' => ['Spalten 33/33/33', 'Drei gleich breite Spalten', 'thirds', [[211], [212], [213]]],
'ep_container_columns_quarters' => ['Spalten 25/25/25/25', 'Vier gleich breite Spalten', 'quarters', [[221], [222], [223], [224]]],
'ep_container_half_and_two_quarters' => ['Spalten 50/25/25', 'Eine breite und zwei schmale Spalten', 'half_and_two_quarters', [[231, 'textmedia,teaser,list,form_formframework'], [232], [233]]],
'ep_container_two_quarters_and_half' => ['Spalten 25/25/50', 'Zwei schmale und eine breite Spalte', 'two_quarters_and_half', [[241], [242], [243, 'textmedia,teaser,list,gmap,nlform,form_formframework,menu_pages,menu_subpages,menu_section']]],
'ep_container_half_and_two_quarters' => ['Spalten 50/25/25', 'Eine breite und zwei schmale Spalten', 'half_and_two_quarters', [[231, 'textmedia,teaser,list,form_formframework,' . $plugins], [232], [233]]],
'ep_container_two_quarters_and_half' => ['Spalten 25/25/50', 'Zwei schmale und eine breite Spalte', 'two_quarters_and_half', [[241], [242], [243, 'textmedia,teaser,list,gmap,nlform,form_formframework,menu_pages,menu_subpages,menu_section,' . $plugins]]],
];
// No container inside these columns (topLevelLayout of the gridelements configuration)
$containers = implode(',', array_merge(['ep_container_quarters', 'ep_container_teasergroup'], array_keys($columnContainers)));