For coders TYPO3 Tech Corner

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

"Code faster, look at the time" - does this sound familiar to you?

How about time and respect for code quality? Working in a team? Automated tests?

Join us

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

Null-Safe Operator in the TYPO3 area

With the introduction of PHP8, problems with undefined arrays or variables in general can arise in many places. Here are a few examples and simple solutions.

Go to news

Delete the first/last lines of a (SQL) file

There isn't much to say about the following commands. Sometimes it can be useful to delete the first (or last) X lines from a file. And if the file is too large to open with a conventional program, a...

Go to news

b13/container: Add and modify child elements in edit view

Unlike gridelements, you cannot manage the child elements in the B13 Container extension when you open the container in the editing view. I would be happy to show you how you can quickly install this...

Go to news

Menu comparison: Numbers, numbers, numbers

Go to news