Manual · 6

Templates – lo básico

El HTML de la página, el Head, el título SEO, la descripción y los Snippets son templates. La sintaxis se corresponde en gran medida con Twig o Django (pongo2).

Salida

{{ page.title }}
{{ post.titel|upper }}
{{ preis|floatformat:2 }} €
{{ beschreibung|default:"Sin descripción" }}

Las salidas se escapan automáticamente como HTML: < se convierte en &lt;. Eso protege contra marcado roto y código inyectado. Para HTML que realmente deba aparecer como HTML:

  • Campos HTML: {{ post.inhalt|safe }}
  • Campos Markdown: {{ post.text|markdown }}

Condiciones y bucles

{% if page.slug == "kontakt" %}
  …
{% elif route.query.seite %}
  …
{% else %}
  …
{% endif %}

{% for p in data("team") %}
  <li class="{% if forloop.First %}erste{% endif %}">{{ forloop.Counter }}. {{ p.name }}</li>
{% empty %}
  <li>Todavía no hay nadie.</li>
{% endfor %}

En los bucles están disponibles forloop.Counter (desde 1), forloop.Counter0 (desde 0), forloop.First, forloop.Last y forloop.Revcounter.

Definir variables

{% with post=item("blog", "slug", route.slug) %}
  <h1>{{ post.titel }}</h1>
{% endwith %}

Comentarios

{# No se muestra #}

Espacios en blanco

Las etiquetas de template no modifican los espacios ni los saltos de línea: el texto se emite exactamente tal como está (igual que en Twig). Hallo {% if name %}{{ name }}{% endif %}! conserva el espacio después de «Hallo».

Mostrar sintaxis de template: verbatim

Si necesitas {{ … }} de forma literal, por ejemplo para Vue, Alpine o Handlebars, envuelve esa zona:

{% verbatim %}<div id="app">{{ nachricht }}</div>{% endverbatim %}

El importador añade verbatim automáticamente si el original contiene esas secuencias.

Variables disponibles

Variable Contenido
page.title, page.meta_title, page.slug, page.path, page.description, page.id, page.parent_id Página actual (meta_title y description ya están evaluados)
page.noindex, page.nofollow Ajustes de robots de la página (true/false)
page.lang Idioma efectivo de la página – propio o heredado, si no de (consulta Sitios multilingües)
route.path Ruta solicitada
route.slug Subruta en páginas Catch-All, p. ej. "mein-artikel" o "2025/rueckblick"
route.rest Subruta como lista: route.rest.0, route.rest.1 …
route.query.x Parámetro de consulta ?x=…
today Fecha de hoy como AAAA-MM-DD, a juego con los campos de fecha, p. ej. data("events", "datum__gte", today) para las citas futuras
now Momento actual para el filtro date: {{ now|date:"2006" }} (año en el copyright)
site.title, site.id, site.domain, site.domains, site.favicon El sitio web actual (su página de inicio): site.domain es el primer dominio registrado y site.favicon, la URL del icono del sitio web
preview true en la vista previa del admin

Funciones

Función Resultado
nav() Subpáginas publicadas de la página de inicio del sitio web actual (menú principal), sin las páginas con Ocultar en menús; nav(true) con ellas
children() / children(12) Subpáginas publicadas de la página actual o de la página 12, sin las ocultas; children(true) / children(12, true) con ellas
lang_root() / lang_root(12) Página de inicio del árbol de idioma de la página actual o de la página 12: la propia página o la más cercana por encima con su propio idioma; si no, la página de inicio del sitio. Para menús por idioma: children(lang_root().id)
data("slug", …) Entradas de una Collection o resultado de una fuente REST (consulta Datos)
item("slug", "feld", wert) Primera entrada con feld == wert, o nada
workflow("pfad", …) Resultado de un Workflow con entrada HTTP en esa ruta
image(id, sizes, klasse) <img> responsivo con srcset, dimensiones y texto alternativo; en JPEG/PNG, dentro de <picture> con WebP
file(id) Información del archivo: .url, .name, .alt, .width, .height, .srcset, .webp_srcset, .mime, .size
asset_url(id) URL versionada de un archivo CSS/JS
translations() / translations(entrada) Versiones de idioma publicadas de la página o de una entrada, ordenadas por código de idioma: cada una con lang, title, url, current – para selectores de idioma
language_name("fr") Nombre de un idioma en ese mismo idioma («Français», «Deutsch» …); los códigos desconocidos se quedan como están
not_found() Termina el renderizado con la página 404 (estado 404)

Cada página de nav()/children() (y lang_root()) tiene title, path, slug, id, description y lang, además de hidden (Ocultar en menús). Ejemplo de pie de página con aviso legal y privacidad, que no aparecen en el menú principal:

<footer>{% for p in nav(true) %}{% if p.hidden %}<a href="{{ p.path }}">{{ p.title }}</a> {% endif %}{% endfor %}</footer>

Filtros útiles

Filtro Ejemplo
default {{ x|default:"–" }}
upper, lower, title, capfirst {{ name|upper }}
truncatechars, truncatewords {{ text|truncatechars:120 }}
floatformat {{ preis|floatformat:2 }}
length {{ liste|length }}
join {{ tags|join:", " }}
safe Emitir HTML sin filtrar
markdown Markdown a HTML (markdown:"html" deja pasar el HTML incrustado; ver más abajo)
json Valor como JSON, p. ej. para JavaScript: <script>const cfg = {{ cfg|json }};</script>
urlencode <a href="/suche?q={{ q|urlencode }}">

Markdown directamente en el HTML

Los textos largos se escriben más cómodamente en Markdown, también en medio del HTML de una página o de un Snippet. Envuelve la zona con {% filter markdown %}:

<main class="container">
{% filter markdown %}
# Sobre nosotros

Diseñamos y desarrollamos **sitios web con personalidad**, desde la idea hasta la puesta en marcha.
Más información en [Servicios](/leistungen): el equipo de {{ site.title }} te espera.

- Asesoramiento
- Implementación
{% endfilter %}
</main>
  • Las variables y etiquetas de template funcionan dentro del bloque.
  • Los títulos reciben anclas para enlaces de salto, y las diéresis se transcriben: «Über uns» → #ueber-uns, «Größe» → #groesse.
  • HTML dentro del Markdown: el filtro normal descarta el HTML incrustado (<div …>), porque también procesa contenidos de Collections y fuentes REST que pueden venir de fuera. Para los textos que escribes tú mismo en el editor, {% filter markdown:"html" %} deja pasar el HTML, por ejemplo para un <div class="hinweis"> entre párrafos. Para datos externos, |markdown sigue siendo la opción segura.

Pens – zonas de pruebas

En Pens creas pequeñas zonas de pruebas, como en CodePen: HTML (con todas las posibilidades de los templates: data(), item(), workflow(), filtros …), CSS y JS uno junto a otro, y debajo el resultado, en vivo mientras escribes. Muy útil para probar templates con datos reales, para prototipos o para micrositios pequeños.

  • Cada Pen tiene su propia dirección imposible de adivinar: /cms-admin/pen/<uuid>. Con la sesión iniciada abre el editor (pantalla completa) y Ctrl+S guarda. Arriba cambias el diseño: Código arriba (uno junto a otro) o Código al lado (apilado a la izquierda, resultado a la derecha); Pantalla completa muestra solo el resultado ocupando toda la pantalla (Esc para salir).
  • Público (interruptor de arriba): sin iniciar sesión, la misma dirección muestra el resultado y, al lado, el código, solo para lectura, en pestañas HTML/CSS/JS. Con Mostrar código desactivado, la dirección es una página independiente: solo el resultado, con el título del Pen; práctico para páginas sencillas rápidas. Los Pens no públicos no existen para los visitantes (404). Como administrador ves la vista de los visitantes con Vista de visitante (pestaña nueva, ?view=1).
  • Los Pens son siempre noindex, nofollow (metaetiqueta y cabecera X-Robots-Tag) y no aparecen en ningún sitemap.
  • El resultado se ejecuta en un sandbox con origen propio: los scripts del Pen no llegan a tu sesión de administración.
  • Para los visitantes solo se usan entradas de Collection publicadas; en el editor ves también los borradores, como en la vista previa. site y nav() se refieren al sitio web del dominio solicitado.
  • Los Pens forman parte de los Bundles; no tienen historial de versiones.