Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    dirnbauer

    typo3-content-blocks

    dirnbauer/typo3-content-blocks
    Design
    5
    2 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Expert guidance on creating Content Elements, Record Types, Page Types, and File Types using TYPO3 Content Blocks extension - the single source of truth for content modeling.

    SKILL.md

    TYPO3 Content Blocks Development

    Compatibility: This skill targets TYPO3 v14.x with Content Blocks 2.x. Always match the Packagist friendsoftypo3/content-blocks constraint to your Core version. For Content Blocks 1.x on TYPO3 v13, upstream requires TYPO3 ≥ 13.4 (typo3/cms-core: ^13.4) — confirm on Packagist. Examples use TYPO3 v14 APIs and CB 2.x; adjust composer.json if upstream constraints differ.

    TYPO3 API First: Always use TYPO3's built-in APIs, core features, and established conventions before creating custom implementations. Do not reinvent what TYPO3 already provides. Always verify that the APIs and methods you use exist and are not deprecated in TYPO3 v14 by checking the official TYPO3 documentation.

    1. The Single Source of Truth Principle

    Content Blocks is the modern approach to creating custom content types in TYPO3. It eliminates redundancy by providing a single YAML configuration that generates:

    • TCA (Table Configuration Array)
    • Database schema (SQL)
    • TypoScript rendering
    • Backend forms and previews
    • Labels and translations

    Why Content Blocks?

    Traditional Approach Content Blocks Approach
    Multiple TCA files One config.yaml
    Manual SQL definitions Auto-generated schema
    Separate TypoScript Auto-registered rendering
    Scattered translations Single labels.xlf
    Complex setup Simple folder structure

    2. Installation

    # Install via Composer (DDEV recommended)
    ddev composer require friendsoftypo3/content-blocks
    
    # After installation, clear caches
    ddev typo3 cache:flush
    

    Version constraint: Content Blocks 1.x requires TYPO3 ≥ 13.4 (typo3/cms-core: ^13.4 in the package). TYPO3 13.1–13.3 do not satisfy that Composer constraint.

    Security Configuration (Classic Mode)

    For non-composer installations, deny web access to ContentBlocks folder:

    # .htaccess addition
    RewriteRule (?:typo3conf/ext|typo3/sysext|typo3/ext)/[^/]+/(?:Configuration|ContentBlocks|Resources/Private|Tests?|Documentation|docs?)/ - [F]
    

    3. Content Types Overview

    Content Blocks supports four content types:

    Type Folder Table Use Case
    ContentElements ContentBlocks/ContentElements/ tt_content Frontend content (hero, accordion, CTA)
    RecordTypes ContentBlocks/RecordTypes/ Custom/existing Structured records (news, products, team)
    PageTypes ContentBlocks/PageTypes/ pages Custom page types (blog, landing page)
    FileTypes ContentBlocks/FileTypes/ sys_file_reference Extended file references (photographer, copyright)

    4. Folder Structure

    EXT:my_sitepackage/
    └── ContentBlocks/
        ├── ContentElements/
        │   └── my-hero/
        │       ├── assets/
        │       │   └── icon.svg
        │       ├── language/
        │       │   └── labels.xlf
        │       ├── templates/
        │       │   ├── backend-preview.fluid.html
        │       │   ├── frontend.fluid.html
        │       │   └── partials/
        │       └── config.yaml
        ├── RecordTypes/
        │   └── my-record/
        │       ├── assets/
        │       │   └── icon.svg
        │       ├── language/
        │       │   └── labels.xlf
        │       └── config.yaml
        ├── PageTypes/
        │   └── blog-article/
        │       ├── assets/
        │       │   ├── icon.svg
        │       │   ├── icon-hide-in-menu.svg
        │       │   └── icon-root.svg
        │       ├── language/
        │       │   └── labels.xlf
        │       ├── templates/
        │       │   └── backend-preview.fluid.html
        │       └── config.yaml
        └── FileTypes/
            └── image-extended/
                ├── language/
                │   └── labels.xlf
                └── config.yaml
    

    5. Creating Content Elements

    Kickstart Command (Recommended)

    # Interactive mode
    ddev typo3 make:content-block
    
    # One-liner
    ddev typo3 make:content-block \
      --content-type="content-element" \
      --vendor="myvendor" \
      --name="hero-banner" \
      --title="Hero Banner" \
      --extension="my_sitepackage"
    
    # After creation, update database
    ddev typo3 cache:flush -g system
    ddev typo3 extension:setup --extension=my_sitepackage
    

    Predefined Basics (content elements)

    List under basics: to pull in Core field groups: TYPO3/Header, TYPO3/Appearance, TYPO3/Links, TYPO3/Categories. See the Content Blocks basics reference.

    Minimal Content Element

    # EXT:my_sitepackage/ContentBlocks/ContentElements/hero-banner/config.yaml
    name: myvendor/hero-banner
    fields:
      - identifier: header
        useExistingField: true
      - identifier: bodytext
        useExistingField: true
    

    Full Content Element Example

    # EXT:my_sitepackage/ContentBlocks/ContentElements/hero-banner/config.yaml
    name: myvendor/hero-banner
    group: default
    description: "A full-width hero banner with image and CTA"
    prefixFields: true
    prefixType: full
    basics:
      - TYPO3/Appearance
      - TYPO3/Links
    fields:
      - identifier: header
        useExistingField: true
      - identifier: subheadline
        type: Text
        label: Subheadline
      - identifier: hero_image
        type: File
        minitems: 1
        maxitems: 1
        allowed: common-image-types
      - identifier: cta_link
        type: Link
        label: Call to Action Link
      - identifier: cta_text
        type: Text
        label: Button Text
    

    Frontend Template

    <!-- templates/frontend.fluid.html -->
    <html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
          xmlns:cb="http://typo3.org/ns/TYPO3/CMS/ContentBlocks/ViewHelpers"
          data-namespace-typo3-fluid="true">
    
    <f:asset.css identifier="hero-banner-css" href="{cb:assetPath()}/frontend.css"/>
    
    <section class="hero-banner">
        <f:if condition="{data.hero_image}">
            <f:for each="{data.hero_image}" as="image">
                <f:image image="{image}" alt="{data.header}" class="hero-image"/>
            </f:for>
        </f:if>
        
        <div class="hero-content">
            <h1>{data.header}</h1>
            <f:if condition="{data.subheadline}">
                <p class="subheadline">{data.subheadline}</p>
            </f:if>
            
            <f:if condition="{data.cta_link}">
                <f:link.typolink parameter="{data.cta_link}" class="btn btn-primary">
                    {data.cta_text -> f:or(default: 'Learn more')}
                </f:link.typolink>
            </f:if>
        </div>
    </section>
    </html>
    

    Backend Preview Template

    <!-- templates/backend-preview.fluid.html -->
    <html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
          xmlns:be="http://typo3.org/ns/TYPO3/CMS/Backend/ViewHelpers"
          data-namespace-typo3-fluid="true">
    
    <div class="content-block-preview">
        <strong>{data.header}</strong>
        <f:if condition="{data.subheadline}">
            <br/><em>{data.subheadline}</em>
        </f:if>
        <f:if condition="{data.hero_image}">
            <f:for each="{data.hero_image}" as="image">
                <be:thumbnail image="{image}" width="100" height="100"/>
            </f:for>
        </f:if>
    </div>
    </html>
    

    6. Creating Record Types (Custom Tables)

    Record Types create custom database tables for structured data like teams, products, events, etc.

    Extbase-Compatible Table Naming

    IMPORTANT: For Extbase compatibility, use the tx_extensionkey_domain_model_* naming convention:

    # ✅ CORRECT - Extbase compatible table name
    name: myvendor/team-member
    table: tx_mysitepackage_domain_model_teammember
    labelField: name
    fields:
      - identifier: name
        type: Text
      - identifier: position
        type: Text
      - identifier: email
        type: Email
      - identifier: photo
        type: File
        allowed: common-image-types
        maxitems: 1
    
    # ❌ WRONG - Short table names don't work with Extbase
    name: myvendor/team-member
    table: team_member  # Won't work with Extbase!
    

    Minimal Record Type

    # EXT:my_sitepackage/ContentBlocks/RecordTypes/team-member/config.yaml
    name: myvendor/team-member
    table: tx_mysitepackage_domain_model_teammember
    labelField: name
    fields:
      - identifier: name
        type: Text
    

    Full Record Type Example

    # EXT:my_sitepackage/ContentBlocks/RecordTypes/team-member/config.yaml
    name: myvendor/team-member
    table: tx_mysitepackage_domain_model_teammember
    labelField: name
    fallbackLabelFields:
      - email
    languageAware: true
    workspaceAware: true
    sortable: true
    softDelete: true
    trackCreationDate: true
    trackUpdateDate: true
    internalDescription: true
    restriction:
      disabled: true
      startTime: true
      endTime: true
      userGroup: true  # fe_group visibility fields when applicable
    security:
      ignorePageTypeRestriction: true  # Allow on normal pages
    fields:
      - identifier: name
        type: Text
        required: true
      - identifier: position
        type: Text
      - identifier: email
        type: Email
      - identifier: phone
        type: Text
      - identifier: bio
        type: Textarea
        enableRichtext: true
      - identifier: photo
        type: File
        allowed: common-image-types
        maxitems: 1
      - identifier: social_links
        type: Collection
        labelField: platform
        fields:
          - identifier: platform
            type: Select
            renderType: selectSingle
            items:
              - label: LinkedIn
                value: linkedin
              - label: Twitter/X
                value: twitter
              - label: GitHub
                value: github
          - identifier: url
            type: Link
    

    Record Type options (reference)

    Content Blocks exposes many optional root keys on record types — always confirm names against the current Record Types YAML reference. Commonly used flags include:

    Option Role
    editLocking Editor locking behaviour
    sortField / sortable Manual sorting (sorting column)
    rootLevelType Allow records at PID 0
    readOnly Read-only in FormEngine
    adminOnly Visible to admins only
    hideAtCopy / appendLabelAtCopy Copy behaviour
    group Backend selector grouping

    Multi-Type Records (Single Table Inheritance)

    Create multiple types for one table:

    # EXT:my_sitepackage/ContentBlocks/RecordTypes/person-employee/config.yaml
    name: myvendor/person-employee
    table: tx_mysitepackage_domain_model_person
    typeField: person_type
    typeName: employee
    priority: 0  # Integer ordering; higher values load first (higher priority)
    labelField: name
    languageAware: false
    workspaceAware: false
    fields:
      - identifier: name
        type: Text
      - identifier: department
        type: Text
    
    # EXT:my_sitepackage/ContentBlocks/RecordTypes/person-contractor/config.yaml
    name: myvendor/person-contractor
    table: tx_mysitepackage_domain_model_person
    typeName: contractor
    fields:
      - identifier: name
        type: Text
      - identifier: company
        type: Text
      - identifier: contract_end
        type: DateTime
    

    Record Types as Collection Children

    Define a record that can be used in IRRE collections:

    # EXT:my_sitepackage/ContentBlocks/RecordTypes/slide/config.yaml
    name: myvendor/slide
    table: tx_mysitepackage_domain_model_slide
    labelField: title
    fields:
      - identifier: title
        type: Text
      - identifier: image
        type: File
        maxitems: 1
      - identifier: link
        type: Link
    
    # EXT:my_sitepackage/ContentBlocks/ContentElements/slider/config.yaml
    name: myvendor/slider
    fields:
      - identifier: slides
        type: Collection
        foreign_table: tx_mysitepackage_domain_model_slide
        shareAcrossTables: true
        shareAcrossFields: true
        minitems: 1
    

    7. Creating Page Types (Custom doktypes)

    Page Types extend the pages table with custom page types – ideal for blog articles, landing pages, news pages, or other page variants with special properties.

    When to Use Page Types

    Use Case Example
    Structured page properties Blog with author, teaser image, publish date
    Plugin integration News lists, event calendars reading page properties
    Different page behavior Landing pages without navigation
    SEO-specific fields Custom meta fields per page type

    Minimal Page Type

    # EXT:my_sitepackage/ContentBlocks/PageTypes/blog-article/config.yaml
    name: myvendor/blog-article
    typeName: 1705234567
    fields:
      - identifier: author_name
        type: Text
    

    Full Page Type Example

    # EXT:my_sitepackage/ContentBlocks/PageTypes/blog-article/config.yaml
    name: myvendor/blog-article
    typeName: 1705234567   # Unix timestamp (unique identifier)
    group: default         # Options: default, link, special
    fields:
      - identifier: author_name
        type: Text
        label: Author
        required: true
      - identifier: teaser_text
        type: Textarea
        label: Teaser
      - identifier: hero_image
        type: File
        allowed: common-image-types
        maxitems: 1
      - identifier: publish_date
        type: DateTime
        label: Publish Date
      - identifier: reading_time
        type: Number
        label: Reading Time (minutes)
    

    Page Type Options

    Option Type Required Description
    typeName integer ✓ Unique doktype number (use Unix timestamp)
    group string Group in selector: default, link, special
    allowedRecordTypes array Record types allowed on this doktype (default includes pages, sys_category, sys_file_reference, sys_file_collection; * wildcard possible — see official Page Types API)

    Reserved typeName values: 199, 254 (cannot be used)

    Icons for Page States

    Page Types support state-specific icons. Add these to your assets folder:

    ContentBlocks/PageTypes/blog-article/
    ├── assets/
    │   ├── icon.svg              # Default icon
    │   ├── icon-hide-in-menu.svg # Hidden in menu state
    │   └── icon-root.svg         # Site root state
    └── config.yaml
    

    Backend Preview

    Create a backend-preview.fluid.html to preview custom page properties:

    <!-- templates/backend-preview.fluid.html -->
    <html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
          xmlns:be="http://typo3.org/ns/TYPO3/CMS/Backend/ViewHelpers"
          data-namespace-typo3-fluid="true">
    
    <div class="card card-size-medium">
        <div class="card-body">
            <be:link.editRecord uid="{data.uid}" table="{data.mainType}" fields="author_name">
                <strong>Author:</strong> {data.author_name}
            </be:link.editRecord>
            <f:if condition="{data.publish_date}">
                <br/><small>Published: <f:format.date format="d.m.Y">{data.publish_date}</f:format.date></small>
            </f:if>
        </div>
    </div>
    </html>
    

    Frontend Integration

    Page Types have no automatic frontend rendering. Add the ContentBlocksDataProcessor to your TypoScript:

    # Configuration/TypoScript/setup.typoscript
    page = PAGE
    page {
        10 = FLUIDTEMPLATE
        10 {
            templateName = Default
            templateRootPaths.10 = EXT:my_sitepackage/Resources/Private/Templates/
            
            dataProcessing {
                # Process Content Blocks page data
                1 = content-blocks
            }
        }
    }
    

    Then access fields in your Fluid template:

    <!-- Resources/Private/Templates/Default.html -->
    <f:if condition="{data.author_name}">
        <p class="author">By {data.author_name}</p>
    </f:if>
    
    <f:if condition="{data.hero_image}">
        <f:for each="{data.hero_image}" as="image">
            <f:image image="{image}" class="hero-image"/>
        </f:for>
    </f:if>
    

    Remove from Page Tree Drag Area

    To hide your page type from the "Create new page" drag area:

    # Configuration/user.tsconfig
    options {
        pageTree {
            doktypesToShowInNewPageDragArea := removeFromList(1705234567)
        }
    }
    

    8. Creating File Types (Extended Metadata)

    New in version 1.2

    File Types extend the sys_file_reference table with custom fields – perfect for photographer credits, copyright notices, or additional reference-level options.

    Available File Type Names

    typeName File Types
    image JPEG, PNG, GIF, WebP, SVG
    video MP4, WebM, OGG
    audio MP3, WAV, OGG
    text TXT, PDF, Markdown
    application ZIP, Office formats

    Minimal File Type

    # EXT:my_sitepackage/ContentBlocks/FileTypes/image-extended/config.yaml
    name: myvendor/image-extended
    typeName: image
    fields:
      - identifier: photographer
        type: Text
        label: Photographer
    

    Full File Type Example

    # EXT:my_sitepackage/ContentBlocks/FileTypes/image-extended/config.yaml
    name: myvendor/image-extended
    typeName: image
    prefixFields: false  # Keep original column names
    fields:
      - identifier: image_overlay_palette
        type: Palette
        label: 'LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette'
        fields:
          # Reuse existing TYPO3 core fields
          - identifier: alternative
            useExistingField: true
          - identifier: description
            useExistingField: true
          - type: Linebreak
          - identifier: link
            useExistingField: true
          - identifier: title
            useExistingField: true
          - type: Linebreak
          # Custom fields
          - identifier: photographer
            type: Text
            label: Photographer
          - identifier: copyright
            type: Text
            label: Copyright Notice
          - identifier: source_url
            type: Link
            label: Source URL
          - type: Linebreak
          - identifier: crop
            useExistingField: true
    

    File Type Options

    Option Type Required Description
    typeName string ✓ One of: text, image, audio, video, application
    prefixFields boolean Whether to prefix field identifiers with the Content Block name (often false for File Types to keep shared field names)

    Use Cases for File Types

    Use Case Fields to Add
    Photography agency photographer, copyright, license_type, expiry_date
    Video platform director, duration, transcript, subtitles
    Document management document_version, author, confidentiality
    E-commerce product_sku, variant_color, variant_size

    Accessing File Type Fields

    In Fluid templates, access custom metadata through FAL references:

    <f:for each="{data.images}" as="image">
        <figure>
            <f:image image="{image}" alt="{image.alternative}"/>
            <f:if condition="{image.properties.photographer}">
                <figcaption>
                    Photo: {image.properties.photographer}
                    <f:if condition="{image.properties.copyright}">
                        | © {image.properties.copyright}
                    </f:if>
                </figcaption>
            </f:if>
        </figure>
    </f:for>
    

    9. Field Types Reference

    Simple Fields

    Type Description Example
    Text Single line text type: Text
    Textarea Multi-line text type: Textarea
    Email Email address type: Email
    Link Link/URL type: Link
    Number Integer/Float type: Number (+ format: integer or format: decimal as needed; legacy YAML sometimes used a non-existent Integer type — use Number)
    DateTime Date and/or time type: DateTime
    Color Color picker type: Color
    Checkbox Boolean checkbox type: Checkbox
    Radio Radio buttons type: Radio
    Slug URL slug type: Slug
    Password Password field type: Password
    Basic Shared “basic” field helper type: Basic
    Country Country selection (aligns with TCA country where supported) type: Country
    Pass Virtual field, not visible in the backend; used for storing data handled by extension logic type: Pass
    SelectNumber Select with numeric values type: SelectNumber
    Uuid UUID string type: Uuid

    Relational Fields

    Type Description Example
    File File references (FAL) type: File
    Relation Record relations type: Relation
    Select Dropdown selection type: Select
    Category System categories type: Category
    Collection Inline records (IRRE) type: Collection
    Folder Folder reference type: Folder
    Language Language selector type: Language

    Structural Fields

    Type Description Example
    Tab Tab separator type: Tab
    Palette Group fields type: Palette
    Linebreak Line break in palette type: Linebreak
    FlexForm FlexForm container type: FlexForm
    Json JSON field type: Json

    Common Field Options

    fields:
      - identifier: my_field
        type: Text
        label: My Field Label           # Static label (or use labels.xlf)
        description: Help text          # Field description
        required: true                  # Make field required
        default: "Default value"        # Default value
        placeholder: "Enter text..."    # Placeholder text
        prefixField: false              # Disable prefixing for this field
        useExistingField: true          # Reuse existing TCA field
        displayCond: 'FIELD:other:=:1'  # Conditional display
        onChange: reload                # Reload form on change
    

    File Field Example

    TCA-only options: Keys like appearance / behaviour belong in generated TCA, not always in Content Blocks YAML. If the schema rejects them, add a TCA override for that field after generation (see Content Blocks docs on extending TCA).

    fields:
      - identifier: gallery_images
        type: File
        allowed: common-image-types
        minitems: 1
        maxitems: 10
    

    Select Field Example

    fields:
      - identifier: layout
        type: Select
        renderType: selectSingle
        default: default
        items:
          - label: Default Layout
            value: default
          - label: Wide Layout
            value: wide
          - label: Compact Layout
            value: compact
    

    Collection Field Example (Inline IRRE)

    fields:
      - identifier: accordion_items
        type: Collection
        labelField: title
        minitems: 1
        maxitems: 20
        appearance:
          collapseAll: true
          levelLinksPosition: both
        fields:
          - identifier: title
            type: Text
            required: true
          - identifier: content
            type: Textarea
            enableRichtext: true
          - identifier: is_open
            type: Checkbox
            label: Initially Open
    

    10. Field Prefixing

    Content Blocks automatically prefixes field identifiers to avoid collisions.

    Prefixing Types

    # Full prefix (default): myvendor_myblock_fieldname
    name: myvendor/my-block
    prefixFields: true
    prefixType: full
    
    # Vendor prefix only: myvendor_fieldname
    name: myvendor/my-block
    prefixFields: true
    prefixType: vendor
    
    # Custom vendor prefix: tx_custom_fieldname
    name: myvendor/my-block
    prefixFields: true
    prefixType: vendor
    vendorPrefix: tx_custom
    
    # No prefix (use with caution!)
    name: myvendor/my-block
    prefixFields: false
    

    Disable Prefixing per Field

    fields:
      - identifier: my_custom_field
        type: Text
        prefixField: false  # This field won't be prefixed
    

    11. Templating Features

    Accessing Data in Fluid

    <!-- Basic field access -->
    {data.header}
    {data.my_field}
    
    <!-- Record metadata -->
    {data.uid}
    {data.pid}
    {data.languageId}
    {data.mainType}      <!-- Table name: tt_content -->
    {data.recordType}    <!-- CType: myvendor_heroblock -->
    {data.fullType}      <!-- tt_content.myvendor_heroblock -->
    
    <!-- Raw database values -->
    {data.rawRecord.some_field}
    
    <!-- System properties -->
    {data.systemProperties.createdAt}
    {data.systemProperties.lastUpdatedAt}
    {data.systemProperties.sorting}
    {data.systemProperties.disabled}
    
    <!-- Language info -->
    {data.languageInfo.translationParent}
    {data.languageInfo.translationSource}
    
    <!-- Relations are auto-resolved! -->
    <f:for each="{data.gallery_images}" as="image">
        <f:image image="{image}" width="400"/>
    </f:for>
    
    <!-- Nested collections -->
    <f:for each="{data.accordion_items}" as="item">
        <h3>{item.title}</h3>
        <f:format.html>{item.content}</f:format.html>
    </f:for>
    

    Asset ViewHelpers

    <!-- Include CSS from assets folder -->
    <f:asset.css identifier="my-block-css" href="{cb:assetPath()}/frontend.css"/>
    
    <!-- Include JS from assets folder -->
    <f:asset.script identifier="my-block-js" src="{cb:assetPath()}/frontend.js"/>
    
    <!-- Cross-block asset reference -->
    <f:asset.css identifier="shared-css" href="{cb:assetPath(name: 'vendor/other-block')}/shared.css"/>
    

    Translation ViewHelper

    <!-- Access labels.xlf translations -->
    <f:translate key="{cb:languagePath()}:my_label"/>
    
    <!-- Cross-block translation -->
    <f:translate key="{cb:languagePath(name: 'vendor/other-block')}:shared_label"/>
    

    12. Extending Existing Tables

    Add custom types to existing tables (like tx_news):

    # EXT:my_sitepackage/ContentBlocks/RecordTypes/custom-news/config.yaml
    name: myvendor/custom-news
    table: tx_news_domain_model_news
    typeName: custom_news
    fields:
      - identifier: title
        useExistingField: true
      - identifier: custom_field
        type: Text
    

    13. Workflow with DDEV

    Standard Development Workflow

    # 1. Create new Content Block
    ddev typo3 make:content-block
    
    # 2. Clear system caches
    ddev typo3 cache:flush -g system
    
    # 3. Update database schema
    ddev typo3 extension:setup --extension=my_sitepackage
    
    # Alternative: Use Database Analyzer in TYPO3 Backend
    # Admin Tools > Maintenance > Analyze Database Structure
    

    Using webprofil/make Extension

    If webprofil/make is installed:

    # Create Content Block with webprofil/make
    ddev make:content_blocks
    
    # Clear caches and update database (prefer Core CLI)
    ddev typo3 cache:flush
    ddev typo3 extension:setup --extension=my_sitepackage
    # `database:updateschema` exists only with helhum/typo3-console — do not assume it in plain Core projects
    

    Integration with Extbase

    After creating Record Types with proper table names, generate Extbase models:

    # If typo3:make:model is available
    ddev typo3 make:model --extension=my_sitepackage
    
    # Generate repository
    ddev typo3 make:repository --extension=my_sitepackage
    

    14. Defaults Configuration

    Create a content-blocks.yaml in project root for default settings:

    # content-blocks.yaml
    vendor: myvendor
    extension: my_sitepackage
    content-type: content-element
    skeleton-path: content-blocks-skeleton
    
    config:
      content-element:
        basics:
          - TYPO3/Header
          - TYPO3/Appearance
          - TYPO3/Links
          - TYPO3/Categories
        group: default
        prefixFields: true
        prefixType: full
      
      record-type:
        prefixFields: true
        prefixType: vendor
        vendorPrefix: tx_mysitepackage
    

    15. Best Practices

    DO ✅

    1. Use Extbase-compatible table names for Record Types:

      table: tx_myextension_domain_model_myrecord
      
    2. Reuse existing fields when possible:

      - identifier: header
        useExistingField: true
      
    3. Group related fields with Tabs and Palettes:

      - identifier: settings_tab
        type: Tab
        label: Settings
      
    4. Use meaningful identifiers (snake_case):

      - identifier: hero_background_image
      
    5. Clear caches after changes:

      ddev typo3 cache:flush -g system
      ddev typo3 extension:setup --extension=my_sitepackage
      
    6. Use labels.xlf for all user-facing labels

    DON'T ❌

    1. Don't use raw SQL - Content Blocks generates schema automatically

    2. Don't duplicate TCA - Config.yaml is the single source of truth

    3. Don't use short table names for Extbase integration:

      # ❌ Wrong
      table: team_member
      
      # ✅ Correct
      table: tx_mysitepackage_domain_model_teammember
      
    4. Don't use dashes in identifiers:

      # ❌ Wrong
      identifier: hero-image
      
      # ✅ Correct
      identifier: hero_image
      
    5. Don't forget shareAcross options when using foreign_table in multiple places

    16. Troubleshooting

    Content Block Not Appearing

    # Clear all caches
    ddev typo3 cache:flush
    
    # Rebuild class loading
    ddev composer dump-autoload
    
    # Check extension setup
    ddev typo3 extension:setup --extension=my_sitepackage
    

    Database Errors

    # Update database schema (Core)
    ddev typo3 extension:setup --extension=my_sitepackage
    # With typo3-console only: ddev typo3 database:updateschema
    
    # Or use Compare Tool
    # Admin Tools > Maintenance > Analyze Database Structure
    

    Field Not Saving

    • Check field identifier is unique (use prefixing)
    • Verify field type is correct
    • Check for typos in config.yaml
    • Ensure labels.xlf has matching keys

    17. Version constraints

    Use TYPO3 v14.1+ with Content Blocks 2.x (friendsoftypo3/content-blocks currently requires typo3/cms-core: ^14.1 — confirm on Packagist).

    // ext_emconf.php — TYPO3 v14.1+ + Content Blocks 2.x
    'depends' => [
        'typo3' => '14.1.0-14.99.99',
        'content_blocks' => '2.0.0-2.99.99',
    ],
    

    Related Skills

    For migration between classic TYPO3 extensions and Content Blocks, see the dedicated migration skill:

    • typo3-content-blocks-migration - Bidirectional migration guide with:
      • TCA → Content Blocks field mapping
      • Content Blocks → TCA reverse mapping
      • Data migration scripts
      • Step-by-step examples
      • Checklists for both directions

    18. Package Management for v14 Compatibility

    If extensions don't support TYPO3 v14 yet, fork and update:

    # Add private fork as VCS repository in composer.json
    # Then update extension for v14 using typo3-rector and typo3-update skills
    

    Required private forks for webconsulting stack:

    • webprofil/wp-t3monitoring-client (^13 → ^14)
    • webprofil/deployer (^13 → ^14)
    • webprofil/crawler (^1.0 → compatible with v14)
    • webprofil/make (^1.1 → compatible with v14)

    References

    • Content Blocks Documentation
    • YAML Reference
    • Field Types
    • Content Elements API
    • Record Types API
    • Page Types API
    • File Types YAML Reference
    • Migration Skill
    • Packagist: friendsoftypo3/content-blocks

    v14-Only Changes

    The following changes affect Content Blocks development on TYPO3 v14 only.

    New TCA Type country [v14 only]

    TYPO3 v14 introduces a native country TCA type (#99911). Content Blocks can use this for country selection fields. Check Content Blocks YAML documentation for support of this field type.

    TCA itemsProcessors [v14 only]

    New itemsProcessors option (#107889) enables dynamic item generation for select fields. Content Blocks may expose this via YAML configuration for advanced select field customization.

    Type-Specific TCA Properties [v14 only]

    • Type-specific ctrl properties (#108027) — title, label, and other ctrl properties can now be overridden per record type in the types section.
    • Type-specific TCA defaults (#107281) — default values can differ per record type.

    Fluid 5.0 Strict Types [v14 only]

    Content Block Fluid templates must comply with Fluid 5.0 strict typing:

    • ViewHelper arguments are strictly typed. Ensure correct types (int vs string).
    • No underscore-prefixed variable names (_myVar).
    • CDATA sections are preserved (not stripped).

    Content Element Restrictions per Column [v14.1+ only]

    TYPO3 v14.1 integrates content_defender functionality into Core. Backend layouts can now restrict which Content Elements (including Content Blocks) are allowed per colPos without third-party extensions.


    Credits & Attribution

    This skill incorporates information from the official Content Blocks documentation maintained by the TYPO3 Content Types Team and Friends of TYPO3.

    Original documentation: https://docs.typo3.org/p/friendsoftypo3/content-blocks/

    Adapted by webconsulting.at for this skill collection

    Source: https://github.com/dirnbauer/webconsulting-skills Thanks to Netresearch DTT GmbH for their contributions to the TYPO3 community.

    Recommended Servers
    Notion
    Notion
    Repository
    dirnbauer/webconsulting-skills
    Files