
Site Sets (TYPO3 13.4+)
| Set | Purpose |
|---|---|
mpc/mp-core (aggregator) | Pulls in all feature sets below in one include |
mpc/mp-core-base (required) | Core functionality, templates, base styling, shared settings |
mpc/mp-core-container | Container elements (accordion, tabs, slider, grid) |
mpc/mp-core-news | News extension integration |
mpc/mp-core-form | Form framework configuration |
mpc/mp-core-seo | SEO (Open Graph, Twitter Cards, Schema.org, sitemap) |
mpc/mp-core is an aggregator that depends on mpc/mp-core-base plus all feature sets. Including only mpc/mp-core in your site is sufficient. If you need fine-grained control, include mpc/mp-core-base and pick individual feature sets.
Set roles
| Set | Role |
|---|---|
mpc/mp-core | Aggregator + shared Site Settings (settings.yaml, settings.definitions.yaml in this folder) |
mpc/mp-core-base | Pulls in TYPO3 system extensions; registers the shared settings paths above; optional integrations when present |
mpc/mp-core-* (feature) | Feature-specific TypoScript and settings; each depends on mpc/mp-core-base only |
Important: When authoring a custom Site Set, set
dependencies: [mpc/mp-core-base, …]— nevermpc/mp-core. Depending on the aggregator from a child set causes a SetRegistry recursion deadlock.
mpc/mp-core-base dependencies
Required: typo3/form, typo3/redirects, typo3/indexed-search
Optional (used when installed): georgringer/news-recordlinks, georgringer/news-sitemap, mpc/mpc-vidply, mpc/mpc-rss
Enabling Sets
Backend: Site Management -> Sites -> Sets tab -> enable and order sets.
YAML (config/sites/[site]/config.yaml):
base: 'https://example.com'
rootPageId: 1
dependencies:
- mpc/mp-core
Or cherry-pick individual sets:
dependencies:
- mpc/mp-core-base
- mpc/mp-core-container
- mpc/mp-core-seo
Site Settings
Editable via Site Management → Sites → Settings or config/sites/[site]/settings.yaml.
Regenerate after changing settings.definitions.yaml / settings.yaml:
node Documentation/scripts/sync-site-settings.mjs
Core (shared — mpc/mp-core / registered via mpc/mp-core-base)
Site Settings definitions and defaults live in Configuration/Sets/mp-core/settings.definitions.yaml and settings.yaml. The base set only references these files.
Source: Configuration/Sets/mp-core/
Schema default —
defaultinsettings.definitions.yaml(Site Settings UI). Shipped default — value fromsettings.yamlwhen it overrides the schema (column—= same as schema).
PIDs
| Key | Type | Default |
|---|---|---|
PIDs.pidSearch | int | 0 |
PIDs.pidHome | int | 1 |
PIDs.pidMetaNavTop | int | 66 |
PIDs.pidMetaNavFooter | int | 25 |
PIDs.pidMainNavMeta | int | 25 |
PIDs.pidCategories | int | 251 |
PIDs.pidLogosBannerTop | int | 391 |
PIDs.pidSupplement | int | 24 |
PIDs.pidWebFonts | int | 0 |
Configuration
| Key | Type | Default |
|---|---|---|
config.admPanel | bool | false |
config.debug | bool | false |
config.noCache | bool | false |
config.removeDefaultJS | string | external |
config.spamProtectEmailAddresses | bool | true |
config.spamProtectEmailAddresses_atSubst | string | [at] |
config.absRefPrefix | string | auto |
config.headerComment | string | (empty) |
Performance
| Key | Type | Default |
|---|---|---|
performance.compressJs | bool | false |
performance.compressCss | bool | false |
performance.concatenateJs | bool | false |
performance.concatenateCss | bool | false |
performance.enableLazyLoading | bool | true |
Navigation
| Key | Type | Schema default | Shipped default |
|---|---|---|---|
navigation.maxDepth | int | 5 | 3 |
navigation.showHiddenPages | bool | false | — |
navigation.enableBreadcrumb | bool | true | — |
Search
| Key | Type | Default |
|---|---|---|
search.headerSearch | bool | true |
search.autosuggest | bool | true |
Meta
| Key | Type | Schema default | Shipped default |
|---|---|---|---|
meta.viewport | string | width=device-width, initial-scale=1 | — |
meta.robots | string | index,follow | — |
meta.appleMobileWebAppCapable | string | no | — |
meta.compatible | string | IE=edge | — |
meta.google | string | notranslate | — |
meta.googleSiteVerification | string | (empty) | zPXbpegj_B5wbUDB7aXteJbnbT0IPiTDgsP53on-gRA |
Templates & paths
| Key | Type | Default |
|---|---|---|
basePath | string | EXT:mp_core |
pageTemplates | string | EXT:mp_core/Resources/Private/Templates/Page/ |
pagePartials | string | EXT:mp_core/Resources/Private/Partials/Page/ |
pageLayouts | string | EXT:mp_core/Resources/Private/Layouts/Page/ |
pageFaviconsFile | string | EXT:mp_core/Resources/Private/Partials/Page/Favicons.html |
contentElementTemplates | string | EXT:mp_core/Resources/Extensions/fluid_styled_content/Private/Templates/ |
contentElementPartials | string | EXT:mp_core/Resources/Extensions/fluid_styled_content/Private/Partials/ |
contentElementLayouts | string | EXT:mp_core/Resources/Extensions/fluid_styled_content/Private/Layouts/ |
containerElementTemplates | string | EXT:mp_core/Resources/Private/Templates/Container/ |
containerElementPartials | string | EXT:mp_core/Resources/Private/Partials/Container/ |
containerElementLayouts | string | EXT:mp_core/Resources/Private/Layouts/Container/ |
pluginsNewsTemplates | string | EXT:mp_core/Resources/Extensions/news/Templates/ |
pluginsNewsPartials | string | EXT:mp_core/Resources/Extensions/news/Partials/ |
pluginsNewsLayouts | string | EXT:mp_core/Resources/Extensions/news/Layouts/ |
pluginsIndexedSearchTemplates | string | EXT:mp_core/Resources/Extensions/indexed_search/Templates/ |
pluginsIndexedSearchPartials | string | EXT:mp_core/Resources/Extensions/indexed_search/Partials/ |
pluginsIndexedSearchLayouts | string | EXT:mp_core/Resources/Extensions/indexed_search/Layouts/ |
contentTypesTemplates | string | EXT:mp_core/Resources/Private/Templates/Content/ |
contentTypesGalleryTemplates | string | EXT:mp_core/Resources/Private/Templates/Content/ |
resourcesPrivate | string | EXT:mp_core/Resources/Private |
resourcesExtensions | string | EXT:mp_core/Resources/Extensions |
structuredDataEnabled | bool | true |
structuredData.extraEntity.type | string | none |
structuredData.extraEntity.name | string | (empty) |
structuredData.extraEntity.description | string | (empty) |
structuredData.extraEntity.keywords | string | (empty) |
Container (mpc/mp-core-container)
Source: Configuration/Sets/mp-core-container/
| Key | Type | Default |
|---|---|---|
container.grid.enabled | bool | true |
container.grid.defaultColumns | int | 2 |
container.grid.maxColumns | int | 4 |
container.grid.gutterSize | string | 20px |
container.accordion.enabled | bool | true |
container.accordion.allowMultiple | bool | false |
container.accordion.firstOpen | bool | true |
container.tabs.enabled | bool | true |
container.tabs.position | string | top |
container.wrapper.maxWidth | string | 1200px |
container.wrapper.padding | string | 15px |
News (mpc/mp-core-news)
Source: Configuration/Sets/mp-core-news/
| Key | Type | Default |
|---|---|---|
news.list.paginate.itemsPerPage | int | 10 |
news.list.orderBy | string | datetime |
news.list.orderDirection | string | desc |
news.list.dateFormat | string | d.m.Y |
news.list.showCategories | bool | true |
news.list.showTags | bool | true |
news.detail.showBackLink | bool | true |
news.detail.showRelated | bool | true |
news.detail.relatedLimit | int | 3 |
news.detail.enableComments | bool | false |
news.media.maxWidth | int | 1200 |
news.media.maxHeight | int | 800 |
Form (mpc/mp-core-form)
Source: Configuration/Sets/mp-core-form/
| Key | Type | Default |
|---|---|---|
form.honeypot.enabled | bool | true |
form.confirmationPage.enabled | bool | true |
form.requiredFieldMarker | string | * |
form.email.senderName | string | Website Contact Form |
form.email.senderEmail | string | noreply@example.com |
form.email.replyToEmail | string | info@example.com |
form.validation.clientSide | bool | true |
form.validation.showInlineErrors | bool | true |
form.storage.saveToDatabase | bool | false |
form.storage.uploadFolder | string | 1:/forms/ |
SEO (mpc/mp-core-seo)
Source: Configuration/Sets/mp-core-seo/
| Key | Type | Default |
|---|---|---|
seo.meta.defaultDescription | string | (empty) |
seo.meta.generateDescriptions | bool | true |
seo.meta.maxDescriptionLength | int | 160 |
seo.meta.maxTitleLength | int | 60 |
seo.meta.titleSeparator | string | | |
seo.openGraph.enabled | bool | true |
seo.openGraph.defaultImage | string | (empty) |
seo.openGraph.imageWidth | int | 1200 |
seo.openGraph.imageHeight | int | 630 |
seo.twitter.enabled | bool | true |
seo.twitter.cardType | string | summary_large_image |
seo.twitter.site | string | (empty) |
seo.sitemap.enabled | bool | true |
seo.sitemap.excludeHiddenPages | bool | true |
seo.sitemap.priority | string | 0.5 |
seo.canonical.enabled | bool | true |
seo.schema.enabled | bool | true |
seo.schema.organizationType | string | Organization |
seo.schema.legalName | string | (empty) |
seo.schema.alternateName | string | (empty) |
seo.schema.description | string | (empty) |
seo.schema.foundingDate | string | (empty) |
seo.schema.vatId | string | (empty) |
seo.schema.taxId | string | (empty) |
seo.schema.knowsAbout | string | (empty) |
seo.schema.person.jobTitle | string | (empty) |
seo.schema.email | string | (empty) |
seo.schema.telephone | string | (empty) |
seo.schema.contactPoint.contactType | string | customer service |
seo.schema.contactPoint.telephone | string | (empty) |
seo.schema.contactPoint.email | string | (empty) |
seo.schema.contactPoint.areaServed | string | (empty) |
seo.schema.contactPoint.availableLanguage | string | (empty) |
seo.schema.address.streetAddress | string | (empty) |
seo.schema.address.addressLocality | string | (empty) |
seo.schema.address.postalCode | string | (empty) |
seo.schema.address.addressRegion | string | (empty) |
seo.schema.address.addressCountry | string | (empty) |
seo.robots.enabled | bool | true |
seo.robots.allowAiBots | bool | true |
seo.robots.crawlDelay | int | 0 |
seo.robots.additional | string | (empty) |
seo.llmsTxt.enabled | bool | true |
seo.llmsTxt.intro | text | (empty) |
seo.llmsTxt.news.storagePid | string | (empty) |
seo.llmsTxt.news.detailPageId | int | 0 |
seo.llmsTxt.news.limit | int | 5 |
Using Settings in TypoScript
Site settings are exposed as flat TypoScript constants under their dotted key (no settings. prefix), e.g. {$navigation.maxDepth}, {$config.admPanel}, {$PIDs.pidWebFonts}. The path settings (pageTemplates, basePath, …) are additionally exposed with a settings. prefix, which is why the mpcSitepackage.* path constants reference {$settings.pageTemplates}.
For values that must be resolved at render time (e.g. inside config, page.meta, or DataProcessor properties), read them directly via the site:settings.* data getter instead of a constant:
# Flat constant (resolved at TypoScript parse time)
page.10.dataProcessing.110.levels = {$navigation.maxDepth}
# Runtime getter (preferred for config / meta / processor stdWrap)
config.compressJs.data = site:settings.performance.compressJs // {$config.compressJs}
page.meta.robots.data = site:settings.meta.robots
Font design tokens are not consumed via TypoScript: they are generated from the Web Font records (see Web Fonts) by WebFontProcessor and emitted as CSS custom properties in Resources/Private/Partials/Page/Styles.html.
Web Fonts
Editors can self-host custom fonts (uploaded to / picked from the FileManager) instead of relying on system fonts. The feature replaces the former design.fonts.* string settings.
Data model
| Record | Table | Purpose |
|---|---|---|
| Web Font Family | tx_mpcore_domain_model_webfontfamily | One CSS font-family (name + fallback stack), assigned to a target CSS variable |
| Font Face | tx_mpcore_domain_model_webfontface | One uploaded font file per weight/style (inline child of a family) |
A family's Applies to field maps it to a CSS custom property:
| Role | CSS variable |
|---|---|
| Body text | --bs-body-font-family |
| Headings | --bs-font-sans-serif |
| Custom CSS variable | the --… name entered in the family record |
Editor workflow
- Create a sysfolder to hold the records and set its page ID in the
PIDs.pidWebFontssite setting. Leave it at0to store the records on the site root page. - In the List module of that folder, create a Web Font Family: enter the family
name(e.g.Inter), afallbackstack (e.g.sans-serif), and choose Applies to. - Add one Font Face per weight/style. Upload or pick a
woff2file via the FileManager and set its weight (100–900) and style (normal/italic). - Flush the frontend cache.
WebFontProcessorgenerates the@font-facerules and the:rootvariable mapping into the nonce'd inline<style>block in the page<head>.
Rendering pipeline
Webfont records (FAL files)
-> WebFontProcessor (page.headerData.2040.dataProcessing.20)
-> WebFontCssBuilder (validate + sanitize, build @font-face + :root CSS)
-> {webFontsCss} in Styles.html
-> <f:asset.css useNonce="1"> + mpc:format.cssSanitize
All values are validated against fixed allow-lists in WebFontCssBuilder (weight, style, font-display, file format, custom-variable name, unicode-range) and the family name / fallback / URL are stripped of any character that could break out of the CSS declaration, so an attacker-supplied value can never escape the inline <style> block.
Constraints
- CSP: self-hosted fonts in
fileadminare same-origin and already covered byfont-src 'self'inConfiguration/ContentSecurityPolicies.php. Serving fonts from another domain requires adding that origin tofont-srcvia a per-siteconfig/sites/<id>/csp.yaml. - Backend permissions: admins can edit the records immediately. Non-admin backend groups need
tables_modify(andtables_select) granted fortx_mpcore_domain_model_webfontfamilyandtx_mpcore_domain_model_webfontface. - A family is only emitted when it has at least one face with a resolvable font file; otherwise the
:rootmapping is skipped (the family name alone would not load anything).
Site configuration (config.yaml)
Beyond Site Settings, mp-core extends the site record and site language via Configuration/SiteConfiguration/Overrides/sites.php. Configure these in Site Management → Sites → [site] → Configuration (or in config/sites/[site]/config.yaml).
| Area | Fields (examples) | Notes |
|---|---|---|
| Customization | navType, subnav, subnavOrder, search, copyrightText | navType: 1 primary, 2 secondary, 3 tertiary |
| Favicons | favicon-96x96-png, faviconIco, faviconSvg, apple-touch-icon, webmanifest, … | File links → Resources/Private/Partials/Page/Favicons.html (Favicons) |
| Colors & styles | color-toggle, color-1…color-8, color-primary, styles | styles injects custom :root CSS; pairs with ColorPickerValueItems in TCA |
| Social media | socialMediaSwitch, platform URL fields | Fed into SocialMediaProcessor / structured data |
| Logos | logoBig, logoSmall, logoSvg, logoText, logoTextHidden | Per-language overrides on site languages; resolved by HeaderLogoProcessor |
| Structured data entity | extraEntityImage | FAL file link for optional Schema.org extra entity (StructuredDataProcessor); type/name/keywords in Site Settings |
Language-specific palettes: copyrightText, logo fields, and logoText / logoTextHidden can differ per site language.
TypoScript Structure
Configuration/
├── ContentSecurityPolicies.php # Frontend CSP mutations auto-applied when
│ # the `security.frontend.*ContentSecurityPolicy`
│ # feature toggle is on (see "Content Security
│ # Policy" below)
├── Services.yaml # PSR-4 autowiring for `Mpc\MpCore\*`; explicit
│ # `public: true` for DataProcessors and the
│ # `ColorPickerValueItems` itemsProcFunc; optional
│ # `Services.local.yaml` import (see below)
├── Services.local.yaml # (optional, gitignored) local-only DI overrides
├── Sets/
│ ├── mp-core/
│ │ ├── config.yaml # Aggregator (depends on all feature sets)
│ │ ├── settings.yaml # Shared Site Settings defaults
│ │ ├── settings.definitions.yaml # Shared Site Settings schema
│ │ ├── constants.typoscript, setup.typoscript, page.tsconfig
│ ├── mp-core-base/
│ │ └── config.yaml # System deps + pointers to mp-core settings
│ ├── mp-core-container/
│ │ ├── config.yaml, settings.yaml, settings.definitions.yaml
│ │ ├── constants.typoscript, setup.typoscript
│ ├── mp-core-news/
│ │ ├── config.yaml, settings.yaml, settings.definitions.yaml
│ │ ├── constants.typoscript, setup.typoscript
│ ├── mp-core-form/
│ │ ├── config.yaml, settings.yaml, settings.definitions.yaml
│ │ ├── constants.typoscript, setup.typoscript
│ └── mp-core-seo/
│ ├── config.yaml, settings.yaml, settings.definitions.yaml
│ ├── constants.typoscript, setup.typoscript
├── TypoScript/
│ ├── constants.typoscript, setup.typoscript
│ ├── VueComponents.typoscript
│ ├── Helper/PageClass.typoscript
│ ├── Constants/*.typoscript
│ └── Setup/
│ ├── 10.Config, 20.Page, 30.Page.Styles, 40.Page.Scripts
│ ├── 50.Page.Navigation, 60.Lib, 90.CleanupRTE
│ ├── Page/*.typoscript
│ └── ContentElements/tt_content/*.typoscript
└── Extensions/
├── constants.typoscript, setup.typoscript
| File | Purpose |
|---|---|
10.Config | Basic TYPO3 config (charset, language, cache) |
20.Page | Page object, template paths, data processors |
30.Page.Styles | CSS includes |
40.Page.Scripts | JavaScript includes |
50.Page.Navigation | Conditional navigation bundles |
60.Lib | Shared lib.* objects |
95.SitePresentationOverrides | SocialMediaProcessor, StructuredDataProcessor |
ContentElements/tt_content/* | Content element rendering, HeaderLogoProcessor |
Dependency Injection (Services.yaml)
Configuration/Services.yaml autowires the Mpc\MpCore\* namespace and registers the services that TYPO3 has to resolve outside the container as public: true:
| Service | Why public: true |
|---|---|
Mpc\MpCore\DataProcessing\HeaderLogoProcessor | Instantiated by TypoScript via GeneralUtility::makeInstance() |
Mpc\MpCore\DataProcessing\SocialMediaProcessor | Same |
Mpc\MpCore\DataProcessing\StructuredDataProcessor | Same |
Mpc\MpCore\Middleware\RobotsTxtMiddleware | Resolved from the PSR-15 middleware stack via the DI container |
Mpc\MpCore\Middleware\LlmsTxtMiddleware | Same |
Mpc\MpCore\UserFunc\ColorPickerValueItems | itemsProcFunc callback |
Local-only DI overrides (Services.local.yaml)
The shipped Services.yaml imports an optional sibling file with ignore_errors: not_found, so projects can register local-only services (ad-hoc helpers, environment-specific wiring) without modifying the published file or breaking container compilation when the file is absent:
# Configuration/Services.local.yaml (gitignored)
services:
# Example: register a local-only helper or override a service binding.
Configuration/Services.local.yaml is listed in .gitignore for this exact pattern.
Project tooling (bin/)
Project-local scripts live in mpcore/bin/ (outside any extension repository). Full command reference: mpcore/README.
Docs-site import (bin/docsite-import.php)
php bin/docsite-import.php
php bin/docsite-import.php --dry-run
ddev exec php bin/docsite-import.php --dry-run
From docs-site/: npm run import / npm run import:dry (wraps the same script).
XLF sorting (bin/sort-xlf.php)
php bin/sort-xlf.php
php bin/sort-xlf.php --dry-run --package=mp-core
ddev exec php bin/sort-xlf.php
Content Security Policy (ContentSecurityPolicies.php)
Configuration/ContentSecurityPolicies.php ships a strict frontend CSP that is
auto-applied by TYPO3 13.4+ once one of these feature toggles is enabled
(System -> Settings -> Feature Toggles):
security.frontend.enforceContentSecurityPolicy-- enforce modesecurity.frontend.reportContentSecurityPolicy-- report-only mode
The shipped policy mutates the TYPO3 frontend defaults as follows:
| Directive | Mutation | Rationale |
|---|---|---|
default-src | Set 'self' | Strict baseline; everything without its own directive must be same-origin. |
script-src | Extend nonceProxy | Inline <script> blocks (ThemeInit.html, JSON-LD <script type="application/ld+json">) are nonce-gated via <f:security.nonce()>. |
style-src | Extend nonceProxy | Inline <style> blocks (colour overrides in Styles.html, per-element background image in fluid_styled_content/Layouts/Container.html) use <f:asset.css useNonce="1">. |
img-src | Extend data: | Allow SCSS-emitted inline SVG fallbacks (svg-load) and base64 placeholders. |
font-src | Set 'self' | All webfonts are self-hosted in Resources/Public/Fonts/. |
connect-src | Set 'self' | No XHR/fetch/WebSocket beyond own origin. |
object-src | Set 'none' | Block legacy plugins (<object>, <embed>, <applet>). |
base-uri | Set 'self' | Prevent <base href> injection attacks. |
form-action | Set 'self' | Forms post back to same origin only. |
frame-ancestors | Set 'self' | Clickjacking defence: not embeddable cross-origin. |
Per-site overrides
Operators can relax or tighten the policy per site via
config/sites/<id>/csp.yaml:
inheritDefault: true
mutations:
- mode: extend
directive: img-src
sources: ["https://cdn.example.com"]
- mode: extend
directive: form-action
sources: ["https://newsletter.example.com"]
Trust boundary for site colour configuration
Inline CSS variables in Resources/Private/Partials/Page/Styles.html are now
funnelled through the mpc:format.cssColor ViewHelper, which delegates to
Mpc\MpCore\Service\CssColorValidator. Only syntactically valid CSS colours
(named, #rgb[a], #rrggbb[aa], rgb()/rgba()/hsl()/hsla()) are emitted;
malformed or attacker-supplied site-configuration entries are silently
dropped, so they can never break out of the inline <style> block.
The same validator is reused in Mpc\MpCore\UserFunc\ColorPickerValueItems
so the backend colour-picker dropdown also filters out invalid slots and
caps labels at 200 characters.
Template Path Configuration
page.10 = FLUIDTEMPLATE
page.10 {
templateRootPaths {
0 = EXT:mp_core/Resources/Private/Templates/Page/
10 = {$settings.pageTemplates}
}
partialRootPaths {
0 = EXT:mp_core/Resources/Private/Partials/
10 = {$settings.pagePartials}
}
layoutRootPaths {
0 = EXT:mp_core/Resources/Private/Layouts/
10 = {$settings.pageLayouts}
}
}
Path precedence: 0 = core, 10 = extension, 20+ = project. Higher numbers override lower.
Extension Overrides
plugin.tx_news.view.templateRootPaths.10 = EXT:mp_core/Resources/Extensions/news/Templates/
plugin.tx_form.view.templateRootPaths.10 = EXT:mp_core/Resources/Extensions/form/Templates/
plugin.tx_indexedsearch.view.templateRootPaths.10 = EXT:mp_core/Resources/Extensions/indexed_search/Templates/
Conditional Configuration
Navigation bundles depend on the site configuration field navType (see Configuration/SiteConfiguration/Overrides/sites.php):
navType | Layout |
|---|---|
1 | Primary navigation |
2 | Secondary navigation |
3 | Tertiary navigation |
[traverse(site("configuration"), "navType") == "1"]
page.includeJSFooter.navigationPrimary = EXT:mp_core/Resources/Public/JavaScripts/navigationPrimary.js
[END]
TCA Overrides
Quick Reference
| File | Purpose |
|---|---|
tt_content_00_base.php | Global link wizard, palettes, Vue TodoList CType |
tt_content_00_header.php | Extended header options |
pages.php | Feature toggles, teaser description, link icon |
sys_category.php | Main category relation on pages |
sys_file_metadata.php | RTE description, accessibility flag |
sys_file_reference.php | Outline and download options |
sys_template.php | Static TypoScript registration |
Page Fields (pages.php)
| Field | Type | Description |
|---|---|---|
newsletter | Checkbox toggle | Newsletter signup box |
socialmedia | Checkbox toggle | Social media sharing bar |
breadcrumb | Checkbox toggle | Breadcrumb navigation |
headercontainer | Checkbox toggle | Header container layout |
teaser_description | Textarea | Teaser/card description |
link_icon | File (SVG) | Custom page link icon |
link_icon_background | Checkbox toggle | Icon background |
Global Link Wizard (tt_content_00_base.php)
| Field | Type | Options |
|---|---|---|
tx_link_switch | Checkbox toggle | Enable/disable link |
tx_link | Link wizard | Page, file, URL, record |
tx_link_layout | Select | Primary/Secondary/Tertiary button, link styles |
tx_link_text | Text input | Custom link text |
tx_link_position | Select | Center, Left, Right |
Palette: link_config
Custom Content Elements
| Element | File | Description |
|---|---|---|
| Gallery | tt_content_gallery.php | Responsive image galleries + lightbox |
| Stage | tt_content_stage.php | Hero sections (image/video backgrounds) |
| Banner | tt_content_banner.php | Customizable banner sections |
| Single Teaser | tt_content_singleteaser.php | Content teasers with images/links |
| Accordion | tt_content_accordion.php | Collapsible sections (b13/container) |
| Tabs | tt_content_tabs.php | Tabbed panels (b13/container) |
| Slider | tt_content_slider.php | Swiper carousels (b13/container) |
| Grid | tt_content_grid.php | Flexible column layouts (b13/container) |
| Container | tt_content_container.php | Generic wrapper (b13/container) |
| TodoList | tt_content_00_base.php | Vue.js 3 todo (CType: mpcore_todolist) |
| Menu Subpages | tt_content_menu_subpages.php | Enhanced subpage menu |
File Metadata / References
| Table | Field | Description |
|---|---|---|
sys_file_metadata | description | RTE text description |
sys_file_metadata | is_accessible | Accessibility compliance flag |
sys_file_reference | outline | Display with border |
sys_file_reference | allow_download | Show download button |
Common Customization Patterns
Adding a Field to an Existing Element
$myColumns = [
'tx_my_field' => [
'label' => 'My Field',
'config' => ['type' => 'input', 'size' => 30],
],
];
ExtensionManagementUtility::addTCAcolumns('tt_content', $myColumns);
ExtensionManagementUtility::addToAllTCAtypes('tt_content', 'tx_my_field', 'textmedia', 'after:bodytext');
Database Schema
Add columns to ext_tables.sql, then run Admin Tools -> Maintenance -> Analyze Database Structure.
CREATE TABLE tt_content (
tx_my_field varchar(255) DEFAULT '' NOT NULL
);
Tips
- Reuse existing palettes from
tt_content_00_base.phpandtt_content_00_header.php - Prefix custom fields with
tx_to avoid conflicts - Use
LLL:EXT:...references for all labels - Use
displayCondfor conditional field visibility:'displayCond' => 'FIELD:my_toggle:=:1' - Use Site Settings instead of hardcoded TypoScript values
- Follow path numbering:
0(core),10(extension),20+(project)
Further Reading
- Backend -- RTE, Page TSconfig, content previews
- Content elements -- Per-CType TCA field reference
- Frontend -- Build system and asset pipeline
- Favicons -- Favicon generation
- TYPO3 TCA Reference
- TYPO3 Site Sets
- TYPO3 TypoScript Reference
- b13/container