- Megamenu entries with the catalog or spotlight layout get two editor fields, "Data source folders" (source_pages) and "Data source categories" (source_categories); the extension stores them, the site package's listener reads them from the entry row. - ProvideInsightsSpotlight reads its news from those folders (empty = 11 + 442; the newer posts live in 442, the query only read 11) and, when set, only from those categories (Insights: Blog Post + Press Release). Newest datetime first, three cards. - Pages carrying the menu are tagged with the news and event tables, so saving such a record refreshes the menu without a cache flush. - VITEC field descriptions via a TCA override; spec v1.31, README. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7.7 KiB
EVO Megamenu JSON
An editable megamenu for headless TYPO3. One content element holds the whole menu; the extension publishes it as JSON, the front end renders it.
Project-neutral by design — nothing in here knows which site it runs on.
What the editor gets
A plugin called Megamenu. Inside it:
| Level | Holds |
|---|---|
| Entry | one item in the main bar: label, target page, panel layout |
| Column | a heading (optionally a link) and its items |
| Item | label, link, teaser line, badge, thumbnail, “page not ready” flag |
| Teaser card | kicker, headline, text, link, image — for editorial panels |
| Featured | one highlighted block per entry, edited on the entry itself |
Five panel layouts per entry: columns for a curated structure menu,
teasers for a small link column next to cards (news, stories),
pagetree for a structure menu built live from the page tree,
catalog for a data-driven panel whose content comes from the site
package, and spotlight for a visual panel with a left-rail nav and live
content cards (see below).
Installation
composer require evomedien/evo-megamenu-json
vendor/bin/typo3 extension:setup
vendor/bin/typo3 database:updateschema "*.add,*.change"
In the site configuration, add the set EVO Megamenu (JSON) and set:
| Setting | Meaning |
|---|
| megamenu.contentUid | uid of the Megamenu element to publish on every page |
| megamenu.storagePid | alternative: folder whose first Megamenu element is used |
Leave both uid and pid at 0 and the menu is only rendered where the element sits — useful while building it.
Payload
"megaMenu": {
"settings": {
"stage": 3, "openOn": "hover", "closeDelay": 140, "columnsPerRow": 4,
"panelWidth": "container", "pendingBehaviour": "fallback",
"showCounts": true, "showViewAll": true, "viewAllLabel": "View all %s"
},
"entries": [
{
"title": "Products",
"link": "/products",
"layout": "columns",
"columns": [
{
"title": "IP Video Streaming",
"link": "/products/ip-video-streaming",
"items": [
{ "title": "Appliances", "link": "/products/ip-video-streaming/appliances",
"pending": true, "teaser": "MGW Diamond, Ace, Pico",
"image": { "url": "/fileadmin/...", "alternative": "", "title": "", "width": 600, "height": 400 } }
]
}
],
"featured": { "kicker": "Datasheet", "title": "MGW Diamond-H", "text": "…", "link": "/product/…", "image": { } }
}
]
}
settings travels with the menu on purpose: the front end reads hover
behaviour, close delay, column count and labels from the payload instead of
hard-coding them, so an editor can change them without a deploy.
Content stages
stage decides how much detail is emitted — 1 structure only, 2 adds images,
teaser lines and cards, 3 adds the featured block. Later stages only add
keys, so a front end written for stage 1 keeps working when the stage is
raised.
pending
An item whose target page does not exist yet carries "pending": true.
settings.pendingBehaviour says what to do with it: fallback (link to the
column heading instead), mute (show, not clickable) or hide. This keeps
a menu shippable while its deeper pages are still being built.
Layout catalog
For panels built from data rather than by hand — a product catalog with
categories, groups and items, a search bar, whatever the site needs. The
extension stays project-neutral: it dispatches
Evomedien\EvoMegamenuJson\Event\BuildCatalogEvent for every catalog entry
and emits whatever a listener sets via setCatalog() verbatim as
catalog on the entry (null without a listener). The entry's teaser cards
are emitted as teasers as usual and serve as the panel's featured tiles;
its columns are ignored.
#[AsEventListener(identifier: 'site/megamenu-catalog')]
final class ProvideCatalog
{
public function __invoke(BuildCatalogEvent $event): void
{
$event->setCatalog(['categories' => [/* … */]]);
}
}
getEntry() hands the listener the raw entry row (to tell several catalog
entries apart), getStage() the content stage.
Data source fields (catalog and spotlight entries): Data source
folders (source_pages, comma list of page uids) and Data source
categories (source_categories, sys_category MM with
tablenames = tx_evomegamenujson_entry, fieldname = source_categories).
The extension only stores them; the listener reads them from the entry row
and decides what they mean (empty = its own default).
Layout pagetree
A structure panel that can never age against the site: the columns mirror
the live subtree of the page the entry links to - one column per child
page, its children as the items. Hidden or nav-hidden pages leave the menu
with the next cache flush. Curated columns are ignored; teasers and the
featured slot stay editorial. From stage 2 a child page with media gets its
first image as image on the column - attach images in the page
properties and the panel turns visual by itself. From stage 2 the items
carry image (first page media or null) and, when set, the page
abstract as teaser.
The entry field Page tree display picks the presentation and travels as
display: columns (default, columns side by side) or rail (the columns
as a list on the left, the hovered column's items as image cards on the
right) plus cardSize (regular | compact) for rail. A front end that
ignores display keeps rendering columns.
Layout spotlight
A visual panel ("rossvideo style"): nav is a flat left rail built live
from the linked page's children - each item with title, link and, from
stage 2, the page abstract as teaser plus the first page media as
image, so the front end can swap the visual area on hover. Next to it the
extension emits spotlight, filled by the site package: it dispatches
Evomedien\EvoMegamenuJson\Event\BuildSpotlightEvent per spotlight entry
and emits whatever a listener sets via setSpotlight() verbatim
(null without a listener). Curated columns are ignored.
The VITEC site package ships ProvideInsightsSpotlight, which supplies
"spotlight": {
"news": [ {"title", "date", "link", "teaser?", "image?"} ],
"events": [ {"title", "start", "end", "venue", "booth", "city",
"country", "attendanceMode", "link", "teaser?", "image?"} ]
}
news: the three latest news records (type 0 - the Solr convention) from the entry's Data source folders (empty = 11 + 442) and, when set, in one of its Data source categories;link=/news/article/<path_segment>per the NewsDetail route enhancer, image fromfal_mediaas processed 640px webp. Pages carrying the menu are tagged with the news and event tables, so saving such a record refreshes the menu.events: the next two events (hideonwebsite= 0, upcoming by eventstart/eventend),link= the record'seventurlor the events page, image processed the same way.
Notes
- Every link is a resolved URL — page, record, external or file, run through typolink at render time.
- Translations are overlaid per record, so a menu can be localised entry by entry.
- The renderer never throws: a broken menu returns an empty value rather than taking the page payload down.
- Caching: every page carrying the menu is tagged with the menu tables and
tt_content_<uid>of the menu element, so saving any menu record refreshes all of them. Panels built from the page tree (pagetree,catalog,spotlight) pick up page changes with the next cache flush. - Without
friendsoftypo3/headlessthe element has no JSON envelope to render into — the extension is built for headless installations.