The Extbase plugin route enhancer
TYPO3 provides three built-in route enhancer types. For Extbase plugins, always
use
type: Extbase. It differs from the generic
Plugin enhancer in one
important way: it generates one route variant per controller/action combination
and handles the plugin argument namespace automatically.
See also
- Routing Enhancers — overview of all enhancer types and how enhancers and aspects work together.
- Extbase plugin enhancer reference — the full reference entry in the Core routing chapter.
How the plugin namespace is derived
Every Extbase plugin has an auto-generated namespace used to prefix all its
URL parameters. The namespace is derived from the
extension and
plugin
keys in the enhancer configuration:
tx_<lowercased_extension>_<lowercased_plugin>
For
extension: My and
plugin: Conferences the namespace is
tx_. You never write this by hand — the enhancer
derives it from those two keys.
Alternatively, set
namespace directly if you need an exact string (for
example, when the auto-derived name would be wrong for a multi-word extension
key):
routeEnhancers:
ConferencesPlugin:
type: Extbase
namespace: tx_myextension_conferences
# … routes …
The key directly under
route —
Conferences here — is
an arbitrary identifier you choose. It only has to be unique across all enhancers on
the site; it is not tied to the extension or plugin name. Pick something descriptive.
See also
Extbase plugin enhancer with explicit namespace —
the
namespace property as an alternative to
extension +
plugin.
Enhancer configuration
A complete enhancer for a plugin with a list and a detail action, showing the
recommended baseline. Only
type,
extension,
plugin and
routes are strictly required;
limit is included here
because you should always scope an enhancer to its pages (see below), and
default is omitted as it is optional:
routeEnhancers:
ConferencesPlugin:
type: Extbase
limitToPages: [42]
extension: MyExtension
plugin: Conferences
routes:
- routePath: '/'
_controller: 'Conference::list'
- routePath: '/{conference_slug}'
_controller: 'Conference::show'
_arguments:
conference_slug: conference
aspects:
conference_slug:
type: PersistedAliasMapper
tableName: tx_myextension_domain_model_conference
routeFieldName: slug
The key properties:
type: Extbase- Selects the Extbase plugin enhancer.
limitTo Pages -
Restricts the enhancer to specific pages. Always set this — without it TYPO3 evaluates the enhancer for every page, which slows down route generation across the whole site.
Each entry is OR-combined. Integer values match against the page UID. String values are Symfony expression language expressions with access to
page(the full page record array),site, andsite.Language New in version 14.2
Expression language support in
limitwas added.To Pages Match by backend layout — useful when layout reliably identifies plugin pages:
limitToPages: - 'page["backend_layout"] == "pagets__conferences"'Copied!A robust, UID-free approach is to register a custom value for the Contains Plugin page property (the
modulefield) inEXT:my_extension/Configuration/TCA/Overrides/pages.php:EXT:my_extension/Configuration/TCA/Overrides/pages.php\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem( 'pages', 'module', [ 'label' => 'Conference plugin', 'value' => 'conferences', ], );Copied!Editors set this field on the plugin page in the backend, then the enhancer targets those pages without any hardcoded UIDs:
limitToPages: - 'page["module"] == "conferences"'Copied!Plain page UIDs:
limitToPages: - 42 - 99Copied!All approaches can be mixed in one array — entries are OR-combined. Use
&&inside a single string for AND logic. extension- The extension name in UpperCamelCase, without vendor prefix and without
underscores (for example
My, notExtension my_).extension plugin- The plugin name as registered in
\TYPO3\(for exampleCMS\ Extbase\ Utility\ Extension Utility:: configure Plugin () Conferences). default(optional)Controller - The controller/action pair to assume when an incoming URL carries no explicit
controller or action. Written as
Controller(noName:: action Name Actionsuffix, no namespace). It is only a fallback: generated URLs (via uriFor()) always supply the controller and action, so a minimal enhancer can omit this key. routes-
One entry per controller/action combination that should produce a readable URL. For example, a single route for the detail action:
routes: - routePath: '/{conference_slug}' _controller: 'Conference::show'Copied!See Defining routes for Extbase plugins for the full route syntax.
aspects-
Maps placeholder names to mappers that translate between internal values (UIDs) and URL segments (slugs). For example, mapping the
conference_placeholder above to a database slug field:slug aspects: conference_slug: type: PersistedAliasMapper tableName: tx_myextension_domain_model_conference routeFieldName: slugCopied!
How route variants are matched
When TYPO3 receives a request, the enhancer tries each
routes entry in
order. The first variant whose
route pattern and
_controller
match the incoming URL wins. When generating a URL, TYPO3 picks the first
variant that satisfies all required placeholders.
Order matters: put more specific routes before more general ones. A route
/ would swallow everything if listed before
/page/ — the paginated list would never match.
If no variant matches during generation, TYPO3 falls back to a plain query
string URL with the raw namespace parameters and a
c.
The cHash parameter
When a URL contains dynamic parameters that are not fully constrained,
TYPO3 appends a cHash signature. This prevents arbitrary URIs from being
cached under the same content — both stopping the cache from growing without
bound and guarding against
cache poisoning, where an
attacker fills the cache with junk variants of a page.
Strict
requirements and aspects that
define a fixed set of valid values eliminate the need for cHash — but only
when every placeholder in the route is covered. If even one placeholder is
left unconstrained, TYPO3 still adds cHash to the whole URL.
A
Persisted aspect on
a slug field removes the need for cHash for that placeholder, because the
mapper restricts it to a known set of database values rather than an open input.
A \d+ requirement alone does not — it still allows unbounded values — so only
a
Static (a fixed range)
removes cHash for a numeric placeholder.
See also
cHash and routing —
background on when and why cHash is added.
The next step is defining the individual routes inside the enhancer — see Defining routes for Extbase plugins.