Dokumentschema v17: Projektraster, verlinktes Bild, klebender Kopfbereich
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s

Alles aus dem Nachbau von kant-it.de, den Umut durchgesehen hat.

Eine Beitragsliste kann Datum, Autor, Auszug und Kategorie ausblenden und
sieht damit aus wie ein Projektraster statt wie ein Blogarchiv. Beinahe
lautlos danebengegangen: |default(true) macht in Twig aus einem
gespeicherten false ein true - die Einstellung haette sich speichern
lassen und nichts getan. Der Test prueft beide Richtungen.

Ein Bild darf verlinken, damit ein Logo auf die Startseite zeigt; die
Adresse geht durch dieselbe Pruefung wie jeder andere Link. Und der
Kopfbereich kann beim Scrollen oben bleiben - als Einstellung der
Website, weil nur das umschliessende Element kleben kann.

Der groesste Fund steckt im Editor: die Liste bekannter Schemafassungen
endete bei 12, waehrend Bausteine v13 bis v15 verlangen. In einem
aktuellen Dokument liess sich damit kein Baustein mehr einfuegen, und
Symbol, Fortschritt, Slider und externer Inhalt in gar keinem. Jetzt eine
Zahl an einer Stelle, mit einem Test ueber jeden Typ und jede Fassung.

Geprueft: 389 PHP-Tests unter 8.2 und 8.4, 18 JS-Tests, Editortest,
Browserpruefung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
kantarciandClaude Opus 5 committed 2026-09-13 00:02:23 +02:00
1 parent efa285c0d0
commit 70283db20a
16 files changed
+185 -12

No files matched your search

+1
View File
@@ -73,6 +73,7 @@
<textarea id="robotsExtra" name="robotsExtra" rows="3">{{ settings.robotsExtra }}</textarea>
<p class="field-help">Nur Kommentarzeilen und einfache Anweisungen wie <code>Disallow: /pfad</code>. Höchstens dreißig Zeilen.</p>
<div class="section-head"><h2>Einwilligung</h2><span class="muted">Nur nötig, wenn die Website etwas von Dritten lädt</span></div>
<label class="check-label" for="stickyHeader"><input id="stickyHeader" name="stickyHeader" type="checkbox" value="1"{{ settings.stickyHeader ? ' checked' : '' }}> Kopfbereich beim Scrollen oben halten</label>
<label class="check-label" for="consentBanner"><input id="consentBanner" name="consentBanner" type="checkbox" value="1"{{ settings.consentBanner ? ' checked' : '' }}> Einwilligungshinweis anzeigen</label>
<p class="field-help">Ohne eingebettete Inhalte anderer Anbieter braucht diese Website keine Einwilligung – dann ist ein Banner nur im Weg und sollte aus bleiben. Eingebettete Inhalte laden ohnehin erst nach Zustimmung, unabhängig von diesem Schalter.</p>
<fieldset class="field-set">
+1 -1
View File
@@ -17,7 +17,7 @@
<body class="kant{{ consentOpen ? ' consent-open' : '' }}">
<a class="skip-link" href="#main">Zum Inhalt springen</a>
{% if areas.header|default(null) %}
<header class="site-header">
<header class="site-header{{ siteSettings.load().stickyHeader ? ' is-sticky' : '' }}">
{% for block in areas.header.blocks %}{% include 'blocks/block.html.twig' with {block: block, postLists: {}, forms: {}, breadcrumbs: [], navigation: navigation|default({}), sections: sections|default({}), richText: true, eagerImage: null} only %}{% endfor %}
</header>
{% endif %}
+2 -2
View File
@@ -26,7 +26,7 @@
{% elseif type == 'button' %}
<a id="{{ block.id }}" class="button{{ designClasses }}" href="{{ props.href }}">{{ props.text }} <span aria-hidden="true">↗</span></a>
{% elseif type == 'image' %}
<figure id="{{ block.id }}" class="block-image{{ designClasses }}">{% set eager = eagerImage|default(null) == block.id %}<img src="{{ props.src }}" alt="{{ props.alt }}" width="{{ props.width }}" height="{{ props.height }}" loading="{{ eager ? 'eager' : 'lazy' }}"{{ eager ? ' fetchpriority="high"' : '' }} decoding="async"{% if props.sources|default([]) %} srcset="{% for source in props.sources %}{{ source.src }} {{ source.width }}w{% if not loop.last %}, {% endif %}{% endfor %}" sizes="(max-width: 650px) 100vw, (max-width: 1024px) 50vw, 800px"{% endif %}>{% if props.caption|default('') %}<figcaption>{{ props.caption }}</figcaption>{% endif %}</figure>
<figure id="{{ block.id }}" class="block-image{{ designClasses }}">{% set eager = eagerImage|default(null) == block.id %}{% if props.href|default('') %}<a class="image-link" href="{{ props.href }}">{% endif %}<img src="{{ props.src }}" alt="{{ props.alt }}" width="{{ props.width }}" height="{{ props.height }}" loading="{{ eager ? 'eager' : 'lazy' }}"{{ eager ? ' fetchpriority="high"' : '' }} decoding="async"{% if props.sources|default([]) %} srcset="{% for source in props.sources %}{{ source.src }} {{ source.width }}w{% if not loop.last %}, {% endif %}{% endfor %}" sizes="(max-width: 650px) 100vw, (max-width: 1024px) 50vw, 800px"{% endif %}>{% if props.href|default('') %}</a>{% endif %}{% if props.caption|default('') %}<figcaption>{{ props.caption }}</figcaption>{% endif %}</figure>
{% elseif type == 'iconcard' %}
<div id="{{ block.id }}" class="block-iconcard{{ designClasses }}">
{% include 'blocks/icon.html.twig' with {name: props.icon} only %}
@@ -195,7 +195,7 @@
{% endif %}
{% elseif type == 'postlist' %}
<div id="{{ block.id }}" class="block-postlist{{ designClasses }}">
{% include 'blocks/post-list.html.twig' with {posts: postLists[block.id]|default([])} only %}
{% include 'blocks/post-list.html.twig' with {posts: postLists[block.id]|default([]), showMeta: block.props.showMeta ?? true, showExcerpt: block.props.showExcerpt ?? true, showTerms: block.props.showTerms ?? true} only %}
</div>
{% elseif type == 'gallery' %}
<div id="{{ block.id }}" class="block-gallery{{ designClasses }}" role="group" aria-label="Bildergalerie">
+3 -3
View File
@@ -13,14 +13,14 @@
{% endif %}
<div class="post-body">
<h3><a href="{{ post.href }}">{{ post.title }}</a></h3>
{% if post.publishedAt or post.author %}
{% if (showMeta ?? true) and (post.publishedAt or post.author) %}
<p class="post-meta">
{% if post.publishedAt %}<time datetime="{{ post.publishedAt|date('Y-m-d') }}">{{ post.publishedAt|date('d.m.Y') }}</time>{% endif %}
{% if post.author %}<span>von {{ post.author }}</span>{% endif %}
</p>
{% endif %}
{% if post.excerpt %}<p class="post-excerpt">{{ post.excerpt }}</p>{% endif %}
{% if post.terms.category is not empty %}
{% if (showExcerpt ?? true) and post.excerpt %}<p class="post-excerpt">{{ post.excerpt }}</p>{% endif %}
{% if (showTerms ?? true) and post.terms.category is not empty %}
<p class="post-terms">{% for term in post.terms.category %}<a href="{{ term.href }}">{{ term.name }}</a>{% endfor %}</p>
{% endif %}
</div>
+1 -1
View File
@@ -39,7 +39,7 @@
{# Header and footer are block documents like any page, so they are built from elements
instead of being written into this template. #}
{% if areas.header|default(null) %}
<header class="site-header">
<header class="site-header{{ siteSettings.load().stickyHeader ? ' is-sticky' : '' }}">
{% for block in areas.header.blocks %}{% include 'blocks/block.html.twig' with {block: block, editing: editing|default(false), postLists: {}, forms: {}, breadcrumbs: [], navigation: navigation|default({}), sections: sections|default({}), richText: areas.header.schemaVersion|default(1) >= 12, eagerImage: eagerImage|default(null)} only %}{% endfor %}
</header>
{% endif %}