Files
wappler af9368177b Initial t3bootstrap-skills plugin: three skills for T3Bootstrap on TYPO3 v14
- t3bootstrap-site-package: composer + site sets + when to add a local extension
- t3bootstrap-overrides: 4-layer override surface (Settings → SCSS → Fluid → DataProcessor)
- t3bootstrap-content-elements: 23 t3bs_* CE catalog + migration matrix (HTML/WP/Joomla/older TYPO3) + Flux-bs5 upgrade wizard

Mirrors the structure of wapplersystems/typo3-skills (.claude-plugin/{plugin.json,marketplace.json}, .agents/skills/<name>/{SKILL.md,agents/openai.yaml}).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-15 09:58:33 +02:00

519 lines
21 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: t3bootstrap-overrides
description: Customize a T3Bootstrap-based TYPO3 v14 project minimally — without forking the upstream `t3bootstrap/*` packages. Covers the four override surfaces in order of invasiveness (Site Settings / TypoScript constants → SCSS `!default` variables → Fluid `templateRootPaths.10` overrides → custom DataProcessors), how to decide which surface fits a given change, the path-index conventions (`0` core, `5` core extensions, `10` site-package, `100` container-bs5, `200` Frameless), and the standard layout for a customer-specific extension that ships such overrides. Use this skill whenever the customer wants different colors, fonts, page structure, navigation, footer, content-element rendering, or any other deviation from upstream T3Bootstrap defaults.
---
# T3Bootstrap Overrides
Use this skill when customizing a TYPO3 v14 project on the T3Bootstrap stack. The goal:
**touch nothing in `vendor/`**, ship the customization as a thin customer extension, keep
`composer update` upgrade-safe.
> **Companion skill:** [`t3bootstrap-site-package`](../t3bootstrap-site-package/SKILL.md) explains the underlying setup. Start there if the project isn't bootstrapped yet.
## Override Surfaces — Pick the Least Invasive
T3Bootstrap exposes **four layers** of customization. Always start with the highest layer
that can solve the problem; descend only when forced.
```
1. Site Settings / TypoScript constants ← most upgrade-safe, no code
2. SCSS !default variable overrides ← brand colors, fonts, spacing tokens
3. Fluid template overrides via index 10 ← structural HTML changes
4. Custom DataProcessor / PHP ← only when data shape must change
```
### Decision table
| Need | Layer | Example |
| --- | --- | --- |
| Change brand color | 2 (SCSS) or 1 (CSS custom property) | Re-define `$primary` |
| Change header height / sticky behavior | 1 (constants) | `header.sticky` setting |
| Show/hide language menu | 1 (constants) | `navigation.languageMenu` |
| Different button styling | 1 + 2 | CSS custom property, or `$btn-padding-y` SCSS |
| Add an extra CSS class to all CEs | 3 (override Content layout) | `Resources/Private/Layouts/Content/Default.html` |
| Replace the Header partial with something completely different | 3 (override partial) | `Resources/Private/Partials/PageHeader.html` |
| Change the data passed to a CE | 4 (custom DataProcessor) | Replace `FrameClassesProcessor` |
If a question is at the boundary (e.g. "is this an SCSS change or a Fluid override?"),
the answer is usually: **whichever is closer to the top of the table**.
## Layer 1 — Site Settings / TypoScript Constants
The `t3bootstrap/template` set exposes a large set of constants under
`Configuration/TypoScript/constants.typoscript`. Categories include navigation, language,
text, font, search box, logo, banner, body tag, breadcrumb, color, color-mode, language
defaults, screen, domains.
### Where they're defined
```text
vendor/t3bootstrap/template/Configuration/TypoScript/constants.typoscript # the master file (~639 lines)
vendor/t3bootstrap/template/Configuration/TypoScript/Plugin/Constants/*.typoscript # per-plugin (calendarize, indexedsearch, …)
```
### How to override
#### Best — Site Setting in the TYPO3 v14 Backend
Site Settings module → "T3Bootstrap Template" category → change the value. Persisted to
`config/sites/<site>/settings.yaml` automatically. Reviewable in git.
#### Better — customer extension's Site Set
Settings shipped from a customer extension's `Configuration/Sets/<Customer>/settings.yaml`:
```yaml
# local_packages/<customer>/site_<customer>/Configuration/Sets/Site<Customer>/settings.yaml
plugin.tx_template.view.templateRootPath: 'EXT:site_<customer>/Resources/Private/Templates/'
plugin.tx_template.view.partialRootPath: 'EXT:site_<customer>/Resources/Private/Partials/'
plugin.tx_template.view.layoutRootPath: 'EXT:site_<customer>/Resources/Private/Layouts/'
# Color tokens at the constants level (CSS custom property variables will see them)
color.primary: '#005262'
color.secondary: '#55aa63'
```
#### Acceptable — TypoScript constants in a customer extension
Only if you need conditions or includes that the Settings YAML can't express:
```typoscript
# local_packages/<customer>/site_<customer>/Configuration/Sets/Site<Customer>/constants.typoscript
plugin.tx_template.view.templateRootPath = EXT:site_<customer>/Resources/Private/Templates/
```
> **Never** edit the upstream constants file. Any constant you want to change has a
> matching site setting key — find it in the backend Constants Editor or in the master
> constants file's `# cat=…` comments.
## Layer 2 — SCSS Variable Overrides
T3Bootstrap's SCSS is built around Bootstrap 5 and uses `!default` on every variable so
customer SCSS loaded **before** the vendor file wins.
### The compilation pipeline
The stack relies on `wapplersystems/ws-scss` (or any project-set-up Node/Vite/PostCSS
pipeline). The conventional entry point is one customer SCSS file that:
1. Defines overrides
2. Imports the t3bootstrap base
3. Imports Bootstrap 5
4. Adds any extra component CSS
### Master variables file
```text
vendor/t3bootstrap/template/Resources/Public/SCSS/_variables.scss
```
Representative excerpt — **all values are `!default`, so you can re-set them upstream**:
```scss
$primary: #005262 !default;
$secondary: #55aa63 !default;
$lightblue: #87c8e6 !default;
$prefix: bs- !default;
$custom-colors: (
dark-gray: #005262,
gray: #999,
graylight: #f7f7f7
) !default;
$icon-sizes: (
sm: 2rem,
md: 3rem,
lg: 4rem,
xl: 6rem
) !default;
$font-family-sans-serif: 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif !default;
$h1-font-size: 2.0rem !default;
$h2-font-size: 1.8rem !default;
$font-size-base: 0.95rem !default;
```
Related files in the same directory: `_colors.scss`, `_mixins.scss`, `_mmenu.scss`,
`_variables-dark.scss`, `_variables-contrast-high.scss`, and the subdirectories
`additions/`, `aos/`, `aria/`, `base-layout/`, `bootstrap/`, `components/`, `effects/`,
`elements/`, `extensions/`, `fonts/`, `mixins/`.
### Customer override pattern
```scss
/* local_packages/<customer>/site_<customer>/Resources/Public/Scss/main.scss */
/* 1. Re-define variables BEFORE importing t3bootstrap */
$primary: #c81d25;
$secondary: #2b6cb0;
$font-family-sans-serif: 'Inter', sans-serif;
$custom-colors: (
brand-dark: #1a1a2e,
brand-light: #f5f5f5,
);
/* Bootstrap defaults can also be redefined here, BEFORE bootstrap loads */
$btn-border-radius: 0;
/* 2. Import the t3bootstrap base — this brings in Bootstrap 5 and all defaults */
@import 'EXT:template/Resources/Public/SCSS/base-layout';
/* 3. Project-specific additions */
.c-customer-banner {
background: $primary;
/* … */
}
```
`@import 'EXT:template/...'` works inside `ws_scss` — it resolves `EXT:` paths via the
TYPO3 path resolver. If your toolchain doesn't, use a relative or absolute path.
### When to use CSS custom properties instead
Bootstrap 5 ships **CSS custom properties** (`--bs-primary`, `--bs-body-color`, …) for
runtime themability. T3Bootstrap respects them.
```css
/* As an inline-style block on the page, or in a separate stylesheet loaded after Bootstrap */
:root {
--bs-primary: #c81d25;
--bs-secondary: #2b6cb0;
}
```
**Rule of thumb:** values that must be available at runtime (dark mode, theme switching,
editor-tweaked colors via Site Settings) → CSS custom properties. Values fixed at build
time (font stack, spacing scale, breakpoints) → SCSS variables.
## Layer 3 — Fluid Template Overrides via Path Index
Every Fluid-rendering object in T3Bootstrap exposes `templateRootPaths`, `partialRootPaths`,
and `layoutRootPaths` as numerically-indexed arrays. **Higher index wins.** The convention
is:
| Index | Owner | Purpose |
| --- | --- | --- |
| `0` | t3bootstrap base | Original templates. Never touch. |
| `5` | `t3bootstrap/core` extension overrides | E.g. core's `fluid_styled_content` overrides. |
| `9` / `40` | `t3bootstrap/template` plugin-specific overrides | Felogin, fluid_styled_content, indexed_search etc. |
| `10` | **Customer site package** | This is the slot you write to. |
| `100` | `t3bootstrap/container-bs5-templates` | The `t3bs_*` CE templates. |
| `200` | Frameless variant from `container-bs5-templates` | `Frameless/` layout dir for the "no-frame" CE option. |
### The page template's override hook
`vendor/t3bootstrap/template/Configuration/TypoScript/HTML/Page/body.typoscript` (lines
7790):
```typoscript
layoutRootPaths {
0 = EXT:template/Resources/Private/Layouts/
10 = {$plugin.tx_template.view.layoutRootPath}
}
templateRootPaths {
0 = EXT:template/Resources/Private/Templates/Page/
10 = {$plugin.tx_template.view.templateRootPath}
}
partialRootPaths {
0 = EXT:template/Resources/Private/Partials/
10 = {$plugin.tx_template.view.partialRootPath}
}
```
Configure `plugin.tx_template.view.*` via Site Settings (preferred) or constants — see
Layer 1.
### What's in `Resources/Private/Templates/Page/` upstream
```
1Column.html
2Columns.html
2Columns2.html
3Columns.html
Onepager.html
```
These are picked by the page's **backend layout**. Override one by copying it to
`local_packages/<customer>/site_<customer>/Resources/Private/Templates/2Columns.html` and
modifying.
### Layouts upstream
```
Resources/Private/Layouts/
├── Content.html # The wrapper used by all fluid_styled_content CEs
└── Page.html # The HTML shell <html><body>…
```
### Partials upstream — what's worth overriding
```
Resources/Private/Partials/
├── BackgroundMedia.html
├── Footer/ ← whole footer block partials (columns, copyright bar)
├── Header/ ← header column partials
├── Navigation/ ← main nav, breadcrumb, language menu, mobile burger
├── Hero.html
├── Navigation.html
├── PageFooter.html
├── PageHeader.html
├── Searchbox.html
└── Skiplinks.html
```
#### Common override targets
| Want to change | Override |
| --- | --- |
| Site-wide header structure | `Resources/Private/Partials/PageHeader.html` |
| Logo placement, sticky behavior | `Resources/Private/Partials/Header/*.html` |
| Navigation rendering | `Resources/Private/Partials/Navigation.html` + `Navigation/*.html` |
| Search box markup | `Resources/Private/Partials/Searchbox.html` |
| Footer layout | `Resources/Private/Partials/PageFooter.html` + `Footer/*.html` |
| Skiplinks for a11y | `Resources/Private/Partials/Skiplinks.html` |
| Hero markup | `Resources/Private/Partials/Hero.html` |
| Background-media wrapper | `Resources/Private/Partials/BackgroundMedia.html` |
> Copy the **whole** partial, then modify. Fluid does not "merge" — once index 10
> shadows index 0, it must contain the full template.
## Overriding `fluid_styled_content` CEs
The stack already overrides core's `fluid_styled_content` at index `9` (template) and `5`
(layouts) via `t3bootstrap/core`. To override **further**, point to a higher index:
```typoscript
# In a customer extension's setup.typoscript
lib.contentElement.templateRootPaths.20 = EXT:site_<customer>/Resources/Private/ContentElements/Templates/
lib.contentElement.partialRootPaths.20 = EXT:site_<customer>/Resources/Private/ContentElements/Partials/
lib.contentElement.layoutRootPaths.20 = EXT:site_<customer>/Resources/Private/ContentElements/Layouts/
```
Upstream-rendered CTypes you can override there:
```text
vendor/t3bootstrap/core/Resources/Private/Extensions/fluid_styled_content/Templates/
├── Textmedia.html
├── Textpic.html
├── Image.html
├── Table.html
├── Shortcut.html
├── Card.html
├── CardsCarousel.html
├── Counterbar.html
├── Countdown.html
├── CompareSlider.html
└── NumberCarousel.html
```
For the `t3bs_*` container-based CEs use the **container_bs5_templates** path indices:
```typoscript
# Override e.g. the Card.html template for t3bs_card
lib.t3bsContent.templateRootPaths.200 = EXT:site_<customer>/Resources/Private/T3bsContent/Templates/
lib.t3bsContent.partialRootPaths.200 = EXT:site_<customer>/Resources/Private/T3bsContent/Partials/
```
Source:
```text
vendor/t3bootstrap/container-bs5-templates/Resources/Private/Templates/
├── Card.html ← t3bs_card
├── Cards.html ← t3bs_cards
├── Accordion.html ← t3bs_accordion
├── AccordionItem.html
├── Tabs.html
├── TabItem.html
├── Carousel.html
├── CarouselItem.html
├── Container.html
├── FluidRow.html
├── Column.html
├── Alert.html
├── Panel.html
├── Well.html
├── Thumbnail.html
├── Media.html
├── Example.html
├── Timeline.html
├── TimelineItem.html
├── Buttongroup.html
├── Buttonlink.html
├── Megamenu.html
└── MegamenuItem.html
```
## Layer 4 — Custom DataProcessors
Only needed when you want to **change the data shape** the Fluid templates see, not just
the markup. Examples:
- Add a derived field (e.g. a "read time" estimate for news items).
- Replace `T3Bootstrap\Core\Frontend\DataProcessing\FrameClassesProcessor` with a custom one that emits different frame CSS classes.
- Add a side-effect (logging, prefetching, conditional caching of related data).
Upstream processors used by `lib.t3bsContent`:
```text
T3Bootstrap\Core\Frontend\DataProcessing\IconProcessor # 706
T3Bootstrap\Core\Frontend\DataProcessing\FrameClassesProcessor # 707
T3Bootstrap\Core\Frontend\DataProcessing\AosDataAttributeProcessor # 708
T3Bootstrap\Core\Frontend\DataProcessing\ProcessedDataToRegisterProcessor # 900
```
Plus core's `TYPO3\CMS\Frontend\DataProcessing\FilesProcessor` at 703 for `background_media`.
### Adding a custom processor
```typoscript
# Customer Site Set setup.typoscript
lib.t3bsContent.dataProcessing.950 = Vendor\SiteCustomer\DataProcessing\ReadTimeProcessor
lib.t3bsContent.dataProcessing.950.target = readTime
```
### Replacing an upstream processor
```typoscript
# Replace at the same index — TypoScript merges shallow, so reassign:
lib.t3bsContent.dataProcessing.707 = Vendor\SiteCustomer\DataProcessing\CustomFrameClassesProcessor
lib.t3bsContent.dataProcessing.707 >
lib.t3bsContent.dataProcessing.707 = Vendor\SiteCustomer\DataProcessing\CustomFrameClassesProcessor
```
The `>` operator clears the original config sub-tree first to prevent stray options.
### TSFE-aware processors
On TYPO3 v14 there is no more `$GLOBALS['TSFE']`. T3Bootstrap's processors use the
**`RegisterUtility`** static registry at `T3Bootstrap\Core\Utility\RegisterUtility` to
share per-request state across processors and ViewHelpers. If your processor needs to
publish a value for a later ViewHelper, write to that registry — don't reach for the
removed TSFE register.
## Standard Customer-Extension Layout
```
local_packages/<customer>/site_<customer>/
├── composer.json
├── ext_emconf.php
├── ext_localconf.php
├── Classes/
│ ├── DataProcessing/ # Layer 4
│ └── ViewHelpers/
├── Configuration/
│ ├── Sets/
│ │ └── Site<Customer>/
│ │ ├── config.yaml # dependencies
│ │ ├── settings.yaml # Layer 1
│ │ ├── constants.typoscript # Layer 1 (only if Settings YAML insufficient)
│ │ └── setup.typoscript # Layer 3 path-index registration + Layer 4 processors
│ └── TCA/Overrides/
└── Resources/
├── Private/
│ ├── Templates/ # Page templates (Layer 3)
│ ├── Layouts/ # Page + content layouts
│ ├── Partials/ # Header/Footer/Nav/Hero/… (Layer 3)
│ ├── ContentElements/ # fluid_styled_content overrides
│ │ ├── Templates/
│ │ ├── Layouts/
│ │ └── Partials/
│ ├── T3bsContent/ # t3bs_* CE overrides
│ │ ├── Templates/
│ │ └── Partials/
│ └── Language/
└── Public/
├── Scss/
│ ├── main.scss # Layer 2 — !default overrides + imports
│ └── _customer-variables.scss
├── Css/ # compiled output
└── JavaScript/
```
`Configuration/Sets/Site<Customer>/config.yaml`:
```yaml
name: <customer>/site-<customer>
label: <Customer> Site Customization
dependencies:
- t3bootstrap/template
- t3bootstrap/container-bs5-templates
```
`setup.typoscript`:
```typoscript
# Page templates
plugin.tx_template {
view {
templateRootPath = EXT:site_<customer>/Resources/Private/Templates/
partialRootPath = EXT:site_<customer>/Resources/Private/Partials/
layoutRootPath = EXT:site_<customer>/Resources/Private/Layouts/
}
}
# fluid_styled_content extensions
lib.contentElement {
templateRootPaths.20 = EXT:site_<customer>/Resources/Private/ContentElements/Templates/
partialRootPaths.20 = EXT:site_<customer>/Resources/Private/ContentElements/Partials/
layoutRootPaths.20 = EXT:site_<customer>/Resources/Private/ContentElements/Layouts/
}
# t3bs_* CEs
lib.t3bsContent {
templateRootPaths.200 = EXT:site_<customer>/Resources/Private/T3bsContent/Templates/
partialRootPaths.200 = EXT:site_<customer>/Resources/Private/T3bsContent/Partials/
}
# Custom DataProcessor
lib.t3bsContent.dataProcessing.950 = Vendor\SiteCustomer\DataProcessing\ReadTimeProcessor
```
Then add the customer set to the site config:
```yaml
# config/sites/<site-id>/config.yaml
dependencies:
- t3bootstrap/template
- t3bootstrap/container-bs5-templates
- <customer>/site-<customer> # <- new
```
## Anti-Patterns
| Anti-pattern | Why it's bad | Correct approach |
| --- | --- | --- |
| Editing files under `vendor/t3bootstrap/*/` | Composer wipes changes on next update | Override via the customer extension's path index `10` (or higher) |
| Forking `t3bootstrap/template` in customer's GitHub | Loses upstream fixes; merge conflicts forever | Customer extension + targeted partial overrides |
| Adding raw `<style>` in PageTSconfig to "patch" colors | Fragile, gets purged by cache flushes, not visible at build time | Layer 2 (SCSS `!default`) or CSS custom properties |
| Copying ALL upstream partials into the customer ext "just in case" | Now you own every change forever | Copy only what you override |
| Setting `templateRootPaths.0` in the customer extension | Shadows the original; future upstream changes invisible | Use index `10` (or higher), keep `0` for vendor |
| Cloning the whole vendor SCSS tree | Re-doing Bootstrap themability | Re-define `!default` variables in customer SCSS, import vendor base |
| Hardcoding `EXT:template/...` paths in the customer ext templates | The customer extension shouldn't refer to upstream paths | Use Fluid layout/partial inheritance — `<f:layout name="Default"/>` finds it via `layoutRootPaths` automatically |
| Modifying `lib.dynamicContent` "to add fields" | The DataProcessor pipeline is the right hook | Add a processor at index 900+ |
## Verification Checklist
After any override change:
1. `ddev exec vendor/bin/typo3 cache:flush` — TypoScript and Fluid template paths are cached.
2. Reload the frontend; if SCSS changed, run the customer's CSS build (`npm run build`, or `ws-scss` watcher).
3. Inspect the rendered HTML — confirm your override is the one rendered (look for a distinctive marker comment you added).
4. **TYPO3 backend → Maintenance → "Render TypoScript"** → confirm the right `templateRootPaths.10` / `.20` / `.200` are populated with your paths.
5. If layered overrides don't seem to take effect: list `lib.t3bsContent.templateRootPaths` via `vendor/bin/typo3 ts:setup --path=lib.t3bsContent.templateRootPaths` (from `claude-diagnostics`) — index values shown in numeric order.
## Reference Files in This Project
```text
vendor/t3bootstrap/template/Configuration/TypoScript/constants.typoscript # all constants
vendor/t3bootstrap/template/Configuration/TypoScript/HTML/Page/body.typoscript # main layoutRootPaths block
vendor/t3bootstrap/template/Resources/Public/SCSS/_variables.scss # SCSS variables
vendor/t3bootstrap/template/Resources/Private/Partials/ # partials to override
vendor/t3bootstrap/template/Resources/Private/Templates/Page/ # page templates
vendor/t3bootstrap/core/Resources/Private/Extensions/fluid_styled_content/ # core CE overrides at index 5/9
vendor/t3bootstrap/container-bs5-templates/Configuration/Sets/ContainerBs5Templates/setup.typoscript # lib.t3bsContent declaration
vendor/t3bootstrap/container-bs5-templates/Resources/Private/Templates/ # t3bs_* CE templates
```
For CE-by-CE migration mapping and the `t3bs_*` catalog, see the
**`t3bootstrap-content-elements`** skill.