Filter für Contao 5 mit Rocksolid Custom Elements
Schritt‑für‑Schritt‑Anleitung für Contao
Das Einrichten einer Filterfunktion in Contao 5 kann mit Bordmitteln und den Rocksolid Custom Elements umgesetzt werden – ganz ohne externe Erweiterungen wie Filterizr. Im Folgenden wird Schritt für Schritt erklärt, wie sich ein solches Setup einrichten lässt. Der Ansatz kombiniert ein zusätzliches Feld im DCA, Sprachdateien für Labels und ein eigenes RSCE-Wrapper-Element mit JavaScript zur Steuerung des Filters.
Die Agentur Zentral GmbH realisiert individuelle Programmierungen in Contao. Dazu gehören maßgeschneiderte Lösungen mit Rocksolid Custom Elements (RSCE) für flexible und erweiterbare Projekte.
Neues Datenfeld im DCA anlegen
Zuerst wird im DCA der Inhaltselemente ein Feld data_category definiert. Dieses Feld dient als Datenattribut, mit dem später die Filterung funktioniert.
// contao/dca/tl_content.php
declare(strict_types=1);
use Contao\CoreBundle\DataContainer\PaletteManipulator;
// ----------------------------
// Data-Attribut
// ----------------------------
$GLOBALS['TL_DCA']['tl_content']['fields']['data_category'] = [
    'label'     => &$GLOBALS['TL_LANG']['tl_content']['data_category'],
    'exclude'   => true,
    'inputType' => 'text',
    'eval'      => [
        'maxlength'      => 255,
        'decodeEntities' => true,
        'tl_class'       => 'w50',
    ],
    'sql'       => "varchar(255) NOT NULL default ''",
];
// Feld in alle Paletten einschleusen
foreach (array_keys($GLOBALS['TL_DCA']['tl_content']['palettes']) as $palette) {
    if ('__selector__' === $palette) {
        continue;
    }
    $current = $GLOBALS['TL_DCA']['tl_content']['palettes'][$palette];
    if (is_string($current) && str_contains($current, '{expert_legend')) {
        PaletteManipulator::create()
            ->addField('data_category', 'expert_legend', PaletteManipulator::POSITION_APPEND)
            ->applyToPalette($palette, 'tl_content');
    } elseif (is_string($current)) {
        $GLOBALS['TL_DCA']['tl_content']['palettes'][$palette] = rtrim($current, ';')
            . ';{expert_legend:hide},data_category';
    }
}
Damit wird das Eingabefeld Daten-Kategorie automatisch allen Inhaltselementen hinzugefügt.
Sprachdateien erweitern
Das Label für das Feld wird über die Sprachdateien definiert:
// contao/languages/de/default.php
$GLOBALS['TL_LANG']['tl_content']['data_category'] = [
    'Daten-Kategorie',
    'Wert für die Filter-Funktion <code>data-category</code> dieses Inhaltselements (kommasepariert).'
];
Dadurch erscheint das Feld mit einer passenden Beschreibung im Backend.
Rocksolid Custom Element: Filter-Wrapper
Nun wird ein RSCE-Wrapper angelegt, der als Container für alle zu filternden Inhalte dient.
rsce_filter_wrapper_start.config.php
<?php
return array(
	'label' => array('Filter-Wrapper (Start)', 'Umschließt die zu filternden Elemente.'),
	'types' => array('content'),
	'contentCategory' => 'includes',
	'wrapper' => array('type' => 'start')
);
rsce_filter_wrapper_start.html5
<div id="filter-wrapper" class="content-filter-wrapper">
  <ul class="filter-controls" aria-label="Filter"></ul>
  <div class="filter-container js-filter">
rsce_filter_wrapper_end.config.php
<?php
return array(
	'label' => array('Filter-Wrapper (Ende)', 'Schließt den Filter-Wrapper.'),
	'types' => array('content'),
	'contentCategory' => 'includes',
	'wrapper' => array('type' => 'stop')
);
rsce_filter_wrapper_end.html5
</div>
</div>
<script>
  (function ($) {
    $(function () {
      var $container = $('.js-filter').last();
      if (!$container.length) return;
      var $items = $container.children().addClass('js-filter-item');
      var cats = {};
      $items.each(function () {
        var raw = ($(this).attr('data-category') || '');
        raw.split(',').map(function (s) { return $.trim(s); })
          .filter(Boolean).forEach(function (c) { cats[c] = true; });
      });
      var list = Object.keys(cats).sort();
      var $controls = $container.prevAll('.filter-controls').first();
      if ($controls.length) {
        $controls.empty().append('<li data-filter="all" class="is-active">Alle</li>');
        list.forEach(function (c) {
          var safe = $('<div>').text(c).html();
          $controls.append('<li data-filter="'+safe+'">'+safe+'</li>');
        });
      }
      $controls.on('click', '[data-filter]', function (e) {
        e.preventDefault();
        var val = $(this).data('filter');
        $(this).addClass('is-active').siblings().removeClass('is-active');
        if (val === 'all') {
          $items.show();
          return;
        }
        $items.each(function () {
          var arr = ($(this).attr('data-category') || '')
            .split(',').map(function (s){ return $.trim(s); }).filter(Boolean);
          $(this).toggle(arr.indexOf(val) !== -1);
        });
      });
    });
  })(jQuery);
</script>
Funktionsweise
- Backend: Redakteure können jedem Inhaltselement eine oder mehrere Kategorien (kommasepariert) zuweisen.
 - Frontend: Die JavaScript-Routine liest diese Kategorien aus, generiert automatisch die Filterbuttons und blendet Inhalte dynamisch ein oder aus.
 - Vorteil: Keine zusätzliche Erweiterung (außer RSCE) notwendig, einfache Integration in bestehende Contao-Projekte.
 
Fazit
Mit diesem Ansatz lassen sich flexible Filterfunktionen in Contao 5 realisieren, ohne dass externe Bibliotheken oder Erweiterungen notwendig sind. Durch die Kombination von DCA-Feld, RSCE-Wrapper und schlankem jQuery-Skript entsteht eine robuste Lösung, die sich leicht erweitern lässt. Ein Beispiel für die Anwendung ist auf der Beispiel-Webseite für das Theme Ultimate zu finden.