Initial Commit
This commit is contained in:
624
VITEC-ContentBlocks-Setup.md
Normal file
624
VITEC-ContentBlocks-Setup.md
Normal file
@@ -0,0 +1,624 @@
|
||||
# VITEC Content Blocks Setup — Step-by-Step
|
||||
|
||||
**Strategie:** Content Blocks (YAML-basiert, deklarativ) als Haupt-Pattern für alle VITEC Content Elements. `nb-headless-content-blocks` übernimmt automatisch das JSON-Mapping.
|
||||
|
||||
**Stack-Basis bei dir (bereits vorhanden):**
|
||||
- `evomedien/vitec` — deine Extension
|
||||
- Site Set `evomedien/vitecset`
|
||||
- `friendsoftypo3/headless` (`headless: 1`)
|
||||
- `nb-headless-content-blocks` (Bridge)
|
||||
- `b13/container` + `itplusx/headless-container` (für Layout-Wrapper, optional)
|
||||
|
||||
---
|
||||
|
||||
## 0. Aufräumen (zwei kleine Issues vorab)
|
||||
|
||||
### 0.1 `nb-headless-content-blocks` ins Site Set migrieren
|
||||
|
||||
Aktuell steht die Extension nur in der **Site-Config**, nicht im **Site Set**. Das sollte konsistent sein, damit das Set in sich abgeschlossen ist.
|
||||
|
||||
**Datei:** `packages/vitec/Configuration/Sets/VitecSet/config.yaml` (oder wo dein Set liegt)
|
||||
|
||||
```yaml
|
||||
name: evomedien/vitecset
|
||||
label: VITEC Set
|
||||
settings:
|
||||
website:
|
||||
background:
|
||||
color: '#386492'
|
||||
dependencies:
|
||||
- typo3/fluid-styled-content
|
||||
- friendsoftypo3/headless
|
||||
- b13/container
|
||||
- itplusx/headless-container
|
||||
- nb-headless-content-blocks/headless-content-blocks # NEU
|
||||
```
|
||||
|
||||
Dann aus `config/sites/<identifier>/config.yaml` die Zeile `- nb-headless-content-blocks/headless-content-blocks` wieder rausnehmen — sie kommt jetzt transitiv über dein Set.
|
||||
|
||||
### 0.2 Version-Mismatch fixen
|
||||
|
||||
- `composer.json` sagt `1.0.1`
|
||||
- `ext_emconf.php` sagt `0.0.1`
|
||||
|
||||
Einfach beide auf den gleichen Wert bringen (Empfehlung: `1.0.0` und bei jedem Deployment hochzählen). Nicht dringend, aber sauber:
|
||||
|
||||
```php
|
||||
// ext_emconf.php
|
||||
'version' => '1.0.0',
|
||||
'state' => 'stable', // 'alpha' wirkt im Produktivbetrieb komisch
|
||||
```
|
||||
|
||||
```json
|
||||
// composer.json
|
||||
"version": "1.0.0"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. Ordnerstruktur anlegen
|
||||
|
||||
Content Blocks leben in der Extension unter einer festen Pfad-Konvention:
|
||||
|
||||
```
|
||||
packages/vitec/
|
||||
├── ContentBlocks/
|
||||
│ └── ContentElements/
|
||||
│ ├── hero-section/ ← erster Content Block (Beispiel)
|
||||
│ │ ├── config.yaml ← Feld-Definitionen
|
||||
│ │ ├── assets/
|
||||
│ │ │ └── icon.svg ← Icon für CE-Wizard
|
||||
│ │ ├── language/
|
||||
│ │ │ └── labels.xlf ← Übersetzungen
|
||||
│ │ └── templates/
|
||||
│ │ └── EditorPreview.html ← optional: Backend-Preview
|
||||
│ ├── feature-teaser/
|
||||
│ ├── cta-banner/
|
||||
│ └── ...
|
||||
├── Classes/
|
||||
├── Configuration/
|
||||
├── composer.json
|
||||
└── ext_emconf.php
|
||||
```
|
||||
|
||||
Ein Content Block = ein Ordner. Name = Ordnername (kleingeschrieben, mit Bindestrichen).
|
||||
|
||||
---
|
||||
|
||||
## 2. Erster Content Block: VITEC Hero Section
|
||||
|
||||
Nachgebaut nach einem typischen Template aus deinen Figma-Wireframes: Eyebrow + Heading + Subline + Body + CTA + Hero-Image + Background-Variant.
|
||||
|
||||
### 2.1 `config.yaml`
|
||||
|
||||
**Datei:** `packages/vitec/ContentBlocks/ContentElements/hero-section/config.yaml`
|
||||
|
||||
```yaml
|
||||
name: vitec/hero-section
|
||||
group: vitec
|
||||
prefixFields: true
|
||||
prefixType: full
|
||||
|
||||
fields:
|
||||
- identifier: eyebrow
|
||||
type: Text
|
||||
max: 50
|
||||
|
||||
- identifier: header
|
||||
useExistingField: true
|
||||
required: true
|
||||
|
||||
- identifier: subheader
|
||||
useExistingField: true
|
||||
|
||||
- identifier: bodytext
|
||||
useExistingField: true
|
||||
enableRichtext: true
|
||||
|
||||
- identifier: cta
|
||||
type: Link
|
||||
allowedTypes:
|
||||
- page
|
||||
- url
|
||||
- file
|
||||
- email
|
||||
|
||||
- identifier: cta_label
|
||||
type: Text
|
||||
default: 'Learn more'
|
||||
max: 30
|
||||
|
||||
- identifier: hero_image
|
||||
type: File
|
||||
minitems: 0
|
||||
maxitems: 1
|
||||
allowed: common-image-types
|
||||
extendedPalette: true
|
||||
|
||||
- identifier: background_variant
|
||||
type: Select
|
||||
renderType: selectSingle
|
||||
default: none
|
||||
items:
|
||||
- label: None
|
||||
value: none
|
||||
- label: Orange
|
||||
value: orange
|
||||
- label: Blue
|
||||
value: blue
|
||||
- label: Graphite
|
||||
value: graphite
|
||||
- label: Midnight
|
||||
value: midnight
|
||||
|
||||
- identifier: show_logo_wall
|
||||
type: Checkbox
|
||||
default: 0
|
||||
```
|
||||
|
||||
**Was passiert hier:**
|
||||
|
||||
- `name: vitec/hero-section` → TCA-Typ `vitec_hero_section`, Tabelle `tt_content`
|
||||
- `group: vitec` → eigene Sektion im CE-Wizard (muss noch registriert werden — siehe 2.5)
|
||||
- `useExistingField: true` → recycled TYPO3-Core-Felder (`header`, `subheader`, `bodytext`). Keine neuen DB-Spalten, konsistente Bedeutung
|
||||
- `prefixFields: true` + `prefixType: full` → neue Felder bekommen `tx_vitec_hero_section_*` als DB-Prefix (vermeidet Kollisionen)
|
||||
- **Keine TCA-Override-Datei nötig** — Content Blocks generiert das TCA automatisch
|
||||
|
||||
### 2.2 `language/labels.xlf`
|
||||
|
||||
Content Blocks erwartet XLF-Files nach einer festen Namens-Konvention. Jedes Feld bekommt automatisch einen Key `<vendor>.<element>.<field>.label`.
|
||||
|
||||
**Datei:** `packages/vitec/ContentBlocks/ContentElements/hero-section/language/labels.xlf`
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xliff version="1.2">
|
||||
<file source-language="en" datatype="plaintext" original="messages">
|
||||
<body>
|
||||
<!-- Element-Labels -->
|
||||
<trans-unit id="title">
|
||||
<source>VITEC · Hero Section</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="description">
|
||||
<source>Haupt-Hero mit Headline, CTA, Background-Variante</source>
|
||||
</trans-unit>
|
||||
|
||||
<!-- Field-Labels -->
|
||||
<trans-unit id="eyebrow.label">
|
||||
<source>Eyebrow Text</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="eyebrow.description">
|
||||
<source>Kleiner Label-Text über der Headline</source>
|
||||
</trans-unit>
|
||||
|
||||
<trans-unit id="cta.label">
|
||||
<source>CTA Link</source>
|
||||
</trans-unit>
|
||||
|
||||
<trans-unit id="cta_label.label">
|
||||
<source>CTA Button Text</source>
|
||||
</trans-unit>
|
||||
|
||||
<trans-unit id="hero_image.label">
|
||||
<source>Hero Image</source>
|
||||
</trans-unit>
|
||||
|
||||
<trans-unit id="background_variant.label">
|
||||
<source>Background Variant</source>
|
||||
</trans-unit>
|
||||
|
||||
<trans-unit id="show_logo_wall.label">
|
||||
<source>Show Logo Wall below</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
```
|
||||
|
||||
> Die Core-Felder (`header`, `subheader`, `bodytext`) brauchen keine Labels — sie erben die vom TYPO3-Core.
|
||||
|
||||
### 2.3 `assets/icon.svg`
|
||||
|
||||
Content Blocks erkennt Icons automatisch, wenn sie unter `assets/icon.svg` (oder `icon.png`) liegen.
|
||||
|
||||
**Datei:** `packages/vitec/ContentBlocks/ContentElements/hero-section/assets/icon.svg`
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#F47937" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="3" width="18" height="18" rx="2"/>
|
||||
<path d="M3 9h18"/>
|
||||
<circle cx="8" cy="15" r="2"/>
|
||||
<path d="M13 15h5M13 18h3"/>
|
||||
</svg>
|
||||
```
|
||||
|
||||
Platzhalter — tausch später gegen die echten VITEC-Icons aus.
|
||||
|
||||
### 2.4 `templates/EditorPreview.html` (optional aber empfohlen)
|
||||
|
||||
Im **Headless-Mode** wird kein Frontend-Template gerendert. Aber für die Redakteure ist eine Backend-Preview sinnvoll, damit sie im Seiten-Modul sehen, was sie gerade anlegen.
|
||||
|
||||
**Datei:** `packages/vitec/ContentBlocks/ContentElements/hero-section/templates/EditorPreview.html`
|
||||
|
||||
```html
|
||||
<div style="padding: 1rem; border-left: 4px solid #F47937; background: #f8f8f8;">
|
||||
<div style="font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.1em; color: #666;">
|
||||
VITEC · Hero Section — {data.background_variant}
|
||||
</div>
|
||||
<f:if condition="{data.eyebrow}">
|
||||
<div style="font-size: 0.75rem; color: #F47937; margin-top: 0.5rem;">{data.eyebrow}</div>
|
||||
</f:if>
|
||||
<h3 style="margin: 0.25rem 0;">{data.header}</h3>
|
||||
<f:if condition="{data.subheader}">
|
||||
<div style="color: #555;">{data.subheader}</div>
|
||||
</f:if>
|
||||
<f:if condition="{data.cta_label}">
|
||||
<div style="margin-top: 0.5rem;">
|
||||
<span style="display: inline-block; padding: 0.25rem 0.75rem; background: #F47937; color: white; border-radius: 3px; font-size: 0.8rem;">
|
||||
{data.cta_label} →
|
||||
</span>
|
||||
</div>
|
||||
</f:if>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 2.5 Backend-Gruppe "VITEC" registrieren
|
||||
|
||||
Damit `group: vitec` aus der YAML eine saubere Sektion im CE-Wizard wird, muss die Gruppe einmal registriert sein:
|
||||
|
||||
**Datei:** `packages/vitec/Configuration/page.tsconfig` (deine existierende Datei — aktuell leer)
|
||||
|
||||
```tsconfig
|
||||
mod.wizards.newContentElement.wizardItems.vitec {
|
||||
header = VITEC
|
||||
show = *
|
||||
elements {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Das reicht — Content Blocks hängt die einzelnen Elemente dann automatisch unter `elements` ein.
|
||||
|
||||
---
|
||||
|
||||
## 3. Installation & Test
|
||||
|
||||
### 3.1 Caches und TCA flushen
|
||||
|
||||
Nach jeder Content-Block-Änderung:
|
||||
|
||||
```bash
|
||||
vendor/bin/typo3 cache:flush
|
||||
```
|
||||
|
||||
Oder im Backend: Admin Tools → Maintenance → Flush all caches.
|
||||
|
||||
### 3.2 Datenbank-Schema updaten
|
||||
|
||||
Content Blocks erstellt automatisch neue Spalten (z.B. `tx_vitec_hero_section_eyebrow`, `tx_vitec_hero_section_background_variant` etc.):
|
||||
|
||||
```bash
|
||||
vendor/bin/typo3 database:updateschema
|
||||
```
|
||||
|
||||
Oder Backend: Admin Tools → Maintenance → Analyze Database Structure → Run.
|
||||
|
||||
### 3.3 Im Backend anlegen
|
||||
|
||||
1. Seite im Seitenbaum öffnen → Page-Modul
|
||||
2. "Neues Inhaltselement" → Tab **VITEC** → "VITEC · Hero Section"
|
||||
3. Felder ausfüllen (Eyebrow, Heading, CTA, Image, Background-Variant "orange")
|
||||
4. Speichern
|
||||
|
||||
### 3.4 JSON prüfen
|
||||
|
||||
```bash
|
||||
curl -s https://dev.vitec.com/testseite | jq '.content.colPos0[] | select(.type == "vitec_hero_section")'
|
||||
```
|
||||
|
||||
**Erwarteter JSON-Output** (durch `nb-headless-content-blocks` automatisch erzeugt):
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 42,
|
||||
"type": "vitec_hero_section",
|
||||
"colPos": 0,
|
||||
"categories": "",
|
||||
"appearance": {
|
||||
"layout": "default",
|
||||
"frameClass": "default",
|
||||
"spaceBefore": "",
|
||||
"spaceAfter": ""
|
||||
},
|
||||
"content": {
|
||||
"header": "Enterprise Video Solutions",
|
||||
"subheader": "Reliable. Scalable. Proven.",
|
||||
"bodytext": "<p>VITEC delivers mission-critical video...</p>",
|
||||
"tx_vitec_hero_section_eyebrow": "Why VITEC",
|
||||
"tx_vitec_hero_section_cta": {
|
||||
"href": "/success-stories",
|
||||
"target": null,
|
||||
"class": null,
|
||||
"title": null,
|
||||
"linkText": "t3://page?uid=15",
|
||||
"additionalAttributes": []
|
||||
},
|
||||
"tx_vitec_hero_section_cta_label": "Learn more",
|
||||
"tx_vitec_hero_section_hero_image": [
|
||||
{
|
||||
"publicUrl": "https://dev.vitec.com/fileadmin/.../hero.png",
|
||||
"properties": { ... }
|
||||
}
|
||||
],
|
||||
"tx_vitec_hero_section_background_variant": "orange",
|
||||
"tx_vitec_hero_section_show_logo_wall": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Struktur passt zu deinem existierenden `textpic`-Pattern — `content.*` mit allen Feldern nebeneinander. ✅
|
||||
|
||||
---
|
||||
|
||||
## 4. JSON-Schema aufräumen (Field-Namen kürzen)
|
||||
|
||||
Du hast sicher gemerkt: die Feldnamen im JSON sind lang (`tx_vitec_hero_section_eyebrow`). Das kommt vom `prefixFields: true` — nötig für DB-Konsistenz, aber unschön fürs Frontend.
|
||||
|
||||
**Lösung:** Via `nb-headless-content-blocks` EventListener die Keys umbenennen.
|
||||
|
||||
### 4.1 EventListener anlegen
|
||||
|
||||
**Datei:** `packages/vitec/Classes/EventListener/NormalizeContentBlockKeys.php`
|
||||
|
||||
```php
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Evomedien\Vitec\EventListener;
|
||||
|
||||
use Netzbewegung\NbHeadlessContentBlocks\Event\ModifyArrayRecursiveToArrayEvent;
|
||||
use TYPO3\CMS\Core\Attribute\AsEventListener;
|
||||
|
||||
#[AsEventListener(identifier: 'vitec/normalize-content-block-keys')]
|
||||
final class NormalizeContentBlockKeys
|
||||
{
|
||||
public function __invoke(ModifyArrayRecursiveToArrayEvent $event): void
|
||||
{
|
||||
$key = $event->getKey();
|
||||
|
||||
// Strip prefix "tx_vitec_<element>_" from field names
|
||||
// e.g. "tx_vitec_hero_section_eyebrow" → "eyebrow"
|
||||
if (preg_match('/^tx_vitec_[a-z_]+?_([a-z_]+)$/', $key, $matches)) {
|
||||
$event->setKey($matches[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 Services.yaml
|
||||
|
||||
**Datei:** `packages/vitec/Configuration/Services.yaml` (anlegen falls nicht vorhanden)
|
||||
|
||||
```yaml
|
||||
services:
|
||||
_defaults:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
public: false
|
||||
|
||||
Evomedien\Vitec\:
|
||||
resource: '../Classes/*'
|
||||
exclude: '../Classes/Domain/Model/*'
|
||||
```
|
||||
|
||||
> `AsEventListener` Attribute + autoconfigure = Event-Listener wird automatisch registriert. Keine weitere Konfiguration nötig.
|
||||
|
||||
### 4.3 Resultat nach Cache-Flush
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "vitec_hero_section",
|
||||
"content": {
|
||||
"header": "Enterprise Video Solutions",
|
||||
"eyebrow": "Why VITEC",
|
||||
"cta": { ... },
|
||||
"cta_label": "Learn more",
|
||||
"hero_image": [ ... ],
|
||||
"background_variant": "orange",
|
||||
"show_logo_wall": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Saubere, lesbare Keys — React-Kollege glücklich.
|
||||
|
||||
---
|
||||
|
||||
## 5. Pattern für weitere Content Blocks
|
||||
|
||||
Für jeden neuen Content Block brauchst du:
|
||||
|
||||
```
|
||||
packages/vitec/ContentBlocks/ContentElements/<name>/
|
||||
├── config.yaml ← Felder definieren
|
||||
├── language/labels.xlf ← Labels übersetzen
|
||||
├── assets/icon.svg ← Icon
|
||||
└── templates/EditorPreview.html ← optional
|
||||
```
|
||||
|
||||
Dann:
|
||||
```bash
|
||||
vendor/bin/typo3 database:updateschema
|
||||
vendor/bin/typo3 cache:flush
|
||||
```
|
||||
|
||||
Fertig. Keine PHP-Boilerplate, keine TypoScript-Overrides, kein TCA-Gefummel.
|
||||
|
||||
### Template-Vorschlag für deine 20 Figma-Templates
|
||||
|
||||
Nummerierung/Naming-Vorschlag an den Figma-Templates entlang:
|
||||
|
||||
| # | Name | Content Block |
|
||||
|---|---|---|
|
||||
| 01 | Hero | `vitec/hero-section` |
|
||||
| 02 | Feature-Teaser Grid | `vitec/feature-teaser-grid` |
|
||||
| 03 | CTA Banner | `vitec/cta-banner` |
|
||||
| 04 | Quote / Testimonial | `vitec/testimonial` |
|
||||
| 05 | Logo Wall | `vitec/logo-wall` |
|
||||
| 06 | Product Card Grid | `vitec/product-card-grid` |
|
||||
| ... | ... | ... |
|
||||
| 16 | Content Page V1 | `vitec/content-page-v1` |
|
||||
|
||||
Wenn du einen Block gebaut hast, ist jeder weitere 10-20 Minuten Arbeit.
|
||||
|
||||
---
|
||||
|
||||
## 6. Wann brauchst du trotzdem `b13/container`?
|
||||
|
||||
**Antwort:** Für echte Layout-Wrapper mit nested Content Elements. Beispiele:
|
||||
|
||||
- **2-Spalten-Section:** Ein Container, in dessen linker Spalte ein `hero-section` + rechts ein `testimonial` liegt
|
||||
- **Tabs / Accordion:** ein Tab-Container mit mehreren Content Blocks je Tab
|
||||
- **Grid mit freier CE-Wahl:** 3-column-grid, wo der Redakteur pro Spalte frei wählt
|
||||
|
||||
Für diese Fälle:
|
||||
|
||||
1. `b13/container` Container registrieren (wie in der vorherigen Anleitung beschrieben, per PHP TCA-Override)
|
||||
2. `itplusx/headless-container` mappt ihn automatisch ins JSON
|
||||
3. Die Kinder sind dann Content Blocks → das Pattern spielt sauber zusammen
|
||||
|
||||
Laut Doku von `nb-headless-content-blocks`: **"Support for EXT:container"** ist eingebaut — die zwei Extensions beißen sich nicht.
|
||||
|
||||
---
|
||||
|
||||
## 7. Advanced: Sammlungen (Collections)
|
||||
|
||||
Für wiederkehrende Items (z.B. 3 Teaser-Cards in einem Grid) gibt es den `Collection`-Type:
|
||||
|
||||
```yaml
|
||||
name: vitec/feature-teaser-grid
|
||||
group: vitec
|
||||
fields:
|
||||
- identifier: header
|
||||
useExistingField: true
|
||||
|
||||
- identifier: teasers
|
||||
type: Collection
|
||||
minitems: 1
|
||||
maxitems: 6
|
||||
fields:
|
||||
- identifier: icon
|
||||
type: File
|
||||
maxitems: 1
|
||||
allowed: common-image-types
|
||||
- identifier: title
|
||||
type: Text
|
||||
required: true
|
||||
- identifier: description
|
||||
type: Textarea
|
||||
- identifier: link
|
||||
type: Link
|
||||
```
|
||||
|
||||
Im JSON kommt das dann als Array raus:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "vitec_feature_teaser_grid",
|
||||
"content": {
|
||||
"header": "Our Solutions",
|
||||
"teasers": [
|
||||
{ "title": "...", "description": "...", "icon": [...], "link": {...} },
|
||||
{ "title": "...", "description": "...", "icon": [...], "link": {...} }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Cheatsheet: Field-Types
|
||||
|
||||
| YAML `type` | Zweck | JSON-Output-Typ |
|
||||
|---|---|---|
|
||||
| `Text` | Einzeiliger Text | string |
|
||||
| `Textarea` | Mehrzeilig; mit `enableRichtext: true` → RTE | string (HTML bei RTE) |
|
||||
| `Number` | int/float | number |
|
||||
| `Checkbox` | Boolean | boolean |
|
||||
| `Select` `renderType: selectSingle` | Dropdown | string (value) |
|
||||
| `Select` `renderType: selectMultipleSideBySide` | Multi-Select | string (comma-sep) |
|
||||
| `Radio` | Radio-Button-Gruppe | string |
|
||||
| `Link` | TYPO3-Link (Page/URL/File/Email) | object (`href`, `target`, `linkText`…) |
|
||||
| `File` | File-Reference | array of file-objects |
|
||||
| `Color` | Color-Picker | string (hex) |
|
||||
| `DateTime` | Datum/Zeit | string (ISO) |
|
||||
| `Collection` | Wiederholbare Feldgruppen | array of objects |
|
||||
| `Category` | TYPO3-Kategorien | array |
|
||||
| `Relation` | Referenz zu anderen Records | array |
|
||||
|
||||
---
|
||||
|
||||
## 9. Fehlerbild-Cheatsheet
|
||||
|
||||
| Symptom | Ursache | Fix |
|
||||
|---|---|---|
|
||||
| Content Block erscheint nicht im CE-Wizard | Cache oder Gruppe nicht registriert | `cache:flush`, dann Backend-User-Session refresh |
|
||||
| Spalten fehlen in DB (`column not found`) | `database:updateschema` nicht ausgeführt | `vendor/bin/typo3 database:updateschema` |
|
||||
| Feld-Label bleibt englisch/identifier | XLF-Key-Konvention falsch | Key muss exakt `<identifier>.label` heißen (ohne Vendor-Prefix) |
|
||||
| JSON enthält veraltete Struktur | `nb-headless-content-blocks` nicht geladen oder Site-Set greift nicht | TypoScript-Analyzer prüfen |
|
||||
| EventListener greift nicht | `Services.yaml` nicht geladen oder `autoconfigure: false` | Services.yaml prüfen, Cache flush |
|
||||
| Icon wird nicht angezeigt | falsche Position oder SVG-Fehler | Pfad muss `assets/icon.svg` relativ zum CB-Ordner sein |
|
||||
| "Type does not exist" nach Rename | TCA-Cache veraltet | `cache:flush --group=system` |
|
||||
|
||||
---
|
||||
|
||||
## 10. Quickstart
|
||||
|
||||
```bash
|
||||
# 1. Aufräumen (einmalig)
|
||||
# - nb-headless-content-blocks ins Site Set migrieren
|
||||
# - Version in ext_emconf.php / composer.json angleichen
|
||||
|
||||
# 2. Ordnerstruktur für ersten Block
|
||||
mkdir -p packages/vitec/ContentBlocks/ContentElements/hero-section/{assets,language,templates}
|
||||
|
||||
# 3. Files anlegen:
|
||||
# - config.yaml
|
||||
# - language/labels.xlf
|
||||
# - assets/icon.svg
|
||||
# - templates/EditorPreview.html (optional)
|
||||
|
||||
# 4. DB + Cache
|
||||
vendor/bin/typo3 database:updateschema
|
||||
vendor/bin/typo3 cache:flush
|
||||
|
||||
# 5. Backend: CE anlegen, speichern
|
||||
|
||||
# 6. Test
|
||||
curl -s https://dev.vitec.com/testseite | jq '.content.colPos0'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Nächste Schritte
|
||||
|
||||
Nachdem der erste Content Block läuft:
|
||||
|
||||
1. **EventListener** für saubere Keys einbauen (Schritt 4)
|
||||
2. Die 20 Templates aus Figma durchgehen → pro Template ein Content Block
|
||||
3. Wenn Layouts mit nested CEs gebraucht werden → `b13/container` dazupacken
|
||||
4. **Custom Records** (`tx_vitec_market`, `_solution`, `_product`, `_story`) — Content Blocks kann auch Record Types. Siehe YAML reference → RecordTypes
|
||||
5. **m:n Relationen** zwischen Records — via `Relation`-Field-Type (mit `allowed` und `maxitems`)
|
||||
|
||||
Sobald der Hero-Section-Block JSON liefert, melden — dann bauen wir zusammen den ersten Record Type (`tx_vitec_market`) und die bidirektionalen Relationen.
|
||||
|
||||
---
|
||||
|
||||
## Referenzen
|
||||
|
||||
- **Content Blocks:** https://docs.typo3.org/p/friendsoftypo3/content-blocks/main/en-us/
|
||||
- **Field Types:** https://docs.typo3.org/p/friendsoftypo3/content-blocks/main/en-us/YamlReference/FieldTypes/Index.html
|
||||
- **nb-headless-content-blocks:** https://github.com/Netzbewegung-Backend/nb_headless_content_blocks
|
||||
- **Headless Docs:** https://docs.typo3.org/p/friendsoftypo3/headless/main/en-us/
|
||||
- **Beispiel-Repo (Content Blocks):** https://github.com/friendsoftypo3/content-blocks/tree/main/Build/content_blocks_examples
|
||||
Reference in New Issue
Block a user