Custom Content Elements
mit TYPO3 9 erstellen

TYPO3 bietet in Sachen Inhalts-Pflege schon eine Vielzahl an Content Elementen an. Solche sind z.B. Text & Medien (textmedia), Menüs (menu_pages,...) oder HTML (html). Es kann jedoch oft vorkommen, dass man den Redakteuren der Website eigene für Ihre Bedürfnisse zugeschnittene Custom Content Elements zur Verfügung stellen möchte. Dies bietet den Vorteil, dass wirklich nur Informationen eingegeben werden können, welche auch benötigt werden.

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.
Steve Jobs

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:

Background vector created by makyzz – www.freepik.com

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:

Passend zu diesem Thema:

Ajax mit TYPO3 – so funktionierts!

Ajax mit TYPO3 – so funktionierts!

Es gibt diverse Ansätze, um Ajax im Typo3 Frontend zu nutzen. Wir haben hier einen für uns doch sehr einfachen und praktikablen Weg, den wir euch nich…

TYPO3 Chatbot

TYPO3 Chatbot

Chatbots ermöglichen es, die Betreuung von Website-Besuchern im Kundenservice einfach und effizient zu gestalten. Der Einsatz dieser virtuellen Helfer…

TYPO3 Tipps und Tricks: Manueller/Programmatischer Login in Controller-Action (TYPO3 9)

TYPO3 Tipps und Tricks: Manueller/Programmatischer Login in Controller-Action (T…

Manchmal gibt es bei Web-Projekten die Notwendigkeit einen Login programmatisch (manuell, im PHP-Code) durchzuführen. Ein Kunde hat vor kurzem folgend…