Add evo_megamenu_json extension and seed the megamenu

- new project-neutral extension evo_megamenu_json (Evomedien): a Megamenu
  plugin holding entries, columns, items, teaser cards and a featured slot
  as nested records; presentation settings travel with the payload so the
  front end reads behaviour instead of hard-coding it; published as
  page.10.fields.megaMenu, driven by the site settings megamenu.contentUid
  and megamenu.storagePid
- vitec:seed-megamenu fills one element from the live structure: 5 entries,
  26 columns, 95 items, 4 story cards; items without a page yet are flagged
  pending so the front end falls back to the column link
- vitec:debug-sets prints the resolved site set order
- read-only diagnostics: check_megamenu_schema.php, check_typoscript_templates.php
- docs: schema updates run via extension:setup (database:updateschema no
  longer exists in v14), and a JSON Accept header activates headless-mixed,
  which strips every set-added page field
This commit is contained in:
orasche committed 2026-09-11 11:44:20 +02:00
1 parent e9eaa62d89
commit 5bb4e374b4
31 files changed
+2251 -4

No files matched your search

@@ -0,0 +1,169 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!--
Presentation settings for one megamenu. Everything here is emitted as
`settings` in the JSON so the front end reads the behaviour from the
payload instead of hard-coding it.
-->
<T3DataStructure>
<sheets>
<sContent>
<ROOT>
<sheetTitle>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.sheet.content</sheetTitle>
<el>
<settings.stage>
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.stage</label>
<description>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.stage.description</description>
<config>
<type>select</type>
<renderType>selectSingle</renderType>
<default>3</default>
<items>
<numIndex index="0">
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.stage.1</label>
<value>1</value>
</numIndex>
<numIndex index="1">
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.stage.2</label>
<value>2</value>
</numIndex>
<numIndex index="2">
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.stage.3</label>
<value>3</value>
</numIndex>
</items>
</config>
</settings.stage>
<settings.pendingBehaviour>
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.pendingBehaviour</label>
<description>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.pendingBehaviour.description</description>
<config>
<type>select</type>
<renderType>selectSingle</renderType>
<default>fallback</default>
<items>
<numIndex index="0">
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.pendingBehaviour.fallback</label>
<value>fallback</value>
</numIndex>
<numIndex index="1">
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.pendingBehaviour.mute</label>
<value>mute</value>
</numIndex>
<numIndex index="2">
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.pendingBehaviour.hide</label>
<value>hide</value>
</numIndex>
</items>
</config>
</settings.pendingBehaviour>
<settings.showCounts>
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.showCounts</label>
<description>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.showCounts.description</description>
<config>
<type>check</type>
<renderType>checkboxToggle</renderType>
<default>1</default>
</config>
</settings.showCounts>
<settings.showViewAll>
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.showViewAll</label>
<config>
<type>check</type>
<renderType>checkboxToggle</renderType>
<default>1</default>
</config>
</settings.showViewAll>
<settings.viewAllLabel>
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.viewAllLabel</label>
<description>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.viewAllLabel.description</description>
<config>
<type>input</type>
<size>30</size>
<default>View all %s</default>
</config>
</settings.viewAllLabel>
</el>
</ROOT>
</sContent>
<sBehaviour>
<ROOT>
<sheetTitle>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.sheet.behaviour</sheetTitle>
<el>
<settings.openOn>
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.openOn</label>
<description>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.openOn.description</description>
<config>
<type>select</type>
<renderType>selectSingle</renderType>
<default>hover</default>
<items>
<numIndex index="0">
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.openOn.hover</label>
<value>hover</value>
</numIndex>
<numIndex index="1">
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.openOn.click</label>
<value>click</value>
</numIndex>
</items>
</config>
</settings.openOn>
<settings.closeDelay>
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.closeDelay</label>
<description>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.closeDelay.description</description>
<config>
<type>number</type>
<size>8</size>
<default>140</default>
<range>
<lower>0</lower>
<upper>1000</upper>
</range>
</config>
</settings.closeDelay>
<settings.columnsPerRow>
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.columnsPerRow</label>
<description>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.columnsPerRow.description</description>
<config>
<type>number</type>
<size>8</size>
<default>4</default>
<range>
<lower>2</lower>
<upper>6</upper>
</range>
</config>
</settings.columnsPerRow>
<settings.panelWidth>
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.panelWidth</label>
<config>
<type>select</type>
<renderType>selectSingle</renderType>
<default>container</default>
<items>
<numIndex index="0">
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.panelWidth.container</label>
<value>container</value>
</numIndex>
<numIndex index="1">
<label>LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:flexform.panelWidth.full</label>
<value>full</value>
</numIndex>
</items>
</config>
</settings.panelWidth>
</el>
</ROOT>
</sBehaviour>
</sheets>
</T3DataStructure>
@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
use TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider;
return [
'evomegamenujson-plugin' => [
'provider' => SvgIconProvider::class,
'source' => 'EXT:evo_megamenu_json/Resources/Public/Icons/plugin.svg',
],
];
@@ -0,0 +1,13 @@
services:
_defaults:
autowire: true
autoconfigure: true
public: false
Evomedien\EvoMegamenuJson\:
resource: '../Classes/*'
# Resolved through GeneralUtility::makeInstance() from the USER function,
# so it has to be reachable from the container.
Evomedien\EvoMegamenuJson\Service\MenuBuilder:
public: true
@@ -0,0 +1,9 @@
name: evomedien/megamenu
label: EVO Megamenu (JSON)
# headless has to be loaded before this set: it resets the whole page object
# (`page < lib.headlessPage`), which would drop the page-level field added
# here. Declaring the dependency keeps that order without the site
# configuration having to care about the listing position.
dependencies:
- friendsoftypo3/headless
@@ -0,0 +1,19 @@
categories:
megamenu:
label: 'Megamenu'
description: 'Which megamenu element is published at page level'
settings:
megamenu.contentUid:
label: 'Megamenu element (uid)'
description: 'Uid of the "Megamenu" content element to publish on every page as `megaMenu`. 0 = do not publish at page level.'
category: megamenu
type: int
default: 0
megamenu.storagePid:
label: 'Megamenu folder (pid)'
description: 'Alternative to the uid above: the first megamenu element found on this folder is published. Ignored when an element uid is set.'
category: megamenu
type: int
default: 0
@@ -0,0 +1,41 @@
# =============================================================================
# EVO Megamenu JSON
#
# Two wiring points, one renderer:
# 1. the plugin element renders itself, so the menu can be previewed on the
# page it sits on (content.megamenu),
# 2. the site header needs the menu on every page - set `megamenu.contentUid`
# (or `megamenu.storagePid`) and it is published at page level as
# `megaMenu`.
#
# Two things are deliberate here:
#
# * No TypoScript condition around the page-level field. A condition that
# cannot be evaluated swallows every include that follows it and silently
# disables the TypoScript of all later sets. The renderer returns an empty
# value when nothing is configured - same result, no risk.
#
# * The JSON key is written out literally. Since TYPO3 v12 the TypoScript
# parser substitutes constants only on the VALUE side, so a `{$...}` in
# the object path produces no field at all (found the hard way,
# 2026-09-11). A project that needs another key copies these five lines
# into its own set.
#
# The USER function returns a JSON string; the headless JSON content object
# decodes it, so the menu arrives as a real object, not an escaped string.
# =============================================================================
tt_content.evomegamenujson_megamenu =< lib.contentElement
tt_content.evomegamenujson_megamenu {
fields {
megamenu = USER
megamenu.userFunc = Evomedien\EvoMegamenuJson\UserFunc\MegamenuJsonRenderer->render
}
}
page.10.fields.megaMenu = USER
page.10.fields.megaMenu {
userFunc = Evomedien\EvoMegamenuJson\UserFunc\MegamenuJsonRenderer->render
contentUid = {$megamenu.contentUid}
storagePid = {$megamenu.storagePid}
}
@@ -0,0 +1,64 @@
<?php
declare(strict_types=1);
defined('TYPO3') or die();
use TYPO3\CMS\Extbase\Utility\ExtensionUtility;
/**
* Registers the "Megamenu" plugin (CType evomegamenujson_megamenu).
*
* The element carries the whole menu: its entries live inline below it, and
* the FlexForm holds the presentation settings the front end reads back out
* of the JSON (stage, hover behaviour, column count, labels).
*
* Place ONE element per menu - typically on a sysfolder - and point the site
* setting `megamenu.contentUid` at it to expose the menu at page level.
*/
(static function (): void {
ExtensionUtility::registerPlugin(
'EvoMegamenuJson',
'Megamenu',
'LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:plugin.megamenu',
'evomegamenujson-plugin',
'menu',
'LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:plugin.megamenu.description',
'FILE:EXT:evo_megamenu_json/Configuration/FlexForms/Megamenu.xml'
);
$ll = 'LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:';
$GLOBALS['TCA']['tt_content']['columns']['tx_evomegamenujson_entries'] = [
'label' => $ll . 'tt_content.entries',
'description' => $ll . 'tt_content.entries.description',
'config' => [
'type' => 'inline',
'foreign_table' => 'tx_evomegamenujson_entry',
'foreign_field' => 'parentid',
'foreign_table_field' => 'parenttable',
'foreign_sortby' => 'sorting',
'maxitems' => 12,
'appearance' => [
'collapseAll' => true,
'expandSingle' => true,
'useSortable' => true,
'newRecordLinkAddTitle' => true,
'levelLinksPosition' => 'top',
],
],
];
$GLOBALS['TCA']['tt_content']['types']['evomegamenujson_megamenu']['showitem'] = '
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
--palette--;;general,
header,
--div--;' . $ll . 'tt_content.tab.entries,
tx_evomegamenujson_entries,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:plugin,
pi_flexform,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
--palette--;;hidden,
--palette--;;access,
';
})();
@@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
/**
* A column inside an entry's panel: a headline that is itself a link,
* plus the list of items below it.
*/
$ll = 'LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:tx_evomegamenujson_column.';
return [
'ctrl' => [
'title' => 'LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:tx_evomegamenujson_column',
'label' => 'title',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'delete' => 'deleted',
'sortby' => 'sorting',
'hideTable' => true,
'versioningWS' => true,
'languageField' => 'sys_language_uid',
'transOrigPointerField' => 'l10n_parent',
'transOrigDiffSourceField' => 'l10n_diffsource',
'enablecolumns' => ['disabled' => 'hidden'],
'iconfile' => 'EXT:evo_megamenu_json/Resources/Public/Icons/column.svg',
'searchFields' => 'title',
],
'types' => [
'1' => ['showitem' => 'hidden, title, link, menu_items, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language, sys_language_uid, l10n_parent'],
],
'columns' => [
'sys_language_uid' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
'config' => ['type' => 'language'],
],
'l10n_parent' => [
'displayCond' => 'FIELD:sys_language_uid:>:0',
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'default' => 0,
'items' => [['label' => '', 'value' => 0]],
'foreign_table' => 'tx_evomegamenujson_column',
'foreign_table_where' => 'AND {#tx_evomegamenujson_column}.{#pid}=###CURRENT_PID### AND {#tx_evomegamenujson_column}.{#sys_language_uid} IN (-1,0)',
],
],
'l10n_diffsource' => ['config' => ['type' => 'passthrough']],
'hidden' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.hidden',
'config' => ['type' => 'check', 'renderType' => 'checkboxToggle', 'default' => 0],
],
'parentid' => ['config' => ['type' => 'passthrough']],
'title' => [
'label' => $ll . 'title',
'config' => ['type' => 'input', 'size' => 40, 'eval' => 'trim', 'required' => true],
],
'link' => [
'label' => $ll . 'link',
'description' => $ll . 'link.description',
'config' => ['type' => 'link', 'allowedTypes' => ['page', 'url', 'record'], 'size' => 40],
],
'menu_items' => [
'label' => $ll . 'menu_items',
'config' => [
'type' => 'inline',
'foreign_table' => 'tx_evomegamenujson_item',
'foreign_field' => 'parentid',
'foreign_sortby' => 'sorting',
'maxitems' => 30,
'appearance' => [
'collapseAll' => true,
'expandSingle' => true,
'useSortable' => true,
'newRecordLinkAddTitle' => true,
'levelLinksPosition' => 'top',
],
],
],
],
];
@@ -0,0 +1,184 @@
<?php
declare(strict_types=1);
/**
* One item in the main navigation bar - the thing a visitor hovers.
*
* `link` is a real target: the bar item stays clickable and leads to the
* overview page, the panel only opens on hover. `layout` decides which of
* the two panel shapes renders - a column grid, or a small link column
* next to teaser cards.
*/
$ll = 'LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:tx_evomegamenujson_entry.';
return [
'ctrl' => [
'title' => 'LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:tx_evomegamenujson_entry',
'label' => 'title',
'label_alt' => 'layout',
'label_alt_force' => true,
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'delete' => 'deleted',
'sortby' => 'sorting',
'hideTable' => true,
'versioningWS' => true,
'languageField' => 'sys_language_uid',
'transOrigPointerField' => 'l10n_parent',
'transOrigDiffSourceField' => 'l10n_diffsource',
'enablecolumns' => [
'disabled' => 'hidden',
],
'iconfile' => 'EXT:evo_megamenu_json/Resources/Public/Icons/entry.svg',
'searchFields' => 'title',
],
'types' => [
'1' => [
'showitem' => '
--div--;' . $ll . 'tab.general,
hidden, title, link, layout,
--div--;' . $ll . 'tab.columns,
menu_columns,
--div--;' . $ll . 'tab.teasers,
menu_teasers,
--div--;' . $ll . 'tab.featured,
featured_enable, featured_kicker, featured_title, featured_text, featured_link, featured_image,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
sys_language_uid, l10n_parent
',
],
],
'columns' => [
'sys_language_uid' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
'config' => ['type' => 'language'],
],
'l10n_parent' => [
'displayCond' => 'FIELD:sys_language_uid:>:0',
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'default' => 0,
'items' => [['label' => '', 'value' => 0]],
'foreign_table' => 'tx_evomegamenujson_entry',
'foreign_table_where' => 'AND {#tx_evomegamenujson_entry}.{#pid}=###CURRENT_PID### AND {#tx_evomegamenujson_entry}.{#sys_language_uid} IN (-1,0)',
],
],
'l10n_diffsource' => ['config' => ['type' => 'passthrough']],
'hidden' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.hidden',
'config' => ['type' => 'check', 'renderType' => 'checkboxToggle', 'default' => 0],
],
'parentid' => ['config' => ['type' => 'passthrough']],
'parenttable' => ['config' => ['type' => 'passthrough']],
'title' => [
'label' => $ll . 'title',
'description' => $ll . 'title.description',
'config' => ['type' => 'input', 'size' => 40, 'eval' => 'trim', 'required' => true],
],
'link' => [
'label' => $ll . 'link',
'description' => $ll . 'link.description',
'config' => [
'type' => 'link',
'allowedTypes' => ['page', 'url', 'record'],
'size' => 40,
],
],
'layout' => [
'label' => $ll . 'layout',
'description' => $ll . 'layout.description',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'default' => 'columns',
'items' => [
['label' => $ll . 'layout.columns', 'value' => 'columns'],
['label' => $ll . 'layout.teasers', 'value' => 'teasers'],
],
],
],
'menu_columns' => [
'label' => $ll . 'menu_columns',
'description' => $ll . 'menu_columns.description',
'config' => [
'type' => 'inline',
'foreign_table' => 'tx_evomegamenujson_column',
'foreign_field' => 'parentid',
'foreign_sortby' => 'sorting',
'maxitems' => 12,
'appearance' => [
'collapseAll' => true,
'expandSingle' => true,
'useSortable' => true,
'showSynchronizationLink' => false,
'showAllLocalizationLink' => false,
'showPossibleLocalizationRecords' => false,
'newRecordLinkAddTitle' => true,
'levelLinksPosition' => 'top',
],
],
],
'menu_teasers' => [
'displayCond' => 'FIELD:layout:=:teasers',
'label' => $ll . 'menu_teasers',
'description' => $ll . 'menu_teasers.description',
'config' => [
'type' => 'inline',
'foreign_table' => 'tx_evomegamenujson_teaser',
'foreign_field' => 'parentid',
'foreign_sortby' => 'sorting',
'maxitems' => 8,
'appearance' => [
'collapseAll' => true,
'expandSingle' => true,
'useSortable' => true,
'newRecordLinkAddTitle' => true,
'levelLinksPosition' => 'top',
],
],
],
'featured_enable' => [
'label' => $ll . 'featured_enable',
'description' => $ll . 'featured_enable.description',
'config' => ['type' => 'check', 'renderType' => 'checkboxToggle', 'default' => 0],
],
'featured_kicker' => [
'displayCond' => 'FIELD:featured_enable:=:1',
'label' => $ll . 'featured_kicker',
'config' => ['type' => 'input', 'size' => 30, 'eval' => 'trim', 'max' => 60],
],
'featured_title' => [
'displayCond' => 'FIELD:featured_enable:=:1',
'label' => $ll . 'featured_title',
'config' => ['type' => 'input', 'size' => 40, 'eval' => 'trim'],
],
'featured_text' => [
'displayCond' => 'FIELD:featured_enable:=:1',
'label' => $ll . 'featured_text',
'config' => ['type' => 'text', 'cols' => 40, 'rows' => 3],
],
'featured_link' => [
'displayCond' => 'FIELD:featured_enable:=:1',
'label' => $ll . 'featured_link',
'config' => ['type' => 'link', 'allowedTypes' => ['page', 'url', 'record', 'file'], 'size' => 40],
],
'featured_image' => [
'displayCond' => 'FIELD:featured_enable:=:1',
'label' => $ll . 'featured_image',
'config' => [
'type' => 'file',
'maxitems' => 1,
'allowed' => 'common-image-types',
],
],
],
];
@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
/**
* A single link line inside a column. `teaser` and `image` only reach the
* JSON from content stage 2 on, `pending` marks a target page that does not
* exist yet so the front end can grey the line out instead of linking into
* a 404.
*/
$ll = 'LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:tx_evomegamenujson_item.';
return [
'ctrl' => [
'title' => 'LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:tx_evomegamenujson_item',
'label' => 'title',
'label_alt' => 'teaser',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'delete' => 'deleted',
'sortby' => 'sorting',
'hideTable' => true,
'versioningWS' => true,
'languageField' => 'sys_language_uid',
'transOrigPointerField' => 'l10n_parent',
'transOrigDiffSourceField' => 'l10n_diffsource',
'enablecolumns' => ['disabled' => 'hidden'],
'iconfile' => 'EXT:evo_megamenu_json/Resources/Public/Icons/item.svg',
'searchFields' => 'title,teaser',
],
'types' => [
'1' => ['showitem' => 'hidden, title, link, pending, teaser, badge, image, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language, sys_language_uid, l10n_parent'],
],
'columns' => [
'sys_language_uid' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
'config' => ['type' => 'language'],
],
'l10n_parent' => [
'displayCond' => 'FIELD:sys_language_uid:>:0',
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'default' => 0,
'items' => [['label' => '', 'value' => 0]],
'foreign_table' => 'tx_evomegamenujson_item',
'foreign_table_where' => 'AND {#tx_evomegamenujson_item}.{#pid}=###CURRENT_PID### AND {#tx_evomegamenujson_item}.{#sys_language_uid} IN (-1,0)',
],
],
'l10n_diffsource' => ['config' => ['type' => 'passthrough']],
'hidden' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.hidden',
'config' => ['type' => 'check', 'renderType' => 'checkboxToggle', 'default' => 0],
],
'parentid' => ['config' => ['type' => 'passthrough']],
'title' => [
'label' => $ll . 'title',
'config' => ['type' => 'input', 'size' => 40, 'eval' => 'trim', 'required' => true],
],
'link' => [
'label' => $ll . 'link',
'config' => ['type' => 'link', 'allowedTypes' => ['page', 'url', 'record', 'file'], 'size' => 40],
],
'pending' => [
'label' => $ll . 'pending',
'description' => $ll . 'pending.description',
'config' => ['type' => 'check', 'renderType' => 'checkboxToggle', 'default' => 0],
],
'teaser' => [
'label' => $ll . 'teaser',
'description' => $ll . 'teaser.description',
'config' => ['type' => 'input', 'size' => 40, 'eval' => 'trim', 'max' => 255],
],
'badge' => [
'label' => $ll . 'badge',
'description' => $ll . 'badge.description',
'config' => ['type' => 'input', 'size' => 15, 'eval' => 'trim', 'max' => 60],
],
'image' => [
'label' => $ll . 'image',
'description' => $ll . 'image.description',
'config' => [
'type' => 'file',
'maxitems' => 1,
'allowed' => 'common-image-types',
],
],
],
];
@@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
/**
* A teaser card - the editorial half of the "teasers" layout, used where a
* menu should show what is new rather than a full product tree.
*/
$ll = 'LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:tx_evomegamenujson_teaser.';
return [
'ctrl' => [
'title' => 'LLL:EXT:evo_megamenu_json/Resources/Private/Language/locallang_db.xlf:tx_evomegamenujson_teaser',
'label' => 'title',
'label_alt' => 'kicker',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'delete' => 'deleted',
'sortby' => 'sorting',
'hideTable' => true,
'versioningWS' => true,
'languageField' => 'sys_language_uid',
'transOrigPointerField' => 'l10n_parent',
'transOrigDiffSourceField' => 'l10n_diffsource',
'enablecolumns' => ['disabled' => 'hidden'],
'iconfile' => 'EXT:evo_megamenu_json/Resources/Public/Icons/teaser.svg',
'searchFields' => 'title,teasertext',
],
'types' => [
'1' => ['showitem' => 'hidden, kicker, title, teasertext, link, image, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language, sys_language_uid, l10n_parent'],
],
'columns' => [
'sys_language_uid' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
'config' => ['type' => 'language'],
],
'l10n_parent' => [
'displayCond' => 'FIELD:sys_language_uid:>:0',
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'default' => 0,
'items' => [['label' => '', 'value' => 0]],
'foreign_table' => 'tx_evomegamenujson_teaser',
'foreign_table_where' => 'AND {#tx_evomegamenujson_teaser}.{#pid}=###CURRENT_PID### AND {#tx_evomegamenujson_teaser}.{#sys_language_uid} IN (-1,0)',
],
],
'l10n_diffsource' => ['config' => ['type' => 'passthrough']],
'hidden' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.hidden',
'config' => ['type' => 'check', 'renderType' => 'checkboxToggle', 'default' => 0],
],
'parentid' => ['config' => ['type' => 'passthrough']],
'kicker' => [
'label' => $ll . 'kicker',
'description' => $ll . 'kicker.description',
'config' => ['type' => 'input', 'size' => 25, 'eval' => 'trim', 'max' => 60],
],
'title' => [
'label' => $ll . 'title',
'config' => ['type' => 'input', 'size' => 40, 'eval' => 'trim', 'required' => true],
],
'teasertext' => [
'label' => $ll . 'teasertext',
'config' => ['type' => 'text', 'cols' => 40, 'rows' => 3],
],
'link' => [
'label' => $ll . 'link',
'config' => ['type' => 'link', 'allowedTypes' => ['page', 'url', 'record', 'file'], 'size' => 40],
],
'image' => [
'label' => $ll . 'image',
'config' => [
'type' => 'file',
'maxitems' => 1,
'allowed' => 'common-image-types',
],
],
],
];