- evo_megamenu_json: new entry layout "pagetree" - the panel columns mirror the live subtree of the page the entry links to (one child per column, grandchildren as items, getMenu() restrictions apply), so the menu can never age against the page structure again. The stale 9-market panel after the markets realign was the trigger. Curated columns are ignored on this layout; teasers and the featured slot stay editorial. Same columns shape in the payload - front ends need no change beyond knowing the new layout string - new vitec:normalize-slugs --root=<slug> [--style=plain|and]: recursively realigns every slug below a root to <parent-slug>/<slugified-title>, cascading, with a sibling-collision warning; EXT:redirects covers the old URLs. TYPO3's slug generator keeps slashes from page titles (third hit: rtcc-/-rtic), this sweeps a whole tree. Run on /solutions: four fixes, including the long-standing passenger page and solution page 467. The misspelled "engagament" slug stays deliberately - it follows the page title and is fixed in the coordinated typo task Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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 |
Three panel layouts per entry: columns for a structure menu (products,
solutions, markets), teasers for a small link column next to cards
(news, stories), and catalog for a data-driven panel whose content comes
from the site package (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.
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.
- Without
friendsoftypo3/headlessthe element has no JSON envelope to render into — the extension is built for headless installations.