Own content element in TYPO3 (image via sys_file_reference in FlexForm)

Own content element in TYPO3 (image via sys_file_reference in FlexForm)

There are certainly some good blog posts or ready-made extensions that you can use to create your own content elements in TYPO3. Here we show again how the whole thing works as simply as possible. The tags: fal, sys_file, sys_file_reference, flexform, dataprocessing, page content

In the example we use FlexForm to display custom fields. Of course it is debatable whether you want to add your own fields in the database table or whether you prefer to use FlexForm (we should examine the advantages and disadvantages in a separate blog post). In the example we want to render a new page content of the "Highlight" type as simply and quickly as possible. The design provides that in addition to texts, an image should also be displayed. In addition, the editor should be able to choose the background color and the structure.

Code Backend

You define a new content element via a TCA file in your site package, load a FlexForm file and define the fields to be displayed for this page content (EXT:in2template/Configuration/TCA/Overrides/tt_content.php):

<?php $languageFilePrefix = 'LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:'; $frontendLanguageFilePrefix = 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:'; /** * TCA manipulation (mainly for custom content elements) */ $tca = [ 'ctrl' => [ 'typeicons' => [ 'ce.highlight' => 'ce.highlight', ], 'typeicon_classes' => [ 'ce.highlight' => 'ce.highlight', ], ], 'types' => [ 'ce.highlight' => [ 'showitem' => '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general, --palette--;;general, header;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:header.ALT.html_formlabel, pi_flexform, --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance, --palette--;;frames, --palette--;;appearanceLinks, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language, --palette--;;language, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access, --palette--;;hidden, --palette--;;access, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories, categories, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes, rowDescription, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended,' ], ], ]; $GLOBALS['TCA']['tt_content'] = array_replace_recursive($GLOBALS['TCA']['tt_content'], $tca); /** * Include Flexforms */ \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue( '*', 'FILE:EXT:in2template/Configuration/FlexForms/ContentElements/Highlight.xml', 'ce.highlight' ); /** * Register custom content elements */ \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem( 'tt_content', 'CType', [ 'LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:ce.highlight', 'ce.highlight', 'ce.highlight', ], 'textmedia', 'after' );

In the FlexForm file you define the fields to be displayed. Of particular interest is the image field, which is supposed to render IRRE datasets of the type sys_file_reference in the backend as usual (EXT:in2template/Configuration/FlexForms/ContentElements/Highlight.xml):

<T3DataStructure> <meta> <langDisable>1</langDisable> </meta> <sheets> <main> <ROOT> <TCEforms> <sheetTitle>LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:flexform.highlight.main</sheetTitle> </TCEforms> <type>array</type> <el> <title> <TCEforms> <label>LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:flexform.highlight.title</label> <config> <type>input</type> <eval>trim,required</eval> </config> </TCEforms> </title> <subtitle> <TCEforms> <label>LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:flexform.highlight.subtitle</label> <config> <type>text</type> <eval>trim</eval> </config> </TCEforms> </subtitle> <image> <TCEforms> <label>LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:flexform.highlight.image</label> <config> <type>inline</type> <maxitems>1</maxitems> <foreign_table>sys_file_reference</foreign_table> <foreign_table_field>tablenames</foreign_table_field> <foreign_label>uid_local</foreign_label> <foreign_sortby>sorting_foreign</foreign_sortby> <foreign_field>uid_foreign</foreign_field> <foreign_selector>uid_local</foreign_selector> <foreign_selector_fieldTcaOverride> <config> <appearance> <elementBrowserType>file</elementBrowserType> <elementBrowserAllowed>gif,jpg,jpeg,png,svg</elementBrowserAllowed> </appearance> </config> </foreign_selector_fieldTcaOverride> <foreign_types type="array"> <numIndex index="0"> <showitem>--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,--palette--;;filePalette</showitem> </numIndex> <numIndex index="2"> <showitem>--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,--palette--;;filePalette</showitem> </numIndex> </foreign_types> <foreign_match_fields> <fieldname>pi_flexform_highlight</fieldname> </foreign_match_fields> <appearance type="array"> <newRecordLinkAddTitle>1</newRecordLinkAddTitle> <headerThumbnail> <field>uid_local</field> <height>64</height> <width>64</width> </headerThumbnail> <enabledControls> <info>1</info> <new>0</new> <dragdrop>0</dragdrop> <sort>1</sort> <hide>0</hide> <delete>1</delete> <localize>1</localize> </enabledControls> <createNewRelationLinkTitle>LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference</createNewRelationLinkTitle> </appearance> <behaviour> <localizationMode>select</localizationMode> <localizeChildrenAtParentLocalization>1</localizeChildrenAtParentLocalization> </behaviour> <overrideChildTca> <columns type="array"> <uid_local type="array"> <config type="array"> <appearance type="array"> <elementBrowserType>file</elementBrowserType> <elementBrowserAllowed>jpg,jpeg,png,svg,gif</elementBrowserAllowed> </appearance> </config> </uid_local> </columns> <types type="array"> <numIndex index="2"> <showitem>alternative, title,--palette--;;filePalette</showitem> </numIndex> </types> </overrideChildTca> </config> </TCEforms> </image> <label> <TCEforms> <label>LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:flexform.highlight.label</label> <config> <type>input</type> <eval>trim</eval> </config> </TCEforms> </label> <link> <TCEforms> <exclude>1</exclude> <label>LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:flexform.highlight.link</label> <config type="array"> <type>input</type> <eval>trim</eval> <renderType>inputLink</renderType> </config> </TCEforms> </link> <background> <TCEforms> <exclude>1</exclude> <label>LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:flexform.highlight.background</label> <config> <type>select</type> <renderType>selectSingle</renderType> <items type="array"> <numIndex index="1" type="array"> <numIndex index="0">LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:flexform.highlight.background.0</numIndex> <numIndex index="1">0</numIndex> </numIndex> <numIndex index="2" type="array"> <numIndex index="0">LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:flexform.highlight.background.1</numIndex> <numIndex index="1">1</numIndex> </numIndex> </items> </config> </TCEforms> </background> <orient> <TCEforms> <exclude>1</exclude> <label>LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:flexform.highlight.orient</label> <config> <type>select</type> <renderType>selectSingle</renderType> <items type="array"> <numIndex index="1" type="array"> <numIndex index="0">LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:flexform.highlight.orient.0</numIndex> <numIndex index="1">0</numIndex> </numIndex> <numIndex index="2" type="array"> <numIndex index="0">LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:flexform.highlight.orient.1</numIndex> <numIndex index="1">1</numIndex> </numIndex> </items> </config> </TCEforms> </orient> </el> </ROOT> </main> </sheets> </T3DataStructure>

You may also want to have an entry in the wizard so that the new page content is prominently represented when you click on the plus symbol in the page module in the backend. This works via Page TSConfig - in our SitePackage at this point (EXT:in2template/Configuration/TsConfig/Page/Mod/Wizards/ContentElement.tsconfig):

mod.wizards.newContentElement.wizardItems { hfwu { header = Hochschule after = common show = * elements { highlight { iconIdentifier = ce.highlight title = LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:ce.highlight description = LLL:EXT:in2template/Resources/Private/Language/Backend/locallang.xlf:ce.highlight.description tt_content_defValues { CType = ce.highlight } } } } }

Code Frontend

So that the new element can also be rendered in the frontend, it needs a few lines of TypoScript (EXT:in2template/Configuration/TypoScript/Setup/ContentElements/Highlight.typoscript):

lib.in2templateContentElement =< lib.contentElement lib.in2templateContentElement { templateRootPaths { 20 = EXT:in2template/Resources/Private/Templates/ContentElements/ } partialRootPaths { 20 = EXT:in2template/Resources/Private/Partials/ContentElements/ } layoutRootPaths { 20 = EXT:in2template/Resources/Private/Layouts/ContentElements/ } } tt_content.ce\.highlight =< lib.in2templateContentElement tt_content.ce\.highlight { templateName = Highlight dataProcessing { 10 = TYPO3\CMS\Frontend\DataProcessing\FlexFormProcessor 20 = TYPO3\CMS\Frontend\DataProcessing\FilesProcessor 20 { references { table = tt_content fieldName = pi_flexform_highlight } as = image } } }

We use the already existing FlexFormProcessor (DataProcessor) from TYPO3, so that we can use the values from the FlexForm (actually as XML in the database) cleanly in the fluid. In addition, we also use the FilesProcessor so that we can conveniently use the related image to the page content in the template.

The associated HTML template can then look like this (EXT:in2template/Resources/Private/Templates/ContentElements/Highlight.html):

<div class="ce-disturber margin-top-m" id="c{data.uid}"> <div class="container"> <div class="disturber flex{f:if(condition:flexFormData.orient,then:' disturber--left')}{f:if(condition:flexFormData.background,then:' disturber--yellow')}"> <div class="flex__md-8"> <f:if condition="{image.0}"> <f:image image="{image.0}" class="disturber__image" width="900c" maxHeight="300" /> </f:if> </div> <div class="flex__md-4"> <h2 class="disturber__heading">{flexFormData.title}</h2> <f:if condition="{flexFormData.subtitle}"> <p>{flexFormData.subtitle -> f:format.nl2br()}</p> </f:if> <f:if condition="{flexFormData.link} && {flexFormData.label}"> <f:link.typolink class="disturber__button btn btn--primary margin-top-s" parameter="{flexFormData.link}">{flexFormData.label}</f:link.typolink> </f:if> </div> </div> </div> </div>

Remarks

Like most other posts on our blog, this snippet is not completely complete. For example, the entries in the language files (locallang.xlf) are still missing. We have not included the registered SVG icon in ext_localconf.php for reasons of space. We also assume that the user uses a site package so that his TYPO3 installation is properly configured.

Have fun integrating new elements into TYPO3

Alexander Kellner

Alex Kellner

Alex Kellner is not only known for his many TYPO3 extensions such as powermail, femanager or lux, but also for his community work. He is also happy to give administration or development training courses or workshops.

Alexander Kellner  |  Management & COO

TYPO3: Finding unused files in fileadmin

Do you want to delete unused or orphaned files in fileadmin or another storage location? Unfortunately, there's no direct core functionality for this. But a small command in your site package can...

Go to news

TYPO3: Editors with individual user_upload folders

Perhaps you're familiar with this client requirement? Editors should be able to add videos using the "Add media by URL" button. But the files shouldn't be located in fileadmin/user_upload/, but rather...

Go to news

TYPO3: Finding pages in mixed mode

In TYPO3, Mixed Mode refers to translated pages that contain content only partially related to the corresponding content in the main language. This is indicated in the backend by an error message. But...

Go to news

Extbase Extensions: Think extensibility with data, site and language

Today, I have a small request for the TYPO3 extension authors out there: Make sure your extensions are extensible. This will also promote the distribution of the corresponding plugins.

Go to news

SQL: Show all tables sorted by size in descending order

Lately I've been using the SQL command more often to find out which tables in the TYPO3 database are the largest. I've published the snippet once.

Go to news

TYPO3 12 with CKEditor 5: Styles in a single selection

If you set a link in the RTE in TYPO3, you may have to choose between different link classes, for example to create buttons in the frontend. What's new in TYPO3 12 is that you can select not just one...

Go to news