Das Erstellen von eigenen Inhaltselementen (CE) ist nicht sonderlich schwer, erfordert aber ein paar Schritte, welche man beachten sollte. Dieser Guide bezieht sich auf TYPO3 9. Hier eine kurze Auflistung:
- TS-Config anlegen
- Plugin hinzufügen
- Flexform erstellen
- Typoscript Config angeben
- (Backend-Rendering)
- Icon hinzufügen
- Fluid-Templates erstellen
Ja, ihr seht richtig, wir benötigen hier keine eigenen Datenbank-Felder. Alle unsere Daten speichern wir in dem bereits vorhandenen Feld pi_flexform. In unserem Beispiel hier fügen wir ein eigenes Inhaltselement für Zitate ein.
Wenn du nur auf den Gewinn schaust,
wirst du nachlässig. Aber wenn du dich
darauf konzentrierst, richtig gute Produkte
herzustellen, wird der Gewinn folgen.
TS-Config anlegen
Um unser neues Inhaltselement auch über den Wizard im Backend zu erreichen, fügen wir das Element zum New Content Element Wizard hinzu. Hierzu verwenden wir eine .tsconfig-Datei, über welche alle weiteren Inhaltselemente (z.B. für Zitate, Slider,…) eingefügt werden können:
Diese TS-Config Datei registrieren wir unter Configuration/TCA/Overrides/pages.php:
// CONTENT ELEMENTS
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerPageTSConfigFile(
'va_template',
'Configuration/TsConfig/Page/ContentElement/All.tsconfig',
'Varioous Template - All Content Elements'
);
Der Inhalt unserer neu erstellten TS-Config Datei Configuration/TsConfig/Pages/ContentElement/All.tsconfig ist ein simples Include:
##########################
#### CONTENT ELEMENTS ####
##########################
<INCLUDE_TYPOSCRIPT: source="DIR:EXT:va_template/Configuration/TsConfig/Page/ContentElement/Element" extensions="tsconfig">
Hiermit inkludieren wir alle Inhaltselemente, welche sich unter Configuration/TsConfig/Pages/ContentElement/Element befinden. Dort liegt auch unsere neu erstellte TS-Config Datei unseres Zitat-Inhaltselements:
####################################
#### NEW CONTENT ELEMENT WIZARD ####
####################################
mod.wizards.newContentElement.wizardItems.common {
elements {
vatemplate_blockquote {
iconIdentifier = ext-vatemplate-content-blockquote-icon
title = LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.blockquote
description = LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.blockquote.description
tt_content_defValues {
CType = vatemplate_blockquote
}
}
}
show := addToList(vatemplate_blockquote)
}
Wir definieren den CType des Elements (vatemplate_blockquote), ein Icon, den Titel und eine kurze Beschreibung. Diese Informationen sehen wir im Wizard beim Anlegen eines neuen Inhaltselements:

Plugin hinzufügen
Um das Content Element zu erstellen nutzen wir die TYPO3 Core-Methode addPlugin. Wir nutzen jedoch ein selbst erstelltes Utility, um später auch weitere Elemente einfach hinzufügen zu können: Classes/Utility/HelperUtility.php
<?php
namespace Varioous\VaTemplate\Utility;
class HelperUtility
{
/**
* Add content element in Configuration/Overrides/tt_content.php
*
* @param $title The title of the content element (LLL:...)
* @param $cType The CType of the content element, e.g. vatemplate_text
* @param string $showItems The showitem section of the content element
* @param string $extensionKey The extension the content element is stored, e.g. va_template
* @param $iconPath The path to the icon file
* @param $typeIconClass The typeicon class, e.g. ext-vatemplate-content-blockquote-icon, that is registered in ext_localconf.php
* @param string $flexform The path to the flexform values
*/
public static function addContentElement($title, $cType, $showItems, $extensionKey = 'va_template', $iconPath = '', $typeIconClass = '', $flexform = '') {
ExtensionManagementUtility::addPlugin(
array(
$title,
$cType,
$iconPath?$iconPath:'EXT:va_template/ext_icon.svg'
),
'CType',
$extensionKey
);
if($flexform){
ExtensionManagementUtility::addPiFlexFormValue('*', $flexform, $cType);
}
$GLOBALS['TCA']['tt_content']['types'][$cType]['showitem'] = $showItems;
if($typeIconClass === ''){
$typeIconClass = str_replace('_', '', $extensionKey);
$typeIconClass = str_replace('-', '', $typeIconClass);
$typeIconClass = 'ext-' . $typeIconClass . '-content-' . str_replace($typeIconClass . '_', '', $cType) . '-icon';
}
$GLOBALS['TCA']['tt_content']['ctrl']['typeicon_classes'][$cType] = $typeIconClass;
}
...
}
Wir haben somit die Möglichkeit, dass wir ein Plugin inklusive Flexform und Icon zu erstellen. Unser soeben erstelles Utility verwenden wir unter Configuration/TCA/Overrides/tt_content.php:
// ####################
// blockquote
// ####################
HelperUtility::addContentElement(
'LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.blockquote', // Zitat
'vatemplate_blockquote',
'--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,--palette--;;general,--palette--;;headers,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',
'va_template',
'EXT:va_template/Resources/Public/Icons/ContentElement/blockquote.svg',
'ext-vatemplate-content-blockquote-icon',
'FILE:EXT:va_template/Configuration/FlexForms/ContentElement/Blockquote.xml'
);
Flexform erstellen
Unsere benötigten Felder im neuen Inhaltselement erstellen wir, wie oben kurz erwähnt, als Flexform-Values. Hierzu erstellen wir eine Flexform Datei unter Configuration/FlexForms/ContentElement/Blockquote.xml:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3DataStructure>
<sheets>
<sDEF>
<ROOT>
<TCEforms>
<sheetTitle>LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.blockquote</sheetTitle>
</TCEforms>
<type>array</type>
<el>
<quote>
<TCEforms>
<label>LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.blockquote.settings.quote</label>
<config>
<type>text</type>
<rows>5</rows>
<cols>30</cols>
<eval>required</eval>
</config>
</TCEforms>
</quote>
<author>
<TCEforms>
<label>LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.blockquote.settings.author</label>
<config>
<type>input</type>
<eval>trim</eval>
</config>
</TCEforms>
</author>
<role>
<TCEforms>
<label>LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.blockquote.settings.role</label>
<config>
<type>input</type>
<eval>trim</eval>
</config>
</TCEforms>
</role>
</el>
</ROOT>
</sDEF>
</sheets>
</T3DataStructure>
Somit sind unsere Flexform-Felder für die Eingabe im Backend auch schon angelegt:

Wir erstellen eine Kopie von lib.contentElement und geben den neuen Fluid-Template Namen an (Blockquote). Weiters definieren wir hier ein eigenes dataProcessing (TYPO3 Dokumentation) mit einem unter Classes/DataProcessing/ erstellen FlexFormProcessor:
<?php
namespace Varioous\VaTemplate\DataProcessing;
class FlexFormProcessor implements DataProcessorInterface
{
/**
* Process flexform field data to an array
*
* @param ContentObjectRenderer $cObj The data of the content element or page
* @param array $contentObjectConfiguration The configuration of Content Object
* @param array $processorConfiguration The configuration of this processor
* @param array $processedData Key/value store of processed data (e.g. to be passed to a Fluid View)
*
* @return array the processed data as key/value store
*/
public function process(
ContentObjectRenderer $cObj,
array $contentObjectConfiguration,
array $processorConfiguration,
array $processedData
) {
if (isset($processorConfiguration['if.']) && !$cObj->checkIf($processorConfiguration['if.'])) {
return $processedData;
}
// set targetvariable, default "flexform"
$targetVariableName = $cObj->stdWrapValue('as', $processorConfiguration, 'flexform');
// set fieldname, default "pi_flexform"
$fieldName = $cObj->stdWrapValue('fieldName', $processorConfiguration, 'pi_flexform');
// parse flexform
$flexformService = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Service\\FlexFormService');
$processedData[$targetVariableName] = $flexformService->convertFlexFormContentToArray($cObj->data[$fieldName]);
// if targetvariable is settings, try to merge it with contentObjectConfiguration['settings.']
if ($targetVariableName == 'settings') {
if (is_array($contentObjectConfiguration['settings.'])) {
$convertedConf = GeneralUtility::removeDotsFromTS($contentObjectConfiguration['settings.']);
foreach ($convertedConf as $key => $value) {
if (!isset($processedData[$targetVariableName][$key])
|| $processedData[$targetVariableName][$key] == false) {
$processedData[$targetVariableName][$key] = $value;
}
}
}
}
return $processedData;
}
}
Weiter Informationen zu DataProcessors werden in einem eigenen Blog-Artikel von uns bereit gestellt. Also bleibt am Laufenden!
Backend-Rendering
Auf das Backend Rendering des neu erstellen Inhaltselements werde ich nur kurz eingeben. Genaue Infos findet ihr hier: TYPO3 Dokumentation
Das Auslesen unseres Flexform-Feldes funktioniert ganz simpel mittels der Methode xml2array:
...
public function preProcess(
PageLayoutView &$parentObject,
&$drawItem,
&$headerContent,
&$itemContent,
array &$row
) {
if ($row['CType'] === 'vatemplate_blockquote') {
$flexform = $this->cleanUpArray(GeneralUtility::xml2array($row['pi_flexform']),
array('data', 'sDEF', 'lDEF', 'vDEF'));
if ($flexform['quote']) {
$itemContent .= $parentObject->linkEditContent($parentObject->renderText($flexform['quote']), $row)
. '<br />';
}
$drawItem = false;
}
}
public function cleanUpArray(array $cleanUpArray, array $notAllowed) {
$cleanArray = array();
foreach ($cleanUpArray as $key => $value) {
if (in_array($key, $notAllowed)) {
return is_array($value) ? $this->cleanUpArray($value, $notAllowed) : $value;
} else {
if (is_array($value)) {
$cleanArray[$key] = $this->cleanUpArray($value, $notAllowed);
}
}
}
return $cleanArray;
}
...
Icon hinzufügen
Unter Resources/Public/Icons/ContentElement/ erstellen wir ein neues SVG-Icon mit dem Namen blockquote.svg. Dieses Icon können wird danach in der Datei ext_localconf.php registrieren:
/************************************************************************
* CONTENT ELEMENT ICONS
************************************************************************/
if (TYPO3_MODE === 'BE') {
$icons = [
...
'ext-vatemplate-content-blockquote-icon' => 'blockquote.svg'
];
$iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class);
foreach ($icons as $identifier => $path) {
$iconRegistry->registerIcon($identifier, \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class,
['source' => 'EXT:va_template/Resources/Public/Icons/ContentElement/' . $path]);
}
}
Fluid-Template
Fast fertig! Jetzt fehlt uns nur noch die Darstellung im Frontend. Diese wird komfortabel über ein Fluid Template geregelt. Wir erstellen ein neues Fluid Template Resources/Private/Templates/ContentElement/Blockquote.html
...
<f:render section="Blockquote" />
...
<f:section name="Blockquote">
<blockquote>
<div class="quote">
<f:format.nl2br>{content.quote}</f:format.nl2br>
</div>
<footer class="author">
{content.author}<f:if condition="{content.role}"><span class="role">{content.role}</span></f:if>
</footer>
</blockquote>
</f:section>
In unserem Template können wir jetzt komfortabel auf die per Data Processor verarbeiteten Flexform-Daten (content) zugreifen.
Et voilà! Das wars. So könnt ihr auch noch weitere Inhaltselemente erstellen. In einem nächsten Beitrag werde ich euch noch zeigen, wie man einen einfach Bild-Slider auf die Gleiche Art und Weise erstellen kann und wie Data Processors verwendet werden können.
Bildquelle:
Wir entwickeln digitale Lösungen mit Leidenschaft
Warum wir das tun? Weil die Verwirklichung Ihrer Vision unser größter Anspruch und die schönste Anerkennung ist. Deshalb nehmen wir uns gerne ausreichend Zeit für die Realisierung Ihres digitalen Projekts.
Kontaktieren Sie uns, wir sind gerne für Ihre Fragen da: