Skip to main content

🔽 Accordion

Accordion mit MODX 3.1.2, pdoTools, Bootstrap 5.3.8 (Spacelab) und Galerielink

📌 Überblick

Dieses Accordion-Modul:

  • lädt Unterseiten per pdoResources (über pdoPage)
  • zeigt den Seiteninhalt strukturiert als Accordion
  • hat konfigurierbare Parameter:
    • open → Anzahl der beim Laden geöffneten Accordion-Panels
    • limit → Inhalt auf X Zeichen kürzen (optional; letztes Wort wird nicht abgeschnitten)
    • rows → maximale Anzahl geladener Unterseiten
  • erzeugt automatisch Buttons für:
    • Galerie (tvGalleryPfad)
    • Downloads (tvDownloadPfad)
  • zeigt bei gesetztem Datum (tvStartdatum) einen Countdown
  • ergänzt das Hauptmenü:
    • Einträge mit TV tvAccordion = ja erscheinen ohne Untermenü (keine Dropdown-Ebene)

🔧 Warum das bestehende pdoMenu angepasst werden muss

Damit Menüeinträge, die auf der Seite selbst mit einem Accordion dargestellt werden, kein Dropdown im Hauptmenü erzeugen, muss pdoMenu wissen, ob ein Menüpunkt ein Untermenü anzeigen soll oder nicht.
Dies wird über das TV tvAccordion gesteuert:

  • tvAccordion = nein → normales Dropdown-Verhalten
  • tvAccordion = ja → der Menüpunkt wird als einfacher Link ohne Untermenü ausgegeben

So bleibt die Navigation klar strukturiert, auch wenn im Ressourcenbaum eigentlich Unterseiten existieren, die jedoch ausschließlich im Accordion erscheinen sollen.

Siehe das pdoMenu-Beispiel im Buch „MODX 3 – Installation & Einrichtung“ auf der Seite „Bootstrap 5“.


🧩 1. Chunk: modxAccordion

Dieser Chunk wird im Content aufgerufen und erzeugt das komplette Accordion.
Aufruf Beispiel: [[!$modxAccordion? &rows=`20` &open=`1` &limit=`5000`]]

[[!pdoPage:default=`Keine Einträge vorhanden`?
    &context=`web`
    &element=`pdoResources`
    &parents=`[[*id]]`
    &depth=`1`

    <!-- Anzahl der geladenen Ressourcen (Accordion-Items): kommt aus [[+rows]] -->
    &limit=`[[+rows]]`

    <!-- Template für ein einzelnes Accordion-Item -->
    &tpl=`modxAccordionTpl`

    <!-- Wrapper-Chunk für das gesamte Accordion -->
    &tplWrapper=`modxAccordionWrapper`

    <!-- Seiteninhalt (content) mitladen -->
    &includeContent=`1`

    <!-- TVs verarbeiten und als Platzhalter verfügbar machen -->
    &processTVs=`1`
    &tvPrefix=``

    <!-- Versteckte oder unveröffentlichte Ressourcen ausschließen -->
    &showUnpublished=`0`
    &showHidden=`0`

    <!-- Sortierung nach Menüreihenfolge -->
    &sortby=`menuindex`
    &sortdir=`ASC`

    <!-- Benötigte TVs: Galerie, Downloads, Startdatum -->
    &includeTVs=`tvGalleryPfad,tvDownloadPfad,tvStartdatum`

    <!-- Anzahl der beim Laden geöffneten Accordion-Items: kommt aus [[+open]] -->
    &open=`[[+open]]`

    <!-- Maximale Textlänge für content: kommt aus [[+limit]] -->
    &wordLimit=`[[+limit]]`
]]

🔎 Erklärung:

  • &parents=[[*id]] → lädt die direkten Unterseiten der aktuellen Seite.
  • &limit=[[+rows]] → maximale Anzahl der geladenen Unterseiten; der Wert kommt aus dem Chunk-Aufruf (&rows=).
  • &includeTVs=... → lädt TVs für Galerie (tvGalleryPfad), Downloads (tvDownloadPfad) und Countdown (tvStartdatum).
  • &open=[[+open]] → steuert, wie viele Accordion-Einträge beim Laden geöffnet sind (idx <= open); der Wert kommt aus dem Chunk-Aufruf.
  • &wordLimit=[[+limit]] → begrenzt den ausgegebenen content auf eine maximale Zeichenlänge; der Wert kommt aus dem Chunk-Aufruf (&limit=), wobei das letzte Wort nicht abgeschnitten wird (Snippet limitWholeWords).

🧩 2. Chunk: modxAccordionWrapper

Der Wrapper erzeugt das äußere <div class="accordion">.

<div class="accordion" id="modxAccordion-[[*id]]">
    [[+output]]
</div>
  • [[*id]] sorgt für eine eindeutige ID pro Seite.
  • [[+output]] enthält alle generierten Accordion-Items.

🧩 3. Chunk: modxAccordionTpl

(Accordion-Item mit Galerie- und Download-Link)

<div class="accordion-item">
    <h2 class="accordion-header" id="heading-[[+id]]">

        <button class="accordion-button [[+idx:lte=`[[+open:default=`0`]]`:then=``:else=`collapsed`]]"
                type="button"
                data-bs-toggle="collapse"
                data-bs-target="#collapse-[[+id]]"
                aria-expanded="[[+idx:lte=`[[+open:default=`0`]]`:then=`true`:else=`false`]]"
                aria-controls="collapse-[[+id]]">
            [[+pagetitle]]
        </button>

    </h2>

    <div id="collapse-[[+id]]"
         class="accordion-collapse collapse [[+idx:lte=`[[+open:default=`0`]]`:then=`show`]]"
         role="region"
         aria-labelledby="heading-[[+id]]"
         data-bs-parent="#modxAccordion-[[*id]]">

        <div class="accordion-body">

            [[+tvGalleryPfad:notempty=`
                <p class="mb-3">
                    <a href="[[~[[+id]]]]" class="btn btn-sm btn-outline-primary">
                        <i class="bi bi-images"></i> Zur Bildergalerie
                    </a>
                </p>
            `]]

            [[+tvDownloadPfad:notempty=`
                <p class="mb-3">
                    <a href="[[~[[+id]]]]#downloads" class="btn btn-sm btn-outline-secondary">
                        <i class="bi bi-download"></i> Downloads
                    </a>
                </p>
            `]]

            [[+wordLimit:notempty=`
                [[+content:limitWholeWords=`[[+wordLimit]]`:process]]
            `:empty=`
                [[+content:process]]
            `]]

            [[!fcCountdownRow? &date=`[[+tvStartdatum]]` &minYear=`2025` &align=`right` &tpl=`fcCountdownRowTpl`]]

        </div>
    </div>
</div>

🔎 Erklärung der wichtigen Platzhalter / Logik:

  • [[+id]] → Ressourcen-ID; macht die Accordion-IDs eindeutig (z.B. heading-[[+id]], collapse-[[+id]]).
  • [[+pagetitle]] → Titel des Accordion-Eintrags; wird als Button-Text in der Accordion-Überschrift ausgegeben.
  • [[+idx]] → laufende Nummer des Eintrags (1, 2, 3, …); Grundlage für die Öffnungslogik (idx <= open) und damit für collapsed, show und aria-expanded.
  • [[+open]] → Wert aus &open= im Chunk-Aufruf; steuert, wie viele Einträge beim Laden geöffnet sind (Fallback über :default=0 im Template).
  • [[+content]] → vollständiger Content der Unterseite (Ressourceninhalt).
  • [[+content:process]] → wie [[+content]], aber MODX-Tags im Content (z.B. Chunks/Snippets) werden zusätzlich ausgeführt.
  • [[+wordLimit]] → Wert aus &limit= im Chunk-Aufruf; begrenzt den ausgegebenen Content auf eine maximale Länge, wobei das letzte Wort nicht abgeschnitten wird (Snippet limitWholeWords).
  • [[+content:limitWholeWords=[[+wordLimit]]:process]] → kürzt den Content und verarbeitet danach enthaltene MODX-Tags; ohne :process würden diese Tags als Text stehen bleiben.
  • [[+tvGalleryPfad]] → TV; wenn gefüllt, wird der Button „Zur Bildergalerie“ ausgegeben (notempty-Abfrage).
  • [[+tvDownloadPfad]] → TV; wenn gefüllt, wird der Button „Downloads“ ausgegeben (notempty-Abfrage).
  • [[+tvStartdatum]] → TV-Datum für den Countdown; wird an das Snippet fcCountdownRow übergeben.
  • [[+tvGalleryPfad:notempty=...]] / [[+tvDownloadPfad:notempty=...]] → bedingte Ausgabe: der jeweilige Block erscheint nur, wenn der TV-Wert nicht leer ist.
  • [[~[[+id]]]] → erzeugt den Link (URL) zur Detailseite der Ressource; wird für Galerie/Downloads als Ziel verwendet (bei Downloads zusätzlich mit #downloads).
  • data-bs-parent="#modxAccordion-[[*id]]" → sorgt dafür, dass sich die Panels innerhalb dieses Accordions gegenseitig schließen (Bootstrap-Accordion-Verhalten, eindeutig pro Seite durch [[*id]]).
  • aria-expanded="..." / aria-controls="..." / aria-labelledby="..." → Accessibility-Attribute; werden konsistent über die eindeutigen IDs (heading-[[+id]], collapse-[[+id]]) verbunden.
  • [[!fcCountdownRow? … ]] → Snippet zur Ausgabe eines Countdowns (z.B. bis zu einem Ereignisdatum), basierend auf tvStartdatum.

💡 Accordion-Öffnungslogik

Ein Eintrag wird geöffnet, wenn:

idx <= open

Beispiele:

  • open=0idx <= 0 → kein Eintrag offen → alles zu
  • open=1idx <= 1 → nur der erste Eintrag ist offen
  • open=3idx <= 3 → die ersten drei Einträge sind offen
  • open=999 → alle Einträge sind offen (sofern weniger vorhanden)

💡 Inhalt

  • Wenn wordLimit gesetzt ist → limitWholeWords kürzt den Inhalt auf die angegebene Wortanzahl (HTML bleibt grundsätzlich erhalten, kann aber theoretisch unsauber abgeschnitten werden).
  • Wenn wordLimit gesetzt ist → limitWholeWords kürzt den Inhalt auf die angegebene maximale Länge, wobei das letzte Wort nicht abgeschnitten wird. Hinweis: Durch das Kürzen per substr() kann HTML unvollständig werden.

  • Der Button „Zur Bildergalerie“ wird nur ausgegeben, wenn tvGalleryPfad gefüllt ist.
  • Der Link zeigt auf die jeweilige Unterseite ([[~[[+id]]]]), auf der die Galerie eingebunden ist.

  • Der Button „Downloads“ wird nur ausgegeben, wenn tvDownloadPfad gefüllt ist.
  • Der Link führt zur Download-Sektion der jeweiligen Unterseite ([[~[[+id]]]]#downloads).

💡 Countdown

  • Wird ausgegeben, wenn tvStartdatum gesetzt ist.
  • Der Countdown wird über fcCountdownRow erzeugt und unterhalb des Inhalts angezeigt.

🧪 4. Aufrufe im Content

4.1 Einfaches Accordion, alles zu, kompletter Content

[[$modxAccordion]]
  • open → Standard 0 → alle Einträge zu.
  • limit → leer → kompletter Content.
  • rows → nicht gesetzt → &limit=[[+rows]] ist leer; für einen Default muss im Chunk z.B. [[+rows:default=`20`]] verwendet werden.

4.2 Nur der erste Eintrag offen, kompletter Content

[[!$modxAccordion? &open=`1`]]
  • Eintrag 1 offen, Rest zu.
  • Voller Inhalt.

4.3 Erste drei Einträge offen, Inhalt auf 500 Zeichen gekürzt

[[!$modxAccordion? &open=`3` &limit=`500`]]
  • Einträge 1–3 offen.
  • Inhalt auf 500 Zeichen pro Eintrag begrenzt.

4.4 Maximal 10 Unterseiten, erster offen, viel Inhalt

[[!$modxAccordion? &rows=`10` &open=`1` &limit=`5000`]]
  • Maximal 10 Unterseiten im Accordion.
  • Erster Eintrag ist beim Laden offen.
  • Inhalt auf 5000 Zeichen begrenzt (praktisch Volltext).

✅ Voraussetzungen

  • pdoTools ist installiert (pdoPage, pdoResources).
  • TV tvGalleryPfad existiert und ist den Unterseiten zugewiesen (für den Galerie-Link).
  • TV tvDownloadPfad existiert und ist den Unterseiten zugewiesen (für den Download-Button).
  • TV tvStartdatum existiert und ist den Unterseiten zugewiesen (für den Countdown).
  • Bootstrap 5.3.8 (Spacelab) ist im Template eingebunden:
    • CSS (Bootswatch Spacelab)
    • JS (Bootstrap-Bundle, inkl. Collapse-Funktion)
  • Das Template der Seite gibt [[*content]] aus, damit der Chunk-Aufruf im Content angezeigt wird.

Optional: Accordion nur anzeigen, wenn eine TV (Radio Options: ja||nein) aktiv ist

[[*tvAccordion:is=`ja`:then=`
    [[!$modxAccordion? &rows=`10` &open=`1` &limit=`5000`]]
`:else=``]]