Erstellung eines eigenen Content-Elements in Contao

'Philipp Seibt'
Philipp Seibt

In diesem Blogbeitrag wird beschrieben, wie man in Contao 4.8 oder höher ein eigenes Frontend-Element ohne die Nutzung eines Bundles anlegen kann.

Im folgenden Beispiel wird ein Element für die Vorstellung von Teammitgliedern angelegt. Bild und Name des Teammitgliedes werden in einer Kachel dargestellt, bei hover erscheint ein Teasertext und bei Klick soll sich ein modaler Dialog mit ausführlichen Daten zur Person öffnen (ein kurzes Video davon gibt es am Ende des Beitrages). Als Grundlage dient das Nature Theme mit dem CSS-Framework Bulma.

Anlegen der DCA

Zuerst wird im Contao-Root-Verzeichnis unter /contao/dca eine Datei mit dem Namen tl_content.php angelegt.

In $GLOBALS['TL_DCA']['tl_content']['palettes'] werden alle Felder definiert, die im Frontend-Element angezeigt werden sollen. Die Zeile {advanced_classes_legend},advancedCss; ist nur notwendig, wenn die Advanced Classes Erweiterung installiert ist und das Spaltenset im Element genutzt werden soll.

Neue Felder können unter $GLOBALS['TL_DCA']['tl_content']['fields'] angelegt werden. In unserem Beispiel legen wir ein neues Feld für den Inhalt im modalen Dialog an.

Damit die neuen Felder angelegt werden, ist es erforderlich, im Contao Manager den Cache zu leeren und das Installtool aufzurufen.

# contao/dca/tl_content.php

<?php
$GLOBALS['TL_DCA']['tl_content']['palettes']['team_modal'] = '
    {type_legend},type,headline;
    {text_legend},text;
    {modal_legend},team_modal_content;
    {image_legend},addImage;
    {protected_legend:hide},protected;
    {expert_legend:hide},guests,cssID;
    {advanced_classes_legend},advancedCss;
    {invisible_legend:hide},invisible,start,stop;';

$GLOBALS['TL_DCA']['tl_content']['fields']['team_modal_content'] = [
    'label' => &$GLOBALS['TL_LANG']['tl_content']['team_modal_content'],
    'exclude' => true,
    'search' => true,
    'inputType' => 'textarea',
    'eval' => ['mandatory'=>true, 'rte'=>'tinyMCE', 'helpwizard'=>true],
    'explanation' => 'insertTags',
    'sql' => "mediumtext NULL"
];

Anlegen des Content Elements

Als nächstes wird die Klasse für das Content Element angelegt. Hierzu legen wir im Contao-Root-Verzeichnis unter /src/Controller/ContentElement die Datei TeamModalElement.php an.

Mit der Annotation wird der Typ festgelegt ("team_modal", analog zum DCA), in welcher Kategorie das Element angezeigt werden soll (category="texts") und welches Template genutzt werden soll (template="ce_team_modal").

In der Funktion getResponse werden alle Felder übergeben, sodass diese dann im Template genutzt werden können.

# src/Controller/ContentElement/TeamModalElement.php

<?php
namespace App\Controller\ContentElement;

use Contao\ContentModel;
use Contao\CoreBundle\Controller\ContentElement\AbstractContentElementController;
use Contao\CoreBundle\ServiceAnnotation\ContentElement;
use Contao\Template;
use Contao\FilesModel;
use Contao\Controller;
use Contao\System;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * @ContentElement("team_modal",
 *   category="texts",
 *   template="ce_team_modal",
 * )
 */
class TeamModalElement extends AbstractContentElementController
{
    protected function getResponse(Template $template, ContentModel $model, Request $request): ?Response
    {
        $template->text = $model->text;
        $template->modalContent = $model->team_modal_content;
        $template->addImage = false;

        // Add an image
        if ($model->addImage && $model->singleSRC != '')
        {
            $template->addImage = true;
            $objModel = FilesModel::findByUuid($model->singleSRC);

            if ($objModel !== null && is_file(System::getContainer()->getParameter('kernel.project_dir') . '/' . $objModel->path))
            {
                $model->singleSRC = $objModel->path;
                Controller::addImageToTemplate($template, $model->row(), null, null, $objModel);
            }
        }

        return $template->getResponse();
    }
}

Service laden

Damit die Klasse geladen wird, muss im Contao-Root-Verzeichnis unter /config noch die services.yml und die config.yml angelegt werden.

In der services.yml muss Autokonfiguration aktiviert sein und es wird der Namespace zur Klasse TeamModalElement definiert.

Anschließend muss die services.yml in der config.yml geladen werden.

Nach dem Anlegen der Dateien muss wieder der Cache geleert werden.

# config/services.yml

services:
  _defaults:
    autoconfigure: true

  App\Controller\ContentElement\TeamModalElement: ~
# config/config.yml

imports:
  - { resource: services.yml }

Übersetzungen

Damit die Felder im Backend richtig bezeichnet sind, legen wir unter /contao/languages/de die Datei tl_content.php, wie im folgenden Beispiel, an.

Für englische Übersetzungen legen wir eine Datei mit dem gleichen Namen unter contao/languages/en an.

Nach dem Hinzufügen der Übersetzungen ist es wieder erforderlich den Cache zu leeren.

# contao/languages/de/tl_content.php

<?php
$GLOBALS['TL_LANG']['CTE']['team_modal'] = ['Team Modal', 'Element zum Anlegen von Teammitgliedern'];
$GLOBALS['TL_LANG']['tl_content']['modal_legend'] = 'Modal Einstellungen';
$GLOBALS['TL_LANG']['tl_content']['team_modal_content'] = ['Inhalt für modalen Dialog', 'Füge hier den Inhalt für den modalen Dialog ein.'];

 

Im Backend würde das Element anschließend so aussehen:

Template anlegen

Das Template mit dem Namen ce_team_modal.html5 wird einfach im Ordner /templates erstellt.

<!-- templates/ce_team_modal.html5 -->

<div class="<?= $this->class ?> block"<?= $this->cssID ?><?php if ($this->style): ?> style="<?= $this->style ?>"<?php endif; ?>>
    <div class="inside">
        <?php $this->block('content'); ?>

        <?php if ($this->addImage): ?>
            <?php $this->insert('image', $this->arrData); ?>
        <?php endif; ?>

        <button class="modal-button" data-target="#modal<?= $this->id ?>"></button>

        <div class="teaser">
            <div>
                <?= $this->text ?>
            </div>
        </div>

        <?php if ($this->headline): ?>
            <<?= $this->hl ?>>
                <?= $this->headline ?>
            </<?= $this->hl ?>>
        <?php endif; ?>

        <?php $this->endblock(); ?>
    </div>
</div>
<div id="modal<?= $this->id ?>" class="modal">
    <div class="modal-background"></div>
    <div class="modal-content">
        <button class="delete float_right" aria-label="close"></button>
        <?= $this->modalContent ?>
    </div>
</div>

Styling

Damit das Element so aussieht, wie im Beispiel am Ende des Beitrages, wird eine CSS-Datei angelegt und im Layout eingebunden. Wir verwenden allerdings SCSS statt CSS.

// files/style.scss

.ce_team_modal {
  display: inline-block;

  &.block:not(:last-child) {
    margin-bottom: 0;
  }

  img {
    height: auto;
    vertical-align: bottom;
  }

  .inside {
    h2, h3, h4, h5, h6 {
      margin: 0;
      font-size: 16px;
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      background: rgba(0,0,0,.5);
      padding: 10px;
      color: #fff;
      text-align: center;
    }
  }

  .modal-button {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: none;
    border: none;
    cursor: pointer;
    z-index: 1;

    &:hover ~ .teaser {
      display: flex;
    }
  }

  ~ .modal {
    padding: 0 15px;

    .modal-content {
      background: #fff;
      padding: 30px;
      max-width: 900px;
      width: 100%;
    }
  }

  .teaser {
    display: none;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    align-items: center;
    flex-wrap: wrap;
    padding: 30px 30px 40px;
    background: rgba(0,0,0,.3);
    text-align: center;

    p {
      color: #fff;
      font-size: 16px;
    }
  }
}

Das Element im Frontend

Wenn alles geklappt hat, sollte das Element anschließend wie im folgenden Video aussehen. Bei Hover über das Bild wird der Teasertext eingeblendet und bei Klick darauf der modale Dialog dargestellt.

 

-----------------------------------------

Zurück