Manual · 12

Recipes

Main menu with active item

Snippet navigation:

<nav class="hauptmenue">
  <a href="/" {% if page.path == "/" %}aria-current="page"{% endif %}>Start</a>
  {% for p in nav() %}
    <a href="{{ p.path }}" {% if p.path == page.path %}aria-current="page"{% endif %}>{{ p.title }}</a>
  {% endfor %}
</nav>

The order matches the page tree; drafts don’t appear. In the CSS: .hauptmenue [aria-current] { font-weight: 700; }.

Submenu of a section

{% for p in children() %}
  <a href="{{ p.path }}">{{ p.title }}</a>
{% endfor %}

Team page from a Collection

Collection team with name, rolle, foto (image), text (Markdown), plus a component person:

{# Snippet "person" #}
<figure class="person">
  {{ image(foto, "(min-width: 800px) 25vw, 50vw") }}
  <figcaption><strong>{{ name }}</strong><br>{{ rolle }}</figcaption>
  {% slot %}{% endslot %}
</figure>
<div class="team">
  {% for p in data("team") %}
    {% component "person" name=p.name rolle=p.rolle foto=p.foto %}{{ p.text|markdown }}{% endcomponent %}
  {% empty %}
    <p>Das Team stellt sich bald vor.</p>
  {% endfor %}
</div>

Products from a shop

REST source produkte: URL https://shop.example.com/api/products?category={kat}&limit=12, header Authorization: Bearer {env.SHOP_TOKEN}, list path data.items, cache 600.

<form>
  <select name="kat" onchange="this.form.submit()">
    <option value="">Alle</option>
    <option value="schuhe" {% if route.query.kat == "schuhe" %}selected{% endif %}>Schuhe</option>
  </select>
</form>
{% for p in data("produkte", "kat", route.query.kat) %}
  <article>
    <img src="{{ p.image_url }}" alt="{{ p.name }}" loading="lazy">
    <h3>{{ p.name }}</h3>
    <p>{{ p.price|floatformat:2 }} €</p>
  </article>
{% endfor %}

Each category is its own cache entry – both for the REST request and in the page cache.

Upcoming events only

With today and a date comparison, past entries disappear on their own – without deleting them:

{% for e in data("events", "datum__gte", today, "sort", "datum") %}
  <h3>{{ e.titel }}</h3>
  <p>{{ e.datum|slice:"8:10" }}.{{ e.datum|slice:"5:7" }}.{{ e.datum|slice:"0:4" }}</p>
{% empty %}
  <p>Aktuell sind keine Termine geplant.</p>
{% endfor %}

An archive shows the same Collection with "datum__lt", today, "sort", "-datum".

Paginated list

Arithmetic is possible directly in expressions (seite - 1, (seite - 1) * 10); |integer turns the query parameter into a number.

{% with seite=route.query.seite|default:"1"|integer %}
  {% for post in data("blog", "sort", "-datum", "limit", 10, "offset", (seite - 1) * 10) %}
    …
  {% endfor %}
  {% if seite > 1 %}<a href="?seite={{ seite - 1 }}">Neuer</a>{% endif %}
  <a href="?seite={{ seite + 1 }}">Älter</a>
{% endwith %}

Page builder from blocks

The most convenient way is the built-in page builder with building blocks and {% blocks page.blocks %} (see 7.6). Without a schema it also works with a collection: Collection bloecke with seite (text), typ (choice: text, bild, zitat), inhalt (Markdown), bild (image). For each type, a Snippet block/text, block/bild, block/zitat that uses its parameters. On the page:

{% for b in data("bloecke", "seite", page.slug) %}
  {% component "block/"|add:b.typ inhalt=b.inhalt|markdown bild=b.bild %}{% endcomponent %}
{% endfor %}

Providing JSON for JavaScript

<script>
  const termine = {{ data("termine", "sort", "datum")|json }};
</script>

Multilingual sites

Everything important is in Multilingual websites: set the language on the page tree (it is inherited), link the versions, hreflang and sitemap come automatically, you build the language switcher with translations() and the menu per language with children(lang_root().id).

Contact forms

IllusionCMS does not process forms itself. Use a form service or your own API as the action target and include its script as a JS file.