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>
This commit is contained in:
2026-06-15 09:58:33 +02:00
commit af9368177b
11 changed files with 1503 additions and 0 deletions
@@ -0,0 +1,417 @@
---
name: t3bootstrap-content-elements
description: Choose the right content element when migrating content into a T3Bootstrap-based TYPO3 v14 site. Covers the full catalog of 23 `t3bs_*` container-based CEs from `t3bootstrap/container-bs5-templates`, the custom CEs from `t3bootstrap/core` (Card, CompareSlider, Countdown, Counterbar, NumberCarousel) and `t3bootstrap/hero-item`, plus a decision matrix for source materials — static HTML/Bootstrap markup, WordPress blocks, Joomla modules, older TYPO3 sites with `flux_bs5_templates` / `gridelements` / `dce` / `bootstrap_package`. Includes the parent-child container nesting rules, the `t3bsContainerBs5MigrateFluxBs5` upgrade wizard and how to run it, the colPos slot conventions, and guidance on when to pick a core CE (`textmedia`, `image`, `header`, `bullets`) over a custom one. Use this skill whenever migrating content TO a T3Bootstrap project, picking which CE to use for a given visual pattern, debugging "child element doesn't appear in parent" issues, or planning a Flux-to-Container content rewrite.
---
# T3Bootstrap Content Elements
Use this skill to decide **which content element** to use when bringing content into a
T3Bootstrap-based TYPO3 v14 project — from static HTML, another CMS, an older TYPO3
version, or hand-rebuilt by an editor.
> **Companion skills:**
> - [`t3bootstrap-site-package`](../t3bootstrap-site-package/SKILL.md) — make sure the right packages and Site Sets are present before placing CEs.
> - [`t3bootstrap-overrides`](../t3bootstrap-overrides/SKILL.md) — when a stock CE almost fits but you need to tweak its template.
## The Three CE Layers
A T3Bootstrap project draws content elements from **three sources**, in order of
specificity:
1. **Core CEs** from TYPO3's `fluid_styled_content``textmedia`, `image`, `header`, `bullets`, `table`, `uploads`, `menu_*`, `shortcut`, …
T3Bootstrap **rewraps** these via `t3bootstrap/core` (extended `tt_content` fields, Bootstrap-aware Fluid templates).
2. **Custom CEs from `t3bootstrap/core`**`t3bs_card`, `t3bs_compareslider`, `t3bs_countdown`, `t3bs_counterbar`, `t3bs_numbercarousel`. These are **non-container**, single-element CEs with a fixed shape.
3. **Container CEs from `t3bootstrap/container-bs5-templates`** — the 23 `t3bs_*` elements that wrap or compose children via `b13/container`.
**Rule of thumb when migrating:**
- *Plain prose with optional images* → core `textmedia`. Don't reach for a container.
- *Headline + paragraph + image + button, arranged together* → still likely `textmedia` + `t3bs_buttonlink`, **unless** the visual requires Bootstrap card styling.
- *Multiple of these arranged in a Bootstrap-styled box* → `t3bs_card` (single) or `t3bs_cards` (grid).
- *Anything that **wraps** other content elements* → a container (`t3bs_container`, `t3bs_fluidrow` + `t3bs_column`, …).
## Core CEs — Use These First
The core CEs cover most static content. T3Bootstrap doesn't replace them; it gives them
better wrappers, frame classes, breakpoint grids and additional fields (`element_classes`,
`image_classes`, `imagecols_grid`, `background_media`).
| Core CType | When to use |
| --- | --- |
| `textmedia` | Default body content with optional images. Migrating any "paragraph + image" combination. |
| `text` | Pure prose, no media. |
| `header` | Standalone headline above a section. |
| `image` | Image only, optional caption. Migrating image galleries → one `image` per picture. |
| `textpic` | Legacy form of textmedia kept for backwards compatibility — prefer `textmedia` for new content. |
| `bullets` | Lists. |
| `table` | Tabular data. |
| `uploads` | File downloads. |
| `menu_*` | Sitemap, categorized pages, pages, recently updated, related pages. |
| `shortcut` | Reference another tt_content record (useful for "include this CE on multiple pages"). |
| `html` | Raw HTML. **Migration source for everything you can't classify yet** — but a follow-up pass should re-classify into proper CEs. |
T3Bootstrap-extended fields available on every CE:
- `element_classes` — extra CSS classes on the CE wrapper.
- `image_classes` — extra classes on image renderings.
- `imagecols_grid` — JSON breakpoint grid for image columns (responsive 1/2/3/4-col layouts).
- `background_media` — FAL reference for a section background image/video.
- Spacing palette (provided by `t3bootstrap/core`) — responsive padding/margin per breakpoint, stored as JSON in dedicated columns. *(See the spacing-stepper concept memo if extending this.)*
## Custom Single CEs from `t3bootstrap/core`
These are not containers — they're standalone elements with a fixed shape. Each is enabled
by including the matching Site Set.
| CType | Site Set | Source | Use for |
| --- | --- | --- | --- |
| `t3bsCard` (custom card) | `t3bootstrap/card-element` | `vendor/t3bootstrap/core/Configuration/TCA/Overrides/600_content_element_card.php` | A simple card without nested CEs — image, title, text, link. *Use over `t3bs_card` when no nested content elements are needed.* |
| `t3bsCompareSlider` | `t3bootstrap/compareslider-element` | `600_content_element_compare_slider.php` | Before/after image comparison with a draggable divider. |
| `t3bsCountdown` | `t3bootstrap/countdown-element` | `600_content_element_countdown.php` | Date/time countdown widget. |
| `t3bsCounterbar` | `t3bootstrap/counterbar-element` | `202_content_element_counterbar.php` | Animated number counter ("12,000+ customers"). |
| Hero | `t3bootstrap/hero-item` | `vendor/t3bootstrap/hero-item/Configuration/TCA/Overrides/tt_content.php` | Full-width banner with title, subtitle, background image/video, CTA. *Use over `t3bs_container` for landing pages.* |
| Teaser | `wapplersystems/teaser` | n/a | Image + headline + text teaser block, links to a page. |
| Testimonial | `wapplersystems/testimonials` | n/a | Quote + author + photo. |
| Slider | `wapplersystems/ws-slider*` | n/a | Each variant (`flexslider`, `swiper`, `tinyslider`, `slick`, `bootstrap`) is one CE. *Use over `t3bs_carousel` when image-only with no inner content.* |
## Container CEs — The 23 `t3bs_*` Elements
Defined in `vendor/t3bootstrap/container-bs5-templates/Configuration/TCA/Overrides/tt_content.php`
and registered via `b13/container`. **All container slots use the colPos range `2100021079`**.
### Layout containers — wrap arbitrary content
| CType | colPos | Children allowed | Purpose |
| --- | --- | --- | --- |
| `t3bs_container` | `21001` | any | Bootstrap `.container` / `.container-sm` / `.container-fluid` wrapper. Set `tx_t3bs_container_type` to choose the breakpoint. |
| `t3bs_fluidrow` | `21041` | only `t3bs_column` | Bootstrap `.row` with per-breakpoint column grid. |
| `t3bs_column` | `21050` | any | A `.col-*` cell. Width per breakpoint configured via TCA. Always a child of `t3bs_fluidrow`. |
### Content containers — wrap CEs in styled boxes
| CType | colPos | Purpose |
| --- | --- | --- |
| `t3bs_card` | `21008` | Bootstrap card with header/image/body/footer regions; children render in the body. |
| `t3bs_cards` | `21009` | A **set** of cards rendered as group / deck / grid / columns layout (`tx_t3bs_cards_layout`). Children: any. |
| `t3bs_alert` | `21003` | Bootstrap `.alert` (primary/success/danger/warning/info/light/dark) with optional close button. |
| `t3bs_panel` | `21005` | Styled panel (legacy Bootstrap-3-style box). |
| `t3bs_well` | `21004` | Inset well (small/normal/large via `tx_t3bs_well_style`). |
| `t3bs_example` | `21002` | Code-example container (renders the children inside a `.example` box used for documentation pages). |
| `t3bs_thumbnail` | `21006` | Image thumbnail with caption. |
| `t3bs_media` | `21007` | Bootstrap media object — image flush left or right of text. |
### Interactive containers — children become panels/slides/items
| CType | child colPos | Allowed children | Purpose |
| --- | --- | --- | --- |
| `t3bs_accordion` | `21011` | `t3bs_accordion_item` only | Accordion. Each `t3bs_accordion_item` becomes one collapsible panel. |
| `t3bs_accordion_item` | `21019` | any | One accordion panel — contains the body content. |
| `t3bs_tabs` | `21021` | `t3bs_tab_item` only | Tab container (tab/pill via `tx_t3bs_tabs_mode`). |
| `t3bs_tab_item` | `21029` | any | One tab pane. |
| `t3bs_carousel` | `21031` | `t3bs_carousel_item` only | Image/content carousel. Controls/indicators/interval configurable. |
| `t3bs_carousel_item` | `21039` | any | One slide. |
| `t3bs_timeline` | `21071` | `t3bs_timeline_item` only | Vertical timeline. |
| `t3bs_timeline_item` | `21079` | any | One timeline entry. |
### Navigation containers — buttons and megamenu
| CType | child colPos | Children | Purpose |
| --- | --- | --- | --- |
| `t3bs_buttongroup` | `21010` | `t3bs_buttonlink` only | Group of buttons (Bootstrap button group). |
| `t3bs_buttonlink` | — | (standalone) | Single button. Standalone CE — can also appear outside a button group. |
| `t3bs_megamenu` | `21061` | `t3bs_megamenu_item` only | Megamenu dropdown. |
| `t3bs_megamenu_item` | `21069` | any | One megamenu column / sub-section. |
### Parent-child Rules — Common Pitfalls
| Symptom | Cause | Fix |
| --- | --- | --- |
| `t3bs_column` placed without a parent → renders standalone | `t3bs_column` has no UI restriction at root but is only meaningful inside `t3bs_fluidrow`. | Always insert via "create child" inside a `t3bs_fluidrow`. |
| `t3bs_accordion_item` rendered outside an accordion | Same — no rendering wrapper. | Same — insert as a child of `t3bs_accordion`. |
| Editor can't find `t3bs_carousel_item` in the CE wizard root | Correct — these CTypes are deliberately filtered. | Edit by entering the parent's child slot. |
| Carousel/Tabs/Accordion show "0 children" but you added textmedia | You inserted into the parent's *own* colPos (e.g. 0) instead of the parent's *child slot colPos*. | Move the children to the parent's child slot (e.g. `colPos = 21011` for an accordion). |
## Migration Decision Matrix
For each source pattern, the recommended T3Bootstrap target.
### From static HTML / Bootstrap pages
| Source markup | Target CE |
| --- | --- |
| `<section>` with `.container` and paragraphs | `t3bs_container` wrapping `textmedia` children, **or** just `textmedia` with `imagecols_grid` if it's a single paragraph block |
| `.row > .col-md-4` × N | `t3bs_fluidrow` with N `t3bs_column` children. Set column widths per breakpoint via TCA. |
| `.card` block (image + title + body) | `t3bs_card` (with child content for the body) **or** the simpler standalone `t3bsCard` (no children needed) |
| `.card-deck` / `.row-cols-md-3 > .col` of cards | `t3bs_cards` with `tx_t3bs_cards_layout = deck` (or `grid-cards`) |
| `.accordion` / `<details>` | `t3bs_accordion` + one `t3bs_accordion_item` per item |
| Bootstrap `.nav-tabs` / `.nav-pills` | `t3bs_tabs` + `t3bs_tab_item` per tab |
| Bootstrap `.carousel` | `t3bs_carousel` + `t3bs_carousel_item` per slide |
| `.alert.alert-warning` | `t3bs_alert` with `tx_t3bs_alert_class = warning` |
| `.btn.btn-primary` | `t3bs_buttonlink` (with optional `t3bs_buttongroup` parent) |
| Hero `<section>` with full-bleed background | `Hero` (from `t3bootstrap/hero-item`) |
| Vertical timeline | `t3bs_timeline` + `t3bs_timeline_item` per step |
| Before/after slider | `t3bsCompareSlider` |
| Animated counter | `t3bsCounterbar` |
| Countdown timer | `t3bsCountdown` |
| Image gallery | `wapplersystems/filecollection-gallery` set with a `file_collection` CE, **or** N `image` CEs in a `t3bs_fluidrow`. |
### From WordPress
| Gutenberg block | Target |
| --- | --- |
| `core/paragraph` + `core/image` | `textmedia` |
| `core/heading` | `header` |
| `core/list` | `bullets` |
| `core/table` | `table` |
| `core/columns` + `core/column` | `t3bs_fluidrow` + `t3bs_column` |
| `core/group` (background, padding) | `t3bs_container` |
| `core/cover` (full-width image + heading) | `Hero` (from `t3bootstrap/hero-item`) |
| `core/buttons` + `core/button` | `t3bs_buttongroup` + `t3bs_buttonlink` |
| `core/media-text` | `t3bs_media` |
| `core/quote` / `core/pullquote` | `textmedia` with the `Frameless` layout + `element_classes = blockquote` — or a custom `Testimonial` CE if the visual is testimonial-style |
| `core/gallery` | `wapplersystems/filecollection-gallery` |
| WP CPT (e.g. portfolio item) | A TYPO3 news/blog/address record + custom record sitemap, **not** a CE |
| ACF flexible content / page builder layouts | Map each layout to the closest `t3bs_*` container; complex one-offs go in `t3bs_container` with `html` CE child |
### From Joomla
| Joomla pattern | Target |
| --- | --- |
| Joomla article body | `textmedia` (one per paragraph block, or one big with embedded media) |
| Module position | A page-level colPos in T3Bootstrap; map module → CE per the rest of this table |
| K2 / EasyBlog items | `news` records (via `t3bootstrap/news`) or `blog` posts (`t3bootstrap/blog`) |
| RSGallery / Phoca Gallery | `wapplersystems/filecollection-gallery` |
| RSForm / Chronoforms | EXT:form via `t3bootstrap/form` set |
| Sliders (DJ-ImageSlider, Smart Slider) | Pick a `ws-slider-*` variant per the brief (most projects use `swiper` or `flexslider`) |
| Modal / accordion modules | `t3bs_accordion` / `t3bs_tabs` |
| YOOtheme widget kit | Map each widget to its `t3bs_*` cousin; for icon + heading + text use `textmedia` with `t3bs_icon` |
### From older TYPO3 versions
#### From v9v12 with `flux_bs5_templates`
**Use the upgrade wizard.** Don't migrate manually — the wizard preserves child relations,
maps FlexForm values to the new dedicated `tx_t3bs_*` columns, and updates `tx_container_parent`.
```bash
# In DDEV, after composer-installing t3bootstrap/container-bs5-templates:
ddev exec vendor/bin/typo3 upgrade:run t3bsContainerBs5MigrateFluxBs5
# Or via the Install Tool: TYPO3 backend → Admin Tools → Upgrade → Upgrade Wizards
# → "Migrate flux_bs5_templates content elements to container_bs5_templates" → Execute
```
**Mapping the wizard applies** (source `vendor/t3bootstrap/container-bs5-templates/Classes/Updates/MigrateFluxBs5ToContainerBs5.php`):
| Old Flux CType | New CType | Notes |
| --- | --- | --- |
| `fluxbs5templates_container` | `t3bs_container` | FlexForm → `tx_t3bs_container_type` |
| `fluxbs5templates_example` | `t3bs_example` | |
| `fluxbs5templates_alert` | `t3bs_alert` | FlexForm → `tx_t3bs_alert_class`, `tx_t3bs_alert_block`, `tx_t3bs_alert_close_text` |
| `fluxbs5templates_well` | `t3bs_well` | FlexForm → `tx_t3bs_well_style` |
| `fluxbs5templates_panel` | `t3bs_panel` | FlexForm → `tx_t3bs_panel_class` |
| `fluxbs5templates_thumbnail` | `t3bs_thumbnail` | |
| `fluxbs5templates_media` | `t3bs_media` | |
| `fluxbs5templates_card` | `t3bs_card` | |
| `fluxbs5templates_cards` | `t3bs_cards` | FlexForm → `tx_t3bs_cards_layout`, `_grid`, `_gutter` |
| `fluxbs5templates_buttongroup` | `t3bs_buttongroup` | FlexForm → `tx_t3bs_bg_type` |
| `fluxbs5templates_accordion` | `t3bs_accordion` | Children rewired to `t3bs_accordion_item`, colPos 21011 |
| `fluxbs5templates_tabs` | `t3bs_tabs` | Children to `t3bs_tab_item`, colPos 21021. FlexForm → `tx_t3bs_tabs_mode`, `_direction`, `_stackable`, `_position` |
| `fluxbs5templates_carousel` | `t3bs_carousel` | Children to `t3bs_carousel_item`, colPos 21031. FlexForm → controls, indicators, interval, id, color |
| `fluxbs5templates_fluidrow` | `t3bs_fluidrow` | Each flex column becomes a `t3bs_column` child at colPos 21041 |
| `fluxbs5templates_buttonlink` | `t3bs_buttonlink` | FlexForm → full set of `tx_t3bs_button_*` fields |
| `fluxbs5templates_megamenu` | `t3bs_megamenu` | Children to `t3bs_megamenu_item`, colPos 21061 |
**After the wizard runs:** flush caches (`cache:flush`), update the reference index
(`referenceindex:update`), and re-import freshly delta-migrated content from live if you
were doing the parallel live→stage migration described in the global instructions.
#### From v8v11 with `gridelements`
No wizard. Map manually:
| `gridelements_pi1` layout | Target |
| --- | --- |
| 1-column grid | `t3bs_container` |
| 2-column grid | `t3bs_fluidrow` + 2× `t3bs_column` |
| 3/4-column grid | `t3bs_fluidrow` + N× `t3bs_column` |
| Tabbed grid | `t3bs_tabs` + N× `t3bs_tab_item` |
| Accordion grid | `t3bs_accordion` + N× `t3bs_accordion_item` |
| Hero grid | `Hero` (from `t3bootstrap/hero-item`) |
In a migration project: SQL-query `tt_content WHERE CType='gridelements_pi1'`, group by
`tx_gridelements_backend_layout`, and rewrite the CType + children's `colPos` (gridelements
uses `tx_gridelements_columns` instead of `tx_container_parent`).
#### From v8v11 with `dce`
No wizard. DCE content elements are project-specific. For each DCE:
1. Look at its rendering template — what HTML does it emit?
2. Pick the closest `t3bs_*` CE.
3. Map DCE fields → `tx_t3bs_*` columns or extended `tt_content` fields from `t3bootstrap/core`.
4. Custom-only DCEs that have no direct equivalent → wrap in `t3bs_container` with an `html` child for the unique markup, plan to replace gradually.
#### From v11/v12 with `bootstrap_package`
`bootstrap_package` has a different content element set. Mapping:
| `bootstrap_package` CType | T3Bootstrap CType |
| --- | --- |
| `bootstrap_package_card_group` | `t3bs_cards` |
| `bootstrap_package_carousel` | `t3bs_carousel` |
| `bootstrap_package_accordion` | `t3bs_accordion` |
| `bootstrap_package_tabs` | `t3bs_tabs` |
| `bootstrap_package_modal` | No direct CE — use `t3bs_buttonlink` with `tx_t3bs_button_modal = 1` and a referenced text block |
| `bootstrap_package_listgroup` | `bullets` with `element_classes = list-group` |
| `bootstrap_package_panel` | `t3bs_panel` |
| `bootstrap_package_jumbotron` | `Hero` (`t3bootstrap/hero-item`) |
| `bootstrap_package_textmedia` | core `textmedia` |
| `bootstrap_package_icon_group` | `t3bs_fluidrow` + `t3bs_column` per icon, `textmedia` with `tx_t3bs_icon` set inside each |
`bootstrap_package`'s `bootstrap_package_card_group` already uses child elements wired via
TCA — copy the child relationships rather than rebuild.
## When to Pick Which Layer (Cheat Sheet)
```
Is it a wrapping/grouping element (multiple CEs sit inside)?
├── YES → container CE
│ ├── styled box around children? → t3bs_card / t3bs_alert / t3bs_panel / t3bs_well
│ ├── tabs/accordion/carousel? → t3bs_tabs / t3bs_accordion / t3bs_carousel
│ ├── timeline? → t3bs_timeline
│ ├── grid? → t3bs_fluidrow + t3bs_column
│ ├── button group? → t3bs_buttongroup
│ └── transparent / just structure? → t3bs_container
└── NO → single CE
├── prose + maybe one image? → textmedia
├── headline only? → header
├── image-only? → image
├── list? → bullets
├── table? → table
├── hero banner? → Hero (hero-item)
├── card without nested CEs? → t3bsCard (card-element)
├── before/after slider? → t3bsCompareSlider
├── animated number? → t3bsCounterbar
├── countdown? → t3bsCountdown
├── testimonial? → wapplersystems/testimonials
├── slider with image-only slides? → ws-slider variant
├── button-only? → t3bs_buttonlink (standalone)
└── still no fit? → html (temporary, plan to re-classify)
```
## colPos Map (Reference)
When debugging "where did my child go?" — the colPos numbers reserved by
`t3bootstrap/container-bs5-templates`:
```
21001 t3bs_container (single slot)
21002 t3bs_example
21003 t3bs_alert
21004 t3bs_well
21005 t3bs_panel
21006 t3bs_thumbnail
21007 t3bs_media
21008 t3bs_card
21009 t3bs_cards
21010 t3bs_buttongroup (allows only t3bs_buttonlink)
21011 t3bs_accordion (allows only t3bs_accordion_item)
21019 t3bs_accordion_item
21021 t3bs_tabs (allows only t3bs_tab_item)
21029 t3bs_tab_item
21031 t3bs_carousel (allows only t3bs_carousel_item)
21039 t3bs_carousel_item
21041 t3bs_fluidrow (allows only t3bs_column)
21050 t3bs_column
21061 t3bs_megamenu (allows only t3bs_megamenu_item)
21069 t3bs_megamenu_item
21071 t3bs_timeline (allows only t3bs_timeline_item)
21079 t3bs_timeline_item
```
`tx_container_parent` on a child row stores the parent's `uid`; the child's `colPos` is set
to the parent's slot. Direct SQL example:
```sql
-- All children of accordion uid=42
SELECT uid, CType, header, colPos, tx_container_parent
FROM tt_content
WHERE tx_container_parent = 42 AND colPos = 21011;
```
## Content Defender Hints (TYPO3 v14.1+)
`content_defender` is part of TYPO3 v14.1 Core. The container declarations in
`t3bootstrap/container-bs5-templates` already use the `allowed` constraint on the slot
arrays:
```php
$registerContainer($registry, 't3bs_accordion', $ll . 'ce.accordion',
[[['name' => $ll . 'slot.item', 'colPos' => 21011, 'allowed' => ['CType' => 't3bs_accordion_item']]]],
...
);
```
This automatically enforces the "tabs only contain tab items" / "accordions only contain
accordion items" rules — editors can't accidentally drop a `textmedia` into an accordion's
item slot. **Don't override this in PageTSconfig unless you have a deliberate reason.**
For a customer-specific column (e.g. "this colPos accepts only Hero or Card"), add the
constraint in your customer extension's PageTSconfig:
```typoscript
# local_packages/<customer>/site_<customer>/Configuration/page.tsconfig
mod.web_layout.tt_content.colPos_list := addToList(2)
mod.web_layout.BackendLayouts.HeroPage.config.backend_layout.rows.1.columns.1.allowed.CType = t3bootstrap_hero,t3bsCard
```
## Migration Workflow
```
1. Inventory the source.
- WP: `wp post list`, screenshot blocks per post type
- TYPO3: `SELECT CType, COUNT(*) FROM tt_content GROUP BY CType` (use claude-diagnostics' database:query)
- Static: scrape the rendered pages, categorize by visual pattern
2. Build the mapping table (use the decision matrix above).
3. For flux_bs5_templates → ALWAYS the upgrade wizard. Don't re-do this work.
4. For other sources, write the new content in the TYPO3 backend with the right CTypes,
or script the import via a custom Symfony Command.
5. After import: cache:flush, referenceindex:update, visually compare against the source.
6. For each migrated CE, check: is the visual right? If not — is it a missing CE field
(use the t3bootstrap-overrides skill for template tweaks) or a wrong CE choice
(re-evaluate)?
```
## Anti-Patterns
| Anti-pattern | Why it's bad | Correct approach |
| --- | --- | --- |
| Migrating all content as `html` CE | Loses TYPO3 semantics, FAL, link handling, accessibility | Use the decision matrix; `html` is the last resort, not the first |
| Hand-migrating `flux_bs5_templates` content | Tedious, error-prone, breaks parent-child relations | Run the `t3bsContainerBs5MigrateFluxBs5` wizard |
| Using `t3bs_container` for prose | Renders an empty Bootstrap container wrapper for no reason | Use `textmedia` directly; the page template already wraps it |
| Stacking `t3bs_container` inside `t3bs_container` | Nested Bootstrap containers cause padding/margin compounding bugs | Use `t3bs_fluidrow` + `t3bs_column` to subdivide instead |
| Placing `t3bs_buttonlink` inside a textmedia bodytext as RTE link | Looks like a button in the editor, won't get the Bootstrap classes | Use the `t3bs_buttonlink` CE next to the textmedia, or a `t3bs_buttongroup` if multiple |
| Migrating a multi-image gallery as N separate `image` CEs | Loses the gallery's grid relationship | `wapplersystems/filecollection-gallery` set + `file_collection` CE |
| Creating one `t3bs_card` per card in a 3-card grid | Each card is its own outer container | One `t3bs_cards` parent with three child content elements (one per card) — `tx_t3bs_cards_layout = grid-cards` for the grid |
## Reference Files in This Project
```text
vendor/t3bootstrap/container-bs5-templates/Configuration/TCA/Overrides/tt_content.php # all t3bs_* registrations + ContainerConfiguration
vendor/t3bootstrap/container-bs5-templates/Classes/Updates/MigrateFluxBs5ToContainerBs5.php # the upgrade wizard
vendor/t3bootstrap/container-bs5-templates/Resources/Private/Templates/ # CE Fluid templates
vendor/t3bootstrap/core/Configuration/TCA/Overrides/10_tt_content.php # extended tt_content fields (image_classes, element_classes, imagecols_grid, background_media)
vendor/t3bootstrap/core/Configuration/TCA/Overrides/600_content_element_card.php # t3bsCard standalone
vendor/t3bootstrap/core/Configuration/TCA/Overrides/600_content_element_compare_slider.php
vendor/t3bootstrap/core/Configuration/TCA/Overrides/600_content_element_countdown.php
vendor/t3bootstrap/core/Configuration/TCA/Overrides/202_content_element_counterbar.php
vendor/t3bootstrap/hero-item/Configuration/TCA/Overrides/tt_content.php # Hero CType
```
For overriding any of these CEs (different colors, additional fields, replaced templates),
switch to the **`t3bootstrap-overrides`** skill.
For project bootstrapping (required composer packages, site sets), see the
**`t3bootstrap-site-package`** skill.
@@ -0,0 +1,4 @@
interface:
display_name: "T3Bootstrap Content Elements"
short_description: "Pick the right CE when migrating content to T3Bootstrap"
default_prompt: "Use $t3bootstrap-content-elements to choose which TYPO3 content element fits a piece of source content — the 23 t3bs_* container CEs, the custom single CEs (Card, CompareSlider, Countdown, Counterbar, Hero, Teaser, Testimonial), and the right CType-mapping for static HTML, WordPress blocks, Joomla modules, gridelements, dce, bootstrap_package, and the flux_bs5_templates → container_bs5_templates upgrade wizard."
@@ -0,0 +1,519 @@
---
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.
@@ -0,0 +1,4 @@
interface:
display_name: "T3Bootstrap Overrides"
short_description: "Customize T3Bootstrap minimally without forking upstream"
default_prompt: "Use $t3bootstrap-overrides to customize a T3Bootstrap-based TYPO3 v14 project — pick the least invasive override surface (Site Settings, SCSS `!default`, Fluid `templateRootPaths.10`, or custom DataProcessor) for the change at hand and ship it from a thin customer extension instead of forking `vendor/t3bootstrap/*`."
@@ -0,0 +1,402 @@
---
name: t3bootstrap-site-package
description: Set up and configure a TYPO3 v14 project on the T3Bootstrap stack — composer repositories and dependencies for `t3bootstrap/*` and `wapplersystems/*` packages, site configuration with the right Site Sets, multi-language setup, when (and when not) to add a local site package, and the standard set of optional add-on packages (news, blog, address, sliders, gallery, hero, card, counter, countdown). Use this skill when bootstrapping a new T3Bootstrap project, adding a t3bootstrap add-on to an existing project, debugging "set not found" or unexpected content-element-missing errors, or deciding whether a customer-specific extension is needed.
---
# T3Bootstrap Site Package
Use this skill when setting up or extending a TYPO3 v14 project that is built on the
**T3Bootstrap** stack — i.e. uses `t3bootstrap/template`, `t3bootstrap/core` and the
related WapplerSystems extensions instead of (or in addition to) a hand-rolled site
package.
> **Companion skills:**
> - [`t3bootstrap-overrides`](../t3bootstrap-overrides/SKILL.md) once setup is done and customer styling/templating begins.
> - [`t3bootstrap-content-elements`](../t3bootstrap-content-elements/SKILL.md) for which CE to use where.
## First Checks
Before adding anything, **read what already exists**:
1. Is the project Composer mode? (`composer.json` at root, `vendor/` directory present.)
2. Which `t3bootstrap/*` and `wapplersystems/*` packages are already required? — `composer show | grep -E "t3bootstrap|wapplersystems"`
3. Where is the site config? — `config/sites/<site-id>/config.yaml`. Which sets does its `dependencies:` list?
4. Is there a **local site package**? Look for `packages/<vendor>/`, `local_packages/`, or any in-repo TYPO3 extension. **On a vanilla T3Bootstrap project there usually is NO local site package** — the stack is sufficient out of the box and customization happens via Site Settings + Fluid overrides (see `t3bootstrap-overrides`).
5. Is DDEV configured? — `.ddev/config.yaml` present. Confirm PHP version and the DB engine before suggesting commands.
## The Core Stack
A T3Bootstrap project always uses these three foundation extensions:
| Package | Role |
| --- | --- |
| `t3bootstrap/core` | Base ext: ViewHelpers, DataProcessors, BackendLayouts, extended `tt_content` fields (spacing, background, classes, breakpoint grid), `RegisterUtility` (TSFE-replacement registry on v14). |
| `t3bootstrap/template` | Site template: page layouts, navigation, footer, search box, language menu, SCSS theme. Pulls Bootstrap 5 and the icon sets. |
| `t3bootstrap/container-bs5-templates` | The 23 Bootstrap 5 content elements (Card, Accordion, Tabs, Carousel, Timeline, Grid Row/Col, Megamenu, Buttons, …). Replaces the legacy Flux-based `flux_bs5_templates`. |
These three are mandatory. Everything else is an add-on.
### Add-on Packages
All add-ons are optional; pull only what the project needs. Each ships its own Site Set
that has to be included in the site config to take effect.
#### T3Bootstrap-vendored add-ons
| Package | Adds |
| --- | --- |
| `t3bootstrap/hero-item` | Hero content element (full-width banner with title, subtitle, CTA, background image/video). |
| `t3bootstrap/t3bootstrap-news` | `georgringer/news` integration with T3Bootstrap-styled list/detail templates. |
| `t3bootstrap/t3bootstrap-blog` | `t3g/blog` integration with T3Bootstrap-styled templates. |
| `t3bootstrap/t3bootstrap-address` | Address record CE styled for the template. |
| `t3bootstrap/t3bootstrap-form` | EXT:form templates and finishers wired into the template. |
| `t3bootstrap/t3bootstrap-filecollection_gallery` | File-collection-driven gallery CE. |
| `t3bootstrap/t3bootstrap-wsslider` | Slider integration for ws_slider. |
| `t3bootstrap/template-fontawesomeicons` | Font Awesome icon set Site Set. |
| `t3bootstrap/template-bootstrapicons` | Bootstrap Icons Site Set. |
| `t3bootstrap/template-aos` | Animate-on-scroll Site Set. |
| `t3bootstrap/template-imagedesigns` | Image design presets (rounded, framed, shadowed, …). |
#### WapplerSystems shared extensions
| Package | Adds |
| --- | --- |
| `wapplersystems/ws-scss` | SCSS-to-CSS compilation pipeline used by `t3bootstrap/template`. |
| `wapplersystems/ws-components` | Modular SCSS/JS component system (`<scssComponents:require>` / `<jsComponents:require>`). |
| `wapplersystems/ws-slider` | Generic slider framework (front-end-library-agnostic). |
| `wapplersystems/font-downloader` | Self-host Google Fonts. |
| `wapplersystems/teaser` | Teaser CE. |
| `wapplersystems/videos` | Video CE. |
| `wapplersystems/testimonials` | Testimonials CE. |
| `wapplersystems/address` | Address plugin (news-variant). |
| `wapplersystems/newslayouts` | Additional news layouts (3-col, 4-col, vertical list, top-image detail, …). |
| `wapplersystems/tag` | Tagging system. |
## composer.json — The Repository Block
All T3Bootstrap packages are hosted on the **Gitea** instance at `git.wappler.systems`,
WapplerSystems packages on **GitHub**. Both need explicit `repositories` entries in
`composer.json` (Packagist does not mirror them).
```json
{
"repositories": [
{ "type": "git", "url": "gitea@git.wappler.systems:T3Bootstrap/core.git" },
{ "type": "git", "url": "gitea@git.wappler.systems:T3Bootstrap/template.git" },
{ "type": "git", "url": "gitea@git.wappler.systems:T3Bootstrap/container-bs5-templates.git" },
{ "type": "git", "url": "gitea@git.wappler.systems:T3Bootstrap/t3bootstrap-news.git" },
{ "type": "git", "url": "gitea@git.wappler.systems:T3Bootstrap/t3bootstrap-blog.git" },
{ "type": "git", "url": "gitea@git.wappler.systems:T3Bootstrap/t3bootstrap-address.git" },
{ "type": "git", "url": "gitea@git.wappler.systems:T3Bootstrap/t3bootstrap-form.git" },
{ "type": "git", "url": "gitea@git.wappler.systems:T3Bootstrap/t3bootstrap-heroitem.git" },
{ "type": "git", "url": "gitea@git.wappler.systems:T3Bootstrap/t3bootstrap-filecollection_gallery.git" },
{ "type": "git", "url": "gitea@git.wappler.systems:T3Bootstrap/t3bootstrap-wsslider.git" },
{ "type": "git", "url": "git@github.com:WapplerSystems/ws_scss.git" },
{ "type": "git", "url": "git@github.com:WapplerSystems/ws-components.git" },
{ "type": "git", "url": "git@github.com:WapplerSystems/teaser.git" },
{ "type": "git", "url": "git@github.com:WapplerSystems/videos.git" },
{ "type": "git", "url": "git@github.com:WapplerSystems/testimonials.git" }
]
}
```
### SSH access
The Gitea SSH URL requires the developer machine to be authorized at
`git.wappler.systems`. Inside DDEV containers, run `ddev auth ssh` on the **host**
beforehand so the agent forwards. HTTPS fallback URL pattern:
`https://git.wappler.systems/T3Bootstrap/<repo>.git`.
### Require Block — Version Aliasing
The packages are typically tracked on the `release/v14` branch. Use `as`-aliases so
Composer's solver treats the dev branch as a satisfiable version range:
```json
{
"require": {
"typo3/cms-core": "^14.0",
"t3bootstrap/core": "dev-release/v14 as 14.0.0",
"t3bootstrap/template": "dev-release/v14 as 14.0.0",
"t3bootstrap/container-bs5-templates": "dev-release/v14 as 14.0.0",
"t3bootstrap/t3bootstrap-news": "dev-release/v14 as 14.0.0",
"wapplersystems/ws-scss": "dev-master as 14.0.0",
"wapplersystems/ws-components": "dev-master as 14.0.0"
}
}
```
> **Stability:** add `"minimum-stability": "dev"` and `"prefer-stable": true` at the
> top level — otherwise Composer refuses dev branches.
## Site Sets — The Real Configuration Surface
T3Bootstrap configures itself via **TYPO3 v14 Site Sets**, not by patching TypoScript
into the root template. Every t3bootstrap and wapplersystems extension ships one or more
sets under `Configuration/Sets/<SetName>/config.yaml`.
### Set Catalog (foundation)
| Set | Provided by | Pulls in |
| --- | --- | --- |
| `t3bootstrap/core` | `t3bootstrap/core` | TypoScript constants & setup for the core registry, ViewHelpers, DataProcessors. |
| `t3bootstrap/template` | `t3bootstrap/template` | Page rendering, layouts, navigation, footer; **depends on** `t3bootstrap/core`, `t3bootstrap/gridlayouts`, `typo3/indexed-search`. |
| `t3bootstrap/container-bs5-templates` | `t3bootstrap/container-bs5-templates` | All 23 `t3bs_*` CTypes; depends on `t3bootstrap/core`. |
| `t3bootstrap/gridlayouts` | `t3bootstrap/core` | Grid layouts for text/media elements (CE-internal column splits). |
### Set Catalog (icons / theming)
| Set | Provided by | Pulls in |
| --- | --- | --- |
| `t3bootstrap/template-fontawesomeicons` | `t3bootstrap/template` | Font Awesome assets and link to the icon picker. |
| `t3bootstrap/template-bootstrapicons` | `t3bootstrap/template` | Bootstrap Icons assets. |
| `t3bootstrap/template-aos` | `t3bootstrap/template` | animate-on-scroll JS + CSS. |
| `t3bootstrap/template-imagedesigns` | `t3bootstrap/template` | Image design presets. |
| `t3bootstrap/icons` | `t3bootstrap/core` | Generic icon registry hooks. |
### Set Catalog (CE add-ons)
| Set | Provided by |
| --- | --- |
| `t3bootstrap/card-element` | `t3bootstrap/core` |
| `t3bootstrap/compareslider-element` | `t3bootstrap/core` |
| `t3bootstrap/countdown-element` | `t3bootstrap/core` |
| `t3bootstrap/counterbar-element` | `t3bootstrap/core` |
| `t3bootstrap/hero-item` | `t3bootstrap/hero-item` |
### Set Catalog (news / blog / address / form / gallery)
| Set | Provided by |
| --- | --- |
| `t3bootstrap/news` | `t3bootstrap/t3bootstrap-news` |
| `t3bootstrap/news-timeline-cards-straight` | `t3bootstrap/t3bootstrap-news` |
| `t3bootstrap/news-timeline-cards-alternately` | `t3bootstrap/t3bootstrap-news` |
| `t3bootstrap/news-newsblock` | `t3bootstrap/t3bootstrap-news` |
| `t3bootstrap/news-background-image-latest` | `t3bootstrap/t3bootstrap-news` |
| `t3bootstrap/news-right-image-latest` | `t3bootstrap/t3bootstrap-news` |
| `wapplersystems/newslayouts` | `wapplersystems/newslayouts` |
| `wapplersystems/newslayouts-detail-topimage` | `wapplersystems/newslayouts` |
| `wapplersystems/newslayouts-list-3columns` | `wapplersystems/newslayouts` |
| `wapplersystems/newslayouts-list-4columns` | `wapplersystems/newslayouts` |
| `wapplersystems/newslayouts-list-vertical` | `wapplersystems/newslayouts` |
| `t3bootstrap/blog` | `t3bootstrap/t3bootstrap-blog` |
| `t3bootstrap/address` | `t3bootstrap/t3bootstrap-address` |
| `wapplersystems/address-googlemaps` | `wapplersystems/address` |
| `wapplersystems/address-openstreetmap` | `wapplersystems/address` |
| `t3bootstrap/form` | `t3bootstrap/t3bootstrap-form` |
| `wapplersystems/filecollection-gallery` | `t3bootstrap/t3bootstrap-filecollection_gallery` |
| `wapplersystems/teaser` | `wapplersystems/teaser` |
| `wapplersystems/testimonials` | `wapplersystems/testimonials` |
### Set Catalog (sliders)
| Set | Provided by |
| --- | --- |
| `wapplersystems/ws-slider` | `wapplersystems/ws-slider` |
| `wapplersystems/ws-slider-flexslider` | `wapplersystems/ws-slider` |
| `wapplersystems/ws-slider-tinyslider` | `wapplersystems/ws-slider` |
| `wapplersystems/ws-slider-swiper` | `wapplersystems/ws-slider` |
| `wapplersystems/ws-slider-bootstrap` | `wapplersystems/ws-slider` |
| `wapplersystems/ws-slider-slick` | `wapplersystems/ws-slider` |
| `t3bootstrap/ws-slider` | `t3bootstrap/t3bootstrap-wsslider` (T3Bootstrap-styled wrapper) |
> A package's **PHP code** is loaded once Composer pulls it in. Its **TypoScript and
> settings**, however, only take effect when the matching **Site Set is listed in
> `config/sites/<site-id>/config.yaml`** — adding the composer dependency without the
> set means nothing renders.
## Site Config — Typical `config.yaml`
```yaml
base: 'https://my-project.example.com/'
rootPageId: 1
websiteTitle: 'My Project'
dependencies:
# foundation — order matters: core → template → CE library
- t3bootstrap/template # depends on t3bootstrap/core + gridlayouts
- t3bootstrap/container-bs5-templates
# icons & theme add-ons
- t3bootstrap/template-fontawesomeicons
- t3bootstrap/template-bootstrapicons
- t3bootstrap/template-aos
- t3bootstrap/template-imagedesigns
# CE add-ons (only what the project needs)
- t3bootstrap/card-element
- t3bootstrap/counterbar-element
- t3bootstrap/countdown-element
- t3bootstrap/compareslider-element
- t3bootstrap/hero-item
# content domains (only what the project needs)
- t3bootstrap/news
- t3bootstrap/blog
- t3bootstrap/address
- t3bootstrap/form
# optional vendor add-ons
- wapplersystems/teaser
- wapplersystems/testimonials
- wapplersystems/newslayouts
- wapplersystems/ws-slider-swiper
- wapplersystems/filecollection-gallery
# TYPO3 core sets
- typo3/felogin
- typo3/seo-sitemap
languages:
- title: Deutsch
enabled: true
languageId: 0
base: /de/
locale: de_DE.utf8
iso-639-1: de
hreflang: de
flag: de
- title: English
enabled: true
languageId: 1
base: /en/
locale: en_US.utf8
iso-639-1: en
hreflang: en
fallbackType: strict
flag: en-us-gb
errorHandling:
- errorCode: 404
errorHandler: Page
errorContentSource: 't3://page?uid=<404-page-uid>'
- errorCode: 403
errorHandler: Page
errorContentSource: 't3://page?uid=<403-page-uid>'
- errorCode: 500
errorHandler: Page
errorContentSource: 't3://page?uid=<500-page-uid>'
routes:
- route: robots.txt
type: staticText
content: |
User-agent: *
Disallow: /typo3/
Disallow: /typo3_src/
Allow: /typo3/sysext/frontend/Resources/Public/*
```
### Set Dependency Resolution
A set's `dependencies:` are resolved transitively — listing `t3bootstrap/template`
automatically pulls in `t3bootstrap/core` and `t3bootstrap/gridlayouts`. You only need
to list the *highest-level* set you want active.
But: **explicit beats transitive for clarity.** Listing the foundation sets explicitly
makes the config self-documenting and avoids surprises when sets change their deps.
## Do You Need a Local Site Package?
The honest answer for most projects: **no**. The T3Bootstrap stack already provides
everything a site package usually wraps:
| Site-package responsibility | Where it lives in the T3Bootstrap stack |
| --- | --- |
| Page rendering / Fluid layouts | `t3bootstrap/template` → override via `templateRootPaths.10` (see `t3bootstrap-overrides`) |
| Content element templates | `t3bootstrap/container-bs5-templates` + `t3bootstrap/core` → override via root-paths |
| Color theme | `_variables.scss` `!default` overrides (see `t3bootstrap-overrides`) |
| Backend layouts | shipped by `t3bootstrap/template`, customer extends via PageTSconfig |
| Routing | site config `routeEnhancers` |
| Settings | site config `settings:` + site sets |
### When you DO need a local extension
Add a customer-specific extension only if **any** of these is true:
- **Custom PHP** — DataProcessors, Middlewares, EventListeners, ViewHelpers, RegisterUtility extensions, Scheduler tasks. PHP must live in a registered extension.
- **Custom Fluid templates** that go beyond drop-in overrides — e.g. you want to ship reusable Partials for the customer's brand. (Even drop-in overrides work without an extension if you load them from `fileadmin/`, but that mixes content storage with code — not recommended.)
- **Custom TCA** — fields on `tt_content` or other tables beyond what `t3bootstrap/core` already adds.
- **Customer-specific Site Set** — settings, additional TypoScript, a backend layout shipped per project. Sets must live in `Configuration/Sets/<name>/config.yaml` of an extension.
### Skeleton for a customer extension
```text
local_packages/<customer>/site_<customer>/
├── composer.json
├── ext_emconf.php
├── Classes/
│ ├── DataProcessing/
│ └── ViewHelpers/
├── Configuration/
│ ├── Sets/
│ │ └── Site<Customer>/
│ │ ├── config.yaml
│ │ ├── settings.yaml
│ │ └── setup.typoscript
│ └── TCA/Overrides/
├── Resources/
│ ├── Private/
│ │ ├── Templates/ # site-package overrides (see t3bootstrap-overrides skill)
│ │ ├── Partials/
│ │ ├── Layouts/
│ │ └── Language/
│ └── Public/
│ └── Scss/_overrides.scss # !default overrides
└── ext_localconf.php
```
Register the extension as a path repository in the root `composer.json`:
```json
{
"repositories": [
{ "type": "path", "url": "local_packages/<customer>/site_<customer>" }
],
"require": {
"<customer>/site-<customer>": "@dev"
}
}
```
Then add `<customer>/site-<customer>` to the site config `dependencies:`.
## Common Pitfalls
| Symptom | Cause | Fix |
| --- | --- | --- |
| Backend shows no t3bs_* CEs | `t3bootstrap/container-bs5-templates` is required but its **Site Set is not listed** in `config/sites/<id>/config.yaml`. | Add `t3bootstrap/container-bs5-templates` to `dependencies:`. |
| Frontend renders without styling | `t3bootstrap/template` set missing from `dependencies:`, or DDEV is serving stale CSS. | Verify set is listed, then `ddev exec vendor/bin/typo3 cache:flush` + recompile SCSS via `wapplersystems/ws-scss`. |
| `Class "T3Bootstrap\Core\…" not found` | composer didn't pick up the package — usually missing `repositories` entry or no `dev-release/v14` `as` alias. | Re-check `composer.json`, run `composer require t3bootstrap/core:dev-release/v14`. |
| `Set "t3bootstrap/news" not found` | the matching composer package (`t3bootstrap/t3bootstrap-news`) is not installed. | `composer require t3bootstrap/t3bootstrap-news`. |
| News-extension styled wrong | `wapplersystems/newslayouts` listed before `t3bootstrap/news` so the t3bootstrap templates override the wapplersystems ones. | Order matters: T3Bootstrap-news set FIRST, then wapplersystems newslayouts add-ons. |
| Permission prompt on Gitea SSH inside DDEV | DDEV agent isn't forwarded. | `ddev auth ssh` on host before `ddev composer install`. |
## Standard Setup Workflow
1. **Scaffold** with TYPO3 v14 distribution or a clean Composer install.
2. **Add `claude-diagnostics`** (per global instructions) so the rest is faster to debug.
3. **Add repositories block** to `composer.json` for the Gitea + GitHub URLs of t3bootstrap and wapplersystems packages.
4. **Set stability:** `minimum-stability: dev`, `prefer-stable: true`.
5. **Require the foundation:** `t3bootstrap/template`, `t3bootstrap/container-bs5-templates``t3bootstrap/core` comes transitively but list it explicitly if you want pinning.
6. **Require add-ons** matching the project brief (news/blog/form/gallery/sliders).
7. **Site config** — list the sets matching the requires; add languages, error handling, route enhancers.
8. **Site Setting Module** in the TYPO3 backend → verify all sets resolved, no "set not found" errors.
9. **Flush caches**, log in, place a "Card" content element to verify `t3bs_*` CTypes appear.
10. **Decide on overrides** — switch to the `t3bootstrap-overrides` skill once the customer wants color/layout adjustments.
## Where to Find Things in the Vendor Tree
```text
vendor/t3bootstrap/core/Configuration/Sets/ # Core sets (gridlayouts, icons, T3BCore)
vendor/t3bootstrap/template/Configuration/Sets/Template/ # Main site template set
vendor/t3bootstrap/template/Configuration/TypoScript/ # TypoScript constants + setup
vendor/t3bootstrap/container-bs5-templates/Configuration/Sets/ContainerBs5Templates/
vendor/t3bootstrap/container-bs5-templates/Classes/Updates/MigrateFluxBs5ToContainerBs5.php
```
For the override surfaces (`templateRootPaths.10`, SCSS variables, …) see the
**`t3bootstrap-overrides`** skill.
For the CE catalog and content-migration mapping see the
**`t3bootstrap-content-elements`** skill.
@@ -0,0 +1,4 @@
interface:
display_name: "T3Bootstrap Site Package"
short_description: "Set up TYPO3 v14 projects on the T3Bootstrap stack"
default_prompt: "Use $t3bootstrap-site-package to bootstrap or extend a TYPO3 v14 project built on the t3bootstrap/* and wapplersystems/* extensions — composer repositories, package selection, site sets, languages, route enhancers, and the question of when a local site-package extension is actually needed."