---
title: "Feature: Menu content elements"
manual: "Frontend Theme for Extension Development"
version: "main"
source: "Changelog/2.0/Feature-MenuContentElements.rst"
modified: "2026-09-17T04:52:50+00:00"
---

# Feature: Menu content elements

## Description

The theme now renders the eleven `menu_*` content elements
`EXT:frontend` registers - the last of the classic content element set left
uncovered by [Feature: Core content elements](Feature-CoreContentElements.html#feature-core-content-elements):

| Content element | Rendered |
| --- | --- |
| **Pages** | A link per page in **Pages**, or the site root's own subpages when none are selected. |
| **Subpages** | A link per child of the selected pages, or the current page's own children. |
| **Section index** | The same, two levels deep, rooted at the current page when **Pages** is empty. |
| **Section index of subpages from selected pages** | **Subpages**, two levels deep. |
| **Sitemap** | The whole site, seven levels down from the site root. |
| **Sitemaps of selected pages** | The same, rooted at the selected pages instead. |
| **Abstracts** | **Subpages**, each link followed by that page's own **Abstract** field. |
| **Recently updated pages** | Pages beneath the selection (or the current page), sorted by last change, each link followed by that date. |
| **Related pages** | Pages beneath the same entry point sharing a keyword with it. |
| **Categorized pages** | Pages carrying the selected category. |
| **Categorized content** | Content elements carrying the selected category, linked by heading and anchor. |

No TCA of this extension's own is added for any of them, the same as every
other element [Feature: Core content elements](Feature-CoreContentElements.html#feature-core-content-elements) covered: all eleven were
already creatable in the backend before this change, on TYPO3 v13.4 and v14
alike, and only rendered TYPO3's own "no rendering definition" notice.

## Nine on `MenuProcessor`, two on a category query

Nine of the eleven are the core's `MenuProcessor`, unchanged between
v13.4 and v14.3, configured with a different `special` per type -
`list`, `directory`, `updated` or `keywords` \- and, for two of them,
one extra level. **Abstracts** and **Recently updated
pages** needed no data processor beyond that: `MenuProcessor` already
JSON-encodes the whole page row onto every menu item, so the abstract text
and the last-changed timestamp were already there for the reading.

**Recently updated pages** orders pages changed in the same second by
descending uid, so the list comes out the same on every database system. The
order is set with `alternativeSortingField`; a site package that changes
`special.mode` \- to `tstamp`, for example - changes that property along
with it (`tstamp DESC, uid DESC`).

**Categorized pages** and **Categorized content** select by
category membership, which `MenuProcessor` cannot express at all, and
are built on two different mechanisms on purpose, not by accident:

-   **Categorized pages** uses the core's `RECORDS`
    cObject, which can select by category directly.
-   **Categorized content** uses
    `TYPO3CMSFrontendDataProcessingDatabaseQueryProcessor` with a
    subquery against `sys_category_record_mm` instead of `RECORDS`,
    even though `RECORDS` could select the same rows. Rendering
    through `RECORDS` would render every matched content element
    in full, nested inside this one - the wrong shape for a menu, and exposed
    to the same reference-cycle risk documented for **Insert Records**
    in [Feature: Core content elements](Feature-CoreContentElements.html#feature-core-content-elements), which TYPO3 v14 does not guard at
    all. Rendering the matched rows as links instead means nothing can nest,
    so the cycle cannot form in the first place - no structural break was
    needed here the way one was added for **Insert Records**.

> [!NOTE]
> `DatabaseQueryProcessor` wraps every row as
> `['data' => $record]`, the same shape a content element's own
> record has in its template. The **Categorized content** template
> reads `item.data.header`, not `item.header` \- the latter resolves to
> nothing and renders an empty link rather than failing.

## Markup

A single new component, `.theme-content-menu`, is shared by all eleven
elements - a list of links, optionally carrying a date or an abstract line,
nested one level for **Sitemap**'s tree. It is deliberately not the
existing sub-navigation component: a `menu_*` element is authored content
in the content column, not section-scoped site chrome, and reusing the
navigation component would pull navigation styling into content rendering.
See `docs/development/component-library.md` for the markup contract.

## Known gap

Historical `fluid_styled_content` additionally embedded each listed page's
own content elements flagged "section index" into **Section index**
and **Section index of subpages from selected pages**, linked by
anchor. **That is not implemented here.** A second menu level - the listed
pages' own children - stands in for it instead. A site package that needs
anchor-level section navigation has to add it itself.

## Impact

An installation using the theme no longer renders the TYPO3 "no rendering
definition" notice for any `menu_*` element.
`Tests/Functional/CoreContentElementRenderingTest.php` sweeps all
eleven together with every other covered `CType` and fails if any of them
regresses to the notice; two further assertions render past the wrapper to
confirm a menu actually lists what it should, and that the two categorized
elements actually select by category rather than rendering a correct but
empty wrapper.

The markup is generated from the templates below
`Resources/Private/Templates/ContentElements/`, redirected together
with every other template through the Fluid path constants under
`theme.` \- see [Configuration](../../Configuration/Index.html#configuration). See
`docs/architecture/content-elements.md` in the developer documentation
for the full `special`/level table, the category-query reasoning, and the
known gap above.
