Handbuch · 9

Daten: Collections und REST-Quellen

Beide Arten von Datenquellen nutzt du im Template gleich: data("slug").

9.1 Collections

Eine Collection ist eine eigene Datenstruktur mit Feldern – z. B. Blog mit Titel, Datum, Bild und Text.

Anlegen: Collections → + Neu → Name und Slug (der Slug ist der Name für data("…")). Im Tab Schema legst du die Felder an:

Feldtyp Eingabe Im Template
Text, Mehrzeiliger Text, URL Textfeld {{ item.feld }}
Markdown Markdown-Editor mit Vorschau {{ item.feld|markdown }}
HTML Code-Editor {{ item.feld|safe }}
Zahl Zahlenfeld {{ item.feld }}, {{ item.feld|floatformat:2 }}
Ja/Nein Checkbox {% if item.feld %}…{% endif %}
Datum Datumsfeld (gespeichert als JJJJ-MM-TT) {{ item.feld }}
Auswahl Liste fester Optionen {{ item.feld }}
Bild Auswahl aus der Dateiverwaltung {{ image(item.feld) }}
Datei Auswahl aus der Dateiverwaltung {{ file(item.feld).url }}
Verknüpfung (ein Eintrag) Auswahl eines Eintrags einer anderen Collection {{ item.feld.name }}
Verknüpfungen (mehrere) Einträge hinzufügen, entfernen, sortieren {% for x in item.feld %}{{ x.name }}{% endfor %}
Blöcke Formular-Editor für Blöcke aus Bausteinen (siehe 7.6) {% blocks item.feld %}

Der Feldname (z. B. titel) ist der Name im Template, die Bezeichnung das, was im Formular steht. Pflicht erzwingt einen Wert.

Benennst du ein Feld um, behalten vorhandene Einträge ihre alten Werte nur bis zum nächsten Speichern des Eintrags. Plane Feldnamen deshalb möglichst früh.

Sprache der Einträge: Im Schema legst du fest, in welcher Sprache die Einträge einer Collection sind. Nur dann lassen sich Einträge mit Einträgen anderer Sprachen verknüpfen – siehe Mehrsprachige Websites.

Verknüpfungen zwischen Collections: Mit den Feldtypen Verknüpfung und Verknüpfungen zeigt ein Eintrag auf Einträge einer anderen (oder derselben) Collection. Die Ziel-Collection wählst du im Schema neben dem Typ. Ein Blogartikel hat so einen Autor (1:n), und Artikel und Tags können sich gegenseitig vielfach zuordnen (n:m). Gespeichert werden nur die IDs. In data() und item() sind die Verknüpfungen schon aufgelöst:

{% for a in data("blog") %}
  <h2>{{ a.titel }}</h2>
  <p>von {{ a.autor.name }} · {% for t in a.tags %}#{{ t.name }} {% endfor %}</p>
{% endfor %}

Rückwärts, also „alle Artikel dieses Autors“ oder „alle Artikel mit diesem Tag“, filterst du die andere Collection nach der ID. Bei Verknüpfungen (mehrere) bedeutet der Vergleich „enthält“, mit __ne „enthält nicht“:

{% for x in data("blog", "autor", autor.id) %}…{% endfor %}
{% for x in data("blog", "tags", tag.id, "sort", "-datum") %}…{% endfor %}
  • Aufgelöst wird eine Ebene: Die Tags eines Artikels sind ganze Einträge, deren eigene Verknüpfungen aber nur IDs. So bilden gegenseitige Verknüpfungen keine Schleife. Eine Ebene tiefer kommst du mit data() und dem Filter.
  • Gelöschte und, für Besucher, unveröffentlichte Einträge fallen weg. Eine Verknüpfung ist dann leer, und Verknüpfungen enthalten nur die übrigen Einträge. In der Vorschau sind Entwürfe dabei.
  • Im Tab Verwendung stehen passende Beispiele, auch für die Rückrichtung („Verknüpft von“). Das Panel Template-Daten im Seiten-Editor zeigt die aufgelösten Einträge.
  • Die REST-API (/collections/…/items) liefert die IDs. GET /data/{slug} liefert dasselbe wie data() im Template, also aufgelöst.
  • CSV: Der Export schreibt die IDs (mehrere mit Komma). Der Import nimmt IDs oder den Wert eines Textfelds des Ziel-Eintrags, bevorzugt den Slug. So passen Webflow-Exporte, die Verknüpfungen als Slugs ausgeben. Mehrere Werte trennst du mit Komma oder Semikolon, Unbekanntes wird als Hinweis gemeldet.

Ordner: Im Tab Schema kannst du einer Collection einen Ordner geben, z. B. den Namen eines Projekts. Die Liste links gruppiert danach, und jeder Ordner lässt sich zuklappen. Ordner dienen nur der Übersicht und ändern nichts an data("…"). Snippets und CSS/JS-Dateien haben dasselbe Feld neben dem Namen.

Einträge pflegst du im Tab Einträge: + Eintrag, bearbeiten per Doppelklick oder Bearbeiten, Reihenfolge mit den Pfeilen, Veröffentlicht pro Eintrag. Unveröffentlichte Einträge erscheinen nur in der Vorschau.

Im Tab Verwendung zeigt die Collection fertige Template- und API-Beispiele. Mit Öffentlich lesbar über die REST-API können JavaScript-Clients die veröffentlichten Einträge ohne Anmeldung abrufen – auch von anderen Domains aus (CORS ist dann automatisch freigegeben).

CSV-Import und -Export: Im Tab Einträge lädt CSV exportieren alle Einträge (auch Entwürfe) als CSV-Datei herunter – Spalten id, published und dann die Felder; UTF-8 mit BOM, damit Excel Umlaute richtig anzeigt. CSV importieren nimmt eine CSV-Datei (UTF-8, Trennzeichen Komma, Semikolon oder Tab werden erkannt) und ordnet ihre Spalten den Feldern zu – automatisch nach Feldname oder Bezeichnung, änderbar je Spalte. Eine Vorschau zeigt die ersten Einträge so, wie sie gespeichert werden, und listet alle Fehler mit Zeile und Spalte; solange es Fehler gibt, wird nichts importiert. Importiert wird alles oder nichts, neue Einträge kommen ans Ende; Bisherige Einträge ersetzen löscht vorher alle vorhandenen.

  • Abgleich statt Anhängen: Unter Abgleich wählst du ein Feld mit eindeutigen Werten, meist den Slug. Gibt es schon einen Eintrag mit demselben Wert, wird er aktualisiert – nur die zugeordneten Spalten, alles andere (auch der Status, wenn keine Status-Spalte zugeordnet ist) bleibt; sonst wird ein neuer angelegt. Mit Einträge löschen, die nicht in der Datei stehen wird daraus ein vollständiger Abgleich: Einträge behalten ihre ID, nur was in der Datei fehlt, verschwindet. Die Vorschau zeigt je Zeile neu oder ändert #ID und oben das Ergebnis (z. B. „1 neu · 2 aktualisiert · 1 gelöscht“). Doppelte Werte in der Datei oder in der Collection sind Fehler.

  • In Excel bearbeiten: Exportieren, die Datei bearbeiten (Zeilen ändern, neue Zeilen mit leerer id ergänzen, Zeilen streichen) und wieder importieren – die Spalte id wird automatisch als Eintrags-ID erkannt und als Abgleich vorgeschlagen. Eine unbekannte ID ist ein Fehler. Nimm dafür einen frischen Export: Wird der neueste Eintrag gelöscht, kann ein später angelegter dessen ID bekommen.

  • Neue Collection aus CSV: Collections → CSV (neben + Neu). IllusionCMS schlägt Name, Slug und für jede Spalte Feldname und Typ vor (Zahl, Ja/Nein, Datum, URL, HTML, Text …) – alles vor dem Import änderbar, Spalten lassen sich ignorieren.

  • Webflow-Exporte: Die Verwaltungsspalten (Collection ID, Item ID, Created On …) werden ignoriert, Draft und Archived bestimmen den Status (true = Entwurf). Für andere Dateien kannst du eine Spalte mit ja/nein selbst als Status: online oder Status: Entwurf verwenden; ohne solche Spalte sind alle Einträge veröffentlicht.

  • Werte: Zahlen dürfen deutsch (1.234,50) oder englisch (1,234.50) geschrieben sein – 1,5 gilt als 1,5. Ja/Nein versteht ja/nein, true/false, 1/0, x. Daten werden aus 2025-10-02, 02.10.2025, ISO-Zeitstempeln und dem Webflow-Format zu JJJJ-MM-TT. Werte mit führender Null (Postleitzahlen) schlägt der Import als Text vor, nicht als Zahl.

  • Bilder und Dateien: Eine Bild- oder Datei-Spalte enthält entweder die ID einer Datei oder die Adresse einer Datei, die schon per Website-Import übernommen wurde – so finden die Bild-URLs eines Webflow-Exports die importierten Bilder. Andere Adressen bleiben leer (die Vorschau zeigt sie als Hinweis); willst du die Adresse behalten, nimm den Typ URL.

  • Der Import löst keine Workflow-Ereignisse aus – bei tausend Zeilen wären es sonst tausend Workflow-Läufe (z. B. Benachrichtigungen).

Live-Daten: Manche Collections füllen sich auf dem Live-Server von selbst – z. B. Kontaktanfragen aus einem Workflow. Setzt du im Schema den Haken Live-Daten, bleiben ihre Einträge auf dem Ziel erhalten, wenn du ein Bundle von lokal hochlädst; die Testeinträge deiner lokalen Instanz gehen nicht mit. Das Schema (Felder, Name) kommt trotzdem vom lokalen Stand. In der Liste tragen solche Collections das Abzeichen Live.

Singleton: Für Dinge, die es genau einmal gibt – Website-Einstellungen, Farbcodes, Kontaktdaten, Öffnungszeiten – im Schema Singleton anhaken. Die Collection hält dann genau einen Eintrag; statt einer Liste siehst du unter Inhalt gleich das Formular. Im Template liefert data() den Eintrag direkt als Objekt:

{% set s = data("einstellungen") %}
<header style="--primaer: {{ s.primaerfarbe }}">{{ s.firmenname }} · {{ s.telefon }}</header>

Auch die API (GET /api/v1/collections/einstellungen/items, /api/v1/data/einstellungen) liefert ein Objekt; ändern lässt er sich per PUT /api/v1/collections/einstellungen/item. Ein zweiter Eintrag ist nicht möglich, ebenso kein CSV-Import. Umschalten geht nur, solange die Collection höchstens einen Eintrag hat.

Detailseite und Vorschau: Erscheinen die Einträge auf einer Catch-All-Seite (z. B. /blog/<slug>), wähle sie im Schema unter Detailseite und das Feld mit dem URL-Teil (meist slug). Beim Bearbeiten eines Eintrags steht dann rechts die Vorschau dieser Seite – mit dem noch ungespeicherten Stand, also live beim Tippen, umschaltbar Desktop/Tablet/Mobil; Öffnen ↗ zeigt den gespeicherten Eintrag auf der Website.

9.2 data() und item()

{% for post in data("blog") %}…{% endfor %}

Parameter folgen als Paare aus Name und Wert:

Parameter Wirkung Beispiel
sort Sortieren, - = absteigend data("blog", "sort", "-datum")
limit Höchstens n Einträge data("blog", "limit", 3)
offset Die ersten n überspringen data("blog", "offset", 10, "limit", 10)
jedes Feld Filtern auf Gleichheit data("produkte", "kategorie", "schuhe")
feld__gt, __gte, __lt, __lte Größer / größer-gleich / kleiner / kleiner-gleich. Zahlen werden als Zahlen verglichen, Datumsfelder (JJJJ-MM-TT) chronologisch; Einträge ohne Wert fallen heraus data("events", "datum__gte", today)
feld__ne Ungleich data("blog", "kategorie__ne", "intern")

Zusätzlich gibt es die Felder id, _created und _updated (Unix-Zeit) – z. B. "sort", "-_created" für „neueste zuerst“. Werte aus Variablen funktionieren ebenso: data("produkte", "kategorie", route.query.kat).

Einen einzelnen Eintrag findest du mit item():

{% with p=item("produkte", "slug", "sneaker-weiss") %}{{ p.name }}{% endwith %}

9.3 REST-Quellen

REST-Quellen binden beliebige JSON-APIs an – Shop, CRM, Ticketsystem, Headless-CMS, eigene Dienste. Das CMS ruft die API beim Rendern ab, extrahiert die Liste und speichert das Ergebnis eine Weile zwischen.

Anlegen: REST-Quellen → + Neu:

Feld Bedeutung
Name / Slug Slug ist der Name für data("…")
Methode / URL GET oder POST, absolute http(s)-URL
Header z. B. Authorization: Bearer …
Body JSON bei POST
Listen-Pfad Wo in der Antwort die Liste steht, z. B. data.items (leer = ganze Antwort)
Cache Wie lange das Ergebnis wiederverwendet wird (Sekunden, 0 = nie)
Timeout Maximale Wartezeit (1–60 Sekunden)

Platzhalter machen Abrufe flexibel:

  • {name} in URL, Body oder Header wird aus dem Template gefüllt: URL https://shop.example.com/api/products?cat={kat} → data("produkte", "kat", "schuhe").
  • {env.NAME} liest eine Umgebungsvariable des Servers. So gehören Zugangsdaten nicht in die Datenbank: Header Authorization: Bearer {env.SHOP_TOKEN}, Server gestartet mit SHOP_TOKEN=… ./illusioncms.

Testen: Rechts Abruf testen zeigt Status, Dauer und die Daten. Unter Listen im Ergebnis stehen alle Stellen, an denen die Antwort Listen enthält – ein Klick übernimmt den Pfad. Darunter steht ein fertiges Template-Beispiel mit den gefundenen Feldern.

Gut zu wissen:

  • Schlägt ein Abruf fehl (Fehlerstatus, Timeout, ungültiges JSON), kann die Seite nicht gerendert werden. Eingeloggt siehst du die genaue Ursache.
  • Eine Seite mit REST-Daten bleibt höchstens so lange im Seiten-Cache wie die Cache-Dauer der Quelle.
  • Wer REST-Quellen anlegen darf, kann den Server beliebige Adressen abrufen lassen – auch im internen Netz.