TYPO3 9 Bild-Slider

Aus der Reihe "Custom Content Elements". Im heutigen Blog-Beitrag zeige ich euch kurz, wie man innerhalb kürzester Zeit einen einfachen Bild-Slider als eigenständiges Content Element erstellen kann. Wir benötigen hierzu die TYPO3 Erweiterungen gridelements und vhs und den bereits vorangegangenen Beitrag Custom Content Elements.

In Beitrag über Custom Content Elements habe ich bereits erklärt, dass wir ganz ohne neue Datenbank-Felder anlegen zu müssen, neue Inhaltselemente (CE) selbst erstellen können.

Hier nochmal kurz die Schritte, die wir uns ansehen werden:

  • gridelements und vhs installieren
  • TS-Config für Slide anlegen
  • TS-Config für Slider anlegen
  • Plugin für Slide hinzufügen
  • Flexform für Slide erstellen
  • Flexform für Slider erstellen
  • Typoscript Config für Slide angeben
  • Typoscript Config für Slider angeben
  • Icon hinzufügen
  • Fluid-Templates erstellen
TYPO3 9 Bild-Slider

gridelements und vhs installieren

Je nachdem, ob ihr TYPO3 im composer Mode oder in der klassischen Variante mit der Installation von Erweiterungen aus dem TER verwendet, könnt ihr hier eine der folgenden Möglichkeiten auswählen: Gridelements DownloadVHS Download.

TS-Config für Slide anlegen

Wir wollen in unserem Slider nicht nur reine Bilder sliden, sondern eine Kombination aus Text und Bild, z.B. ein Produktbild im Hintergrund und überlagernd Informationen als Text, im Backend sieht das ganze so aus:

TYPO3 9 Bild-Slider

Wir erstellen hier also als erstes unsere Slide Inhalts Elemente. Wir fügen unser neues Inhaltselement zum New Content Element Wizard hinzu. Hierzu verwenden wir eine .tsconfig-Datei, (vgl. TYPO3 9 Custom Content Elements):

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">

Unter Configuration/TsConfig/Pages/ContentElement/Element erstellen wir eine neue Konfigurations-Datei „Slide“ für unser Slide-Element:

######################################## NEW CONTENT ELEMENT WIZARD ########################################mod.wizards.newContentElement.wizardItems.common {    elements {        vatemplate_slide {            iconIdentifier = ext-vatemplate-content-slide-icon            title = LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.slide            description = LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.slide.description            tt_content_defValues {                CType = vatemplate_slide            }        }    }    show := addToList(vatemplate_slide)}

TS-Config für Slider anlegen

Wie anfangs erwähnt, verwenden wir die TYPO3 Erweiterung gridelements für unseren Slider. D.h. wir erstellen einen neuen Container, in welchem später die Slides platziert werden können. Das machen wir parallel zum bereits erstellten Slide Element. Wir erstellen eine neue Datei Configuration/TsConfig/Pages/ContentElement/Element/GridElement.tsconfig:

tx_gridelements {  # TS Elemente haben Vorrang vor Datensätzen mit gleichen IDs  overruleRecords = 1  setup {    imageSlider {      iconIdentifier = ext-vatemplate-content-imageslider-icon      title = LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.imageSlider      description = LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.imageSlider.description      flexformDS = FILE:EXT:va_template/Configuration/FlexForms/ContentElement/GridElement/ImageSlider.xml      topLevelLayout = 1      config {        # 1 Spalte, 1 Reihe        colCount = 1        rowCount = 1        rows {          1 {            columns {              1 {                name = LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.imageSlider.slides                colPos = 0                # innerhalb des gridelements Containers sind nur Slides erlaubt                allowed {                  CType = vatemplate_slide                }              }            }          }        }      }    }

Über registerPageTSConfigFile (siehe weiter oben), binden wir alle unsere TS-Config Dateien, welche sich im Verzeichnis va_template/Configuration/TsConfig/Page/ContentElement/Element befinden, ein – also auch unsere soeben erstellte GridElements.tsconfig.

Plugin für Slide hinzufügen

Im Artikel TYPO3 9 Custom Content Elements haben wir bereits ein Utility angelegt, welches uns beim Hinzufügen von Inhaltselementen hilft. Dieses nutzen wir jetzt zum Registrieren unseres Slide Elements unter Configuration/TCA/Overrides/tt_content.php:

// ####################// slide// ####################HelperUtility::addContentElement(    'LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.slide',  // Slide Element    'vatemplate_slide',    '--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/slide.svg',    'ext-vatemplate-content-slide-icon',    'FILE:EXT:va_template/Configuration/FlexForms/ContentElement/Slide.xml');

Flexform für Slide erstellen

Auch für unser Slide Content Element verwenden wir eine FlexForm, um die gewünschten Felder zu erhalten. Hierzu erstellen wir eine Datei unter Configuration/FlexForms/ContentElement/Slide.xml. Diese Datei enthält zwei Felder, einmal ein media (image) Feld und noch einen bodytext. Die Konfigurationen des media Feldes kann mittels FlexForm leider nicht so komfortabel wie als TCA erstellt werden (vgl. TCA Type Inline). Die Konfiguration des bodytexts ist relativ simpel:

<?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.slide</sheetTitle>                </TCEforms>                <type>array</type>                 <el>                    <media>                        <!-- https://stackoverflow.com/questions/47554243/how-to-add-cropvariants-to-an-image-field-in-typo3-flexform -->                        <TCEforms>                            <label>                                LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.backgroundtext.settings.image                            </label>                            <config>                                <type>inline</type>                                <minitems>1</minitems>                                <maxitems>1</maxitems>                                <appearance type="array">                                    <enabledControls type="array">                                        <delete>1</delete>                                        <dragdrop>0</dragdrop>                                        <new>0</new>                                        <hide>1</hide>                                        <info>1</info>                                        <localize>1</localize>                                    </enabledControls>                                    <fileUploadAllowed>0</fileUploadAllowed>                                    <headerThumbnail type="array">                                        <field>uid_local</field>                                        <height>100c</height>                                        <width>100</width>                                    </headerThumbnail>                                    <useSortable>1</useSortable>                                    <showAllLocalizationLink>0</showAllLocalizationLink>                                    <showPossibleLocalizationRecords>0</showPossibleLocalizationRecords>                                    <showRemovedLocalizationRecords>0</showRemovedLocalizationRecords>                                    <showSynchronizationLink>0</showSynchronizationLink>                                </appearance>                                <behaviour type="array">                                    <localizationMode>select</localizationMode>                                    <localizeChildrenAtParentLocalization>1</localizeChildrenAtParentLocalization>                                </behaviour>                                <foreign_field>uid_foreign</foreign_field>                                <foreign_label>uid_local</foreign_label>                                <foreign_match_fields type="array">                                    <fieldname>media</fieldname>                                </foreign_match_fields>                                <foreign_selector>uid_local</foreign_selector>                                <foreign_selector_fieldTcaOverride type="array">                                    <config type="array">                                        <appearance type="array">                                            <elementBrowserType>file</elementBrowserType>                                            <elementBrowserAllowed>gif,jpg,jpeg,tif,tiff,bmp,pcx,tga,png,pdf,ai,svg                                            </elementBrowserAllowed>                                        </appearance>                                    </config>                                </foreign_selector_fieldTcaOverride>                                <foreign_sortby>sorting_foreign</foreign_sortby>                                <foreign_table>sys_file_reference</foreign_table>                                <foreign_table_field>tablenames</foreign_table_field>                                <overrideChildTca>                                    <types type="array">                                        <numIndex index="0" type="array">                                            <showitem>                                                --palette--;LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,                                                --palette--;;filePalette                                            </showitem>                                        </numIndex>                                        <numIndex index="1" type="array">                                            <showitem>                                                --palette--;LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,                                                --palette--;;filePalette                                            </showitem>                                        </numIndex>                                        <numIndex index="2" type="array">                                            <showitem>                                                --palette--;LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,                                                --palette--;;filePalette                                            </showitem>                                        </numIndex>                                        <numIndex index="3" type="array">                                            <showitem>                                                --palette--;LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.audioOverlayPalette;audioOverlayPalette,                                                --palette--;;filePalette                                            </showitem>                                        </numIndex>                                        <numIndex index="4" type="array">                                            <showitem>                                                --palette--;LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.videoOverlayPalette;videoOverlayPalette,                                                --palette--;;filePalette                                            </showitem>                                        </numIndex>                                        <numIndex index="5" type="array">                                            <showitem>                                                --palette--;LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,                                                --palette--;;filePalette                                            </showitem>                                        </numIndex>                                    </types>                                </overrideChildTca>                            </config>                            <displayCond>FIELD:contentType:=:0</displayCond>                        </TCEforms>                    </media>                    <bodytext>                        <TCEforms>                            <label>                                LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.backgroundtext.settings.bodytext                            </label>                            <config>                                <type>text</type>                                <rows>5</rows>                                <cols>30</cols>                                <enableRichtext>true</enableRichtext>                            </config>                        </TCEforms>                    </bodytext>                </el>            </ROOT>        </sDEF>    </sheets></T3DataStructure>

Somit sind unsere Flexform-Felder für die Eingabe im Backend auch schon angelegt:

TYPO3 9 Bild-Slider

Flexform für Slider erstellen

Nun erstellen wir noch ein FlexForm für den Slider (gridelements), um dort diverse Einstellungen vornehmen zu können, z.B.: Slider Geschwindigkeit, Autoplay,… Hierzu erstellen wir eine Datei Configuration/FlexForms/ContentElement/GridElement/ImageSlider.xml:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?><T3DataStructure>    <meta type="array">        <langChildren>0</langChildren>        <langDisable>1</langDisable>    </meta>    <ROOT>        <type>array</type>        <el>            <sliderAutoSlide>                <TCEforms>                    <label>LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.imageSlider.settings.autoSlide</label>                    <config>                        <type>check</type>                        <renderType>checkboxToggle</renderType>                        <default>1</default>                    </config>                </TCEforms>            </sliderAutoSlide>            <sliderSpeed>                <TCEforms>                    <label>LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.imageSlider.settings.sliderSpeed</label>                    <config>                        <type>input</type>                        <eval>double</eval>                        <default>8</default>                    </config>                </TCEforms>            </sliderSpeed>            <pauseOnHover>                <TCEforms>                    <label>LLL:EXT:va_template/Resources/Private/Language/locallang.xlf:content_element.imageSlider.settings.pauseOnHover</label>                    <config>                        <type>check</type>                        <renderType>checkboxToggle</renderType>                        <default>1</default>                    </config>                </TCEforms>            </pauseOnHover>        </el>    </ROOT></T3DataStructure>

Auch hier erhalten wir im Backend wieder unsere Ausgabe:

TYPO3 9 Bild-Slider

Typoscript Config für Slide angeben

Im Typoscript definieren wir zuerst unsere Template-Pfade (sieheTYPO3 9 Custom Content Elements) und danach das Rendering unseres neuen Inhaltselements:

tt_content {  # slide  vatemplate_slide =< lib.contentElement  vatemplate_slide {    templateName = Slide    dataProcessing {      1 = Varioous\VaTemplate\DataProcessing\FlexFormProcessor      1 {        options {          if.isTrue.field = pi_flexform          fieldName = pi_flexform        }        as = content      }    }  }}

Wir verwenden dem im Blog-Beitrag TYPO3 9 Custom Content Elements erstellten FlexFormProcessor zum Parsen unseres FlexForms.

Typoscript Config für Slider angeben

Auch für den Slider definieren wir das Rendering im Frontend via Typoscript. Siehe gridelements Dokumentation:

tt_content {  gridelements_pi1{    20{      10{        setup{          imageSlider < lib.gridelements.defaultGridSetup          imageSlider {            cObject = FLUIDTEMPLATE            cObject {              templateName = ImageSlider              templateRootPaths {                10 < lib.contentElement.templateRootPaths.200              }              layoutRootPaths {                10 = EXT:va_template/Resources/Private/Layouts/ContentElement              }            }          }        }      }    }  }}

Icon hinzufügen

Unter Resources/Public/Icons/ContentElement/ erstellen wir neue SVG-Icons mit den Namen slide.svg und slider.svg. Dieses Icons können wir danach in der Datei ext_localconf.php registrieren:

/************************************************************************ * CONTENT ELEMENT ICONS ************************************************************************/if (TYPO3_MODE === 'BE') {    $icons = [        ...        'ext-vatemplate-content-slide-icon' => 'slide.svg'        'ext-vatemplate-content-imageslider-icon' => 'slider.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-Templates

Die Darstellung im Frontend können wir wieder komfortabel über Fluid Templates gestalten. Wir erstellen ein neues Fluid Template Resources/Private/Templates/ContentElement/Slide.html

... <f:render section="Slide" arguments="{_all}" /> ... <f:section name="Slide">  <div class="slide">    <f:render section="Image" arguments="{uid: data.uid}" />    <f:render section="Text" arguments="{bodytext: content.bodytext}"/>  </div></f:section> <f:section name="Text">  <div class="ce-bodytext">    <f:format.html>{bodytext}</f:format.html>  </div></f:section> <f:section name="Image">  <f:for each="{v:content.resources.fal(field: 'media', uid: '{uid}')}" as="imageElem" iteration="iterator">    <div style="background-image: url({f:uri.image(src:imageElem.uid, treatIdAsReference:1, width:width)})" class="image"></div>  </f:for></f:section>

Auch für den Slider erstellen wir ein neues Fluid Template: Resources/Private/Templates/ContentElement/ImageSlider.html

... <f:render section="Slider" arguments="{_all}" /> ... <f:section name="Slider">  <div class="slider" data-pauseonhover="{data.flexform_pauseOnHover}" data-autoplayspeed="{data.flexform_sliderSpeed}" data-autoplay="{data.flexform_sliderAutoSlide}">    <f:if condition="{data.tx_gridelements_view_raw_columns.0}">      <f:variable name="contentElements" value="{data.tx_gridelements_view_raw_columns.0}"/>      <f:for each="{contentElements}" as="contentElement">        <v:content.render contentUids="{0: contentElement.uid}" />      </f:for>    </f:if>  </div></f:section>

Ihr könnt jetzt jeden beliebigen Javascript-Slider verwenden. Wir verwenden hier gerne den Slick-Slider. Dort einfach die data-Attribute abfragen und schon gehts los!

Kontakt und weitere Informationen

Habt ihr Fragen oder Anregungen? Einfach per Mail direkt an mich: 

Georg Wurz, BSc
E-Mail: georg@varioous.at
Telefon: +43 7242 21 99 44

Bildquelle:

Background vector created by makyzz – www.freepik.com