Skip to content

Templating

Inhalt dieser Seite:

Guppy verfolgt einen komponentenbasierten Ansatz, um eine saubere Trennung von Logik und Darstellung zu gewährleisten. Unser Ziel ist es, ein System zu schaffen, das sowohl wartungsfreundlich als auch zukunftssicher ist. Um dies zu erreichen, setzen wir auf dynamische und modulare Mechanismen, wie sie auch in der Gestaltung von Templates zum Einsatz kommen. Dies ermöglicht uns, individuelle Anpassungen vorzunehmen, ohne die Kernfunktionen von Shopware 6 zu beeinträchtigen. Durch diese Methodik bleibt Guppy vollständig updatefähig und reduziert langfristig Wartungsaufwand.

Warum dieser Ansatz?

Shopware 6 ist ein mächtiges Framework, dessen Updatefähigkeit und Flexibilität durch unser Vorgehen bestmöglich erhalten bleiben. Die dynamische Handhabung von Konfigurationen ermöglicht:

  1. Maximale Anpassbarkeit: Unterschiedliche Anforderungen können durch gezielte Konfigurationen erfüllt werden, ohne den Kerncode zu modifizieren.
  2. Modularität: Komponenten wie Footer, Header oder Widgets werden als eigenständige Module behandelt, was ihre Wiederverwendbarkeit erhöht.
  3. Upgrade-Kompatibilität: Da wir uns an die Richtlinien von Shopware 6 halten und spezifische Anpassungen in separaten Dateien vornehmen, bleiben künftige Updates des Systems reibungslos anwendbar.
  4. Barrierefreiheit: Durch modulare Templates lassen sich barrierefreie Anpassungen gezielt und flexibel integrieren, ohne globalen Code anzupassen.

Theme-Integration

Guppy nutzt die Theme-Konfiguration (theme.json) als zentrale Steuerungsinstanz für dynamische Anpassungen von Komponenten. Die Konfiguration ermöglicht es, spezifische Designentscheidungen direkt über die Theme-Einstellungen vorzunehmen, ohne tief in den Code eingreifen zu müssen.

Vorteile

Die Verwendung von theme.json erlaubt es, wichtige Einstellungen wie den Footer-Typ flexibel zu definieren. Dies bringt folgende Vorteile:

  1. Klarheit und Struktur: Alle Anpassungen werden an einer zentralen Stelle verwaltet.
  2. Wartungsfreundlichkeit: Änderungen können einfach durch Anpassungen der theme.json vorgenommen werden, ohne den Template-Code zu berühren.
  3. Erweiterbarkeit: Neue Konfigurationsmöglichkeiten können einfach hinzugefügt werden, was das System zukunftssicher macht.
  4. Upgrade-Kompatibilität: Anpassungen erfolgen auf Basis von Shopware-Konventionen, was Konflikte bei zukünftigen Updates minimiert.

Funktionsweise (am Beispiel des Footers)

Der Code für den Footer berücksichtigt die Einstellungen in der theme.json, indem er die Funktion theme_config() verwendet. Diese liest die in der theme.json definierten Werte aus.

Beispielcode:

twig
{% if theme_config('guppy-footer') != "default" %}
    {% set configFooter = theme_config('guppy-footer') %}
{% endif %}

INFO

Erklärung Die Funktion theme_config('guppy-footer') überprüft, ob in der theme.json eine spezifische Footer-Konfiguration (guppy-footer) definiert wurde.

Ergänzung im Footer-Template:

twig
{# src/Resources/views/storefront/base.html.twig #}

{% block base_footer %}
    <footer class="footer-main{% if configFooter %} footer-main-{{ configFooter }} pt-md-3 pt-4{% endif %}">
        {% block base_footer_inner %}
            {% if configFooter %}
                {% sw_include '@Storefront/storefront/layout/footer/footer-' ~ configFooter ~ '.html.twig' %}
            {% else %}
                {{ parent() }}
            {% endif %}
        {% endblock %}
    </footer>
{% endblock %}

Beispielhafte Konfiguration in theme.json:

json
// src/Resources/theme.json

{
  ...
  "config": {
    ...
    "fields": {
        ...
        "guppy-footer": {
            "label": {
                "en-GB": "Footer variant",
                "de-DE": "Footer Variante"
            },
            "type": "text",
            "value": "guppy-default",
            "custom": {
                "componentName": "sw-single-select",
                "options": [
                    {
                        "value": "default",
                        "label": {
                            "en-GB": "Shopware Default",
                            "de-DE": "Shopware Standard"
                        }
                    },
                    {
                        "value": "guppy-default",
                        "label": {
                            "en-GB": "Guppy Default",
                            "de-DE": "Guppy Standard"
                        }
                    }
                ]
            },
            "editable": true,
            "tab": "footer",
            "block": "layoutFooter",
            "order": 100
        }
    }
  }
}

Erweiterung der Template-Logik

Die in der theme.json ausgewählte Footer-Konfiguration guppy-default erfordert ein spezifisches Template mit dem Namen footer-guppy-default.html.twig. Dieses Template wird automatisch geladen, wenn der Wert guppy-default in der Theme-Konfiguration gesetzt wird. Das neue Template wird von der Standardvorlage footer.html.twig abgeleitet, um Änderungen spezifisch und modular zu halten.

Beispielcode für das Template:

twig
{# src/Resources/views/storefront/layout/footer/footer-guppy-default.html.twig #}

{% sw_extends '@Storefront/storefront/layout/footer/footer.html.twig' %}

// Hier Inhalt

INFO

Durch die Integration von Theme-Variablen wie theme_config('guppy-footer') bleibt Guppy hochgradig anpassbar und gleichzeitig kompatibel mit zukünftigen Shopware-Updates. Die Theme-Konfiguration erlaubt es Entwicklern und Admins, Änderungen schnell und effizient vorzunehmen, ohne tief in die Codebasis eingreifen zu müssen.


Template-Varianten-System

Das Guppy Theme implementiert ein umfassendes Varianten-System für verschiedene Komponenten:

Header-Varianten

Der Header kann in verschiedenen Varianten dargestellt werden:

twig
{% if theme_config('guppy-header') != "default" %}
    {% set configHeader = theme_config('guppy-header') %}
{% endif %}

{% block base_header %}
    <header class="header-main{% if configHeader %} header-variant-{{ configHeader }}{% endif %}">
        {% block base_header_inner %}
            {% if configHeader %}
                {% sw_include '@Storefront/storefront/layout/header/header-' ~ configHeader ~ '.html.twig' %}
            {% else %}
                {{ parent() }}
            {% endif %}
        {% endblock %}
    </header>
{% endblock %}

Verfügbare Header-Varianten:

  • default: Shopware Standard-Header
  • compact: Guppy Standard - Kompakte Header-Variante
  • extended: Erweiterte Header-Variante mit Top-Bar
  • simple: Minimalistische Header-Variante

Theme-Konfiguration:

json
"guppy-header": {
    "type": "text",
    "value": "extended",
    "custom": {
        "componentName": "sw-single-select",
        "options": [
            {"value": "default", "label": {"de-DE": "Shopware Standard"}},
            {"value": "compact", "label": {"de-DE": "Guppy Standard"}},
            {"value": "extended", "label": {"de-DE": "Erweitert"}},
            {"value": "simple", "label": {"de-DE": "Simpel"}}
        ]
    }
}

Die Navigation unterstützt verschiedene Flyout-Varianten:

twig
{% if theme_config('guppy-navigation') != "content" %}
    {% set navigationStyle = theme_config('guppy-navigation') %}
{% endif %}

{% block base_navigation %}
    <nav class="nav-main{% if navigationStyle %} nav-{{ navigationStyle }}{% endif %}">
        {% sw_include '@Storefront/storefront/layout/navbar/' ~ (navigationStyle ?: 'content') ~ '.html.twig' %}
    </nav>
{% endblock %}

Verfügbare Navigation-Varianten:

  • content: Shopware Standard-Navigation
  • content-compact: Kompakte Navigation mit optimierter Darstellung

Produktkarten-System

Das Produktkarten-System bietet verschiedene Darstellungsvarianten:

twig
{% if theme_config('guppy-productcard-config') %}
    {% set boxDesign = theme_config('guppy-productcard-config') %}
{% endif %}

<article class="card product-box box-{{ layout }}{% if boxDesign %} box-{{ boxDesign }}{% endif %}">
    <!-- Produktkarten-Inhalt -->
</article>

Verfügbare Produktkarten-Varianten:

  • default: Shopware Standard-Produktkarte
  • guppy-default: Guppy Standard - Barrierefreie Produktkarte

Erweiterte Produktkarten-Konfiguration:

json
"guppy-productcard-protective-frame": true,
"guppy-productcard-image-object-fit": "contain"

Login & Register-Varianten

Login- und Registrierungsseiten können kompakt dargestellt werden:

twig
{% if theme_config('guppy-login-register') == "compact" %}
    {% set loginStyle = "compact" %}
{% endif %}

{% block page_account_login %}
    <div class="account-login{% if loginStyle %} account-login-{{ loginStyle }}{% endif %}">
        <!-- Login-Inhalt -->
    </div>
{% endblock %}

Checkout-Varianten

Der Checkout-Prozess unterstützt verschiedene Darstellungsformen:

twig
{% if theme_config('guppy-checkout') == "compact" %}
    {% set checkoutStyle = "compact" %}
{% endif %}

{% block page_checkout %}
    <div class="checkout-main{% if checkoutStyle %} checkout-{{ checkoutStyle }}{% endif %}">
        <!-- Checkout-Inhalt -->
    </div>
{% endblock %}

Template-Struktur

Die vollständige Template-Hierarchie des Guppy Themes:

src/Resources/views/storefront/
├── base.html.twig                           # Basis-Template mit Skip-Links
├── layout/
│   ├── header.html.twig                     # Header-Haupttemplate
│   ├── header/
│   │   ├── header-compact.html.twig         # Kompakte Header-Variante
│   │   ├── header-extended.html.twig        # Erweiterte Header-Variante
│   │   ├── header-simple.html.twig          # Einfache Header-Variante
│   │   ├── logo.html.twig                   # Logo-Komponente
│   │   ├── search.html.twig                 # Suchkomponente
│   │   └── top-bar-extended.html.twig       # Erweiterte Top-Bar
│   ├── footer.html.twig                     # Footer-Haupttemplate
│   ├── footer/
│   │   └── footer-guppy-default.html.twig   # Guppy-Footer-Variante
│   ├── navbar/
│   │   ├── navbar.html.twig                 # Navbar-Haupttemplate
│   │   ├── content.html.twig                # Standard-Navigation
│   │   └── content-compact.html.twig        # Kompakte Navigation
│   ├── breadcrumb.html.twig                 # Breadcrumb-Navigation
│   └── sidebar/
│       └── category-navigation-onelevel.html.twig
├── component/
│   ├── product/
│   │   ├── card/
│   │   │   ├── box-standard.html.twig       # Standard-Produktkarte
│   │   │   ├── box-landscape.html.twig      # Landscape-Produktkarte
│   │   │   ├── badges.html.twig             # Produkt-Badges
│   │   │   ├── box-image.html.twig          # Produktbild-Komponente
│   │   │   ├── action.html.twig             # Produkt-Aktionen
│   │   │   └── price-unit.html.twig         # Preis-Komponente
│   │   ├── listing.html.twig                # Produktlisting
│   │   ├── description.html.twig            # Produktbeschreibung
│   │   ├── properties.html.twig             # Produkteigenschaften
│   │   └── properties-offcanvas.html.twig   # Eigenschaften-Offcanvas
│   ├── buy-widget/
│   │   ├── buy-widget.html.twig             # Buy-Widget-Hauptkomponente
│   │   ├── buy-widget-form.html.twig        # Buy-Widget-Formular
│   │   └── buy-widget-price.html.twig       # Buy-Widget-Preis
│   ├── account/
│   │   ├── login.html.twig                  # Login-Komponente
│   │   └── register.html.twig               # Registrierung-Komponente
│   ├── checkout/
│   │   ├── offcanvas-cart.html.twig         # Offcanvas-Warenkorb
│   │   └── offcanvas-cart-summary.html.twig # Warenkorb-Zusammenfassung
│   ├── line-item/
│   │   ├── element/
│   │   │   ├── quantity.html.twig           # Mengenauswahl
│   │   │   ├── remove.html.twig             # Entfernen-Button
│   │   │   └── total-price.html.twig        # Gesamtpreis
│   │   └── type/
│   │       └── product.html.twig            # Produkt-Line-Item
│   ├── address/
│   │   └── address-form.html.twig           # Adress-Formular
│   ├── listing/
│   │   └── filter-panel.html.twig           # Filter-Panel
│   └── delivery-information.html.twig       # Lieferinformationen
├── element/
│   ├── cms-element-buy-box.html.twig        # Buy-Box-Element
│   ├── cms-element-image-gallery.html.twig  # Bildergalerie-Element
│   ├── cms-element-product-listing.html.twig # Produktlisting-Element
│   ├── cms-element-sidebar-filter.html.twig  # Sidebar-Filter-Element
│   ├── cms-element-splide-slider.html.twig   # Splide-Slider-Element
│   ├── cms-element-category-navigation-onelevel.html.twig # Kategorienavigation
│   └── cms-element-product-description-reviews.html.twig  # Produktbeschreibung
├── page/
│   ├── account/
│   │   ├── _page.html.twig                  # Account-Basis-Template
│   │   ├── sidebar.html.twig                # Account-Sidebar
│   │   ├── profile/
│   │   │   └── index.html.twig              # Profil-Seite
│   │   ├── register/
│   │   │   └── index.html.twig              # Registrierung-Seite
│   │   └── order-history/
│   │       └── index.html.twig              # Bestellhistorie
│   ├── checkout/
│   │   ├── _page.html.twig                  # Checkout-Basis-Template
│   │   ├── cart/
│   │   │   └── index.html.twig              # Warenkorb-Seite
│   │   ├── confirm/
│   │   │   └── index.html.twig              # Bestätigungsseite
│   │   ├── finish/
│   │   │   ├── index.html.twig              # Abschlussseite
│   │   │   └── finish-details.html.twig     # Abschluss-Details
│   │   ├── address/
│   │   │   ├── index.html.twig              # Adress-Seite
│   │   │   └── register.html.twig           # Adress-Registrierung
│   │   ├── summary.html.twig                # Checkout-Zusammenfassung
│   │   ├── progress.html.twig               # Checkout-Fortschritt
│   │   └── aside-actions-footer.html.twig   # Checkout-Sidebar-Footer
│   ├── content/
│   │   ├── index.html.twig                  # Content-Seite
│   │   ├── detail.html.twig                 # Content-Detail
│   │   └── product-detail.html.twig         # Produktdetail-Seite
│   └── product-detail/
│       ├── index.html.twig                  # Produktdetail-Hauptseite
│       ├── buy-widget.html.twig             # Buy-Widget
│       ├── buy-widget-form.html.twig        # Buy-Widget-Formular
│       └── headline-buybox.html.twig        # Headline-Buybox
├── section/
│   └── cms-section-sidebar.html.twig        # CMS-Sidebar-Sektion
├── block/
│   ├── cms-block-category-navigation-onelevel.html.twig # Kategorienavigation-Block
│   └── cms-block-gallery-buybox.html.twig   # Galerie-Buybox-Block
└── utilities/
    ├── alert.html.twig                      # Alert-Komponente
    ├── icon.html.twig                       # Icon-Komponente
    ├── offcanvas.html.twig                  # Offcanvas-Komponente
    └── thumbnail.html.twig                  # Thumbnail-Komponente

Custom Twig-Extensions

Das Guppy Theme erweitert Twig um zusätzliche Funktionen:

CategoryOneLevelExtension

Die categoryOneLevel() Funktion ermöglicht die Darstellung einstufiger Kategorie-Navigationen:

twig
{% set navigationData = categoryOneLevel(navigationTree, currentCategoryId) %}

{% for category in navigationData %}
    <a href="{{ category.url }}" class="nav-link">
        {{ category.name }}
    </a>
{% endfor %}

Implementierung:

php
// src/Twig/CategoryOneLevelExtension.php
class CategoryOneLevelExtension extends AbstractExtension
{
    public function getFunctions(): array
    {
        return [
            new TwigFunction('categoryOneLevel', [$this, 'categoryOneLevel'])
        ];
    }

    public function categoryOneLevel($navigationTree, $currentCategoryId)
    {
        // Implementierung der einstufigen Kategorienavigation
    }
}

Barrierefreiheits-Features

Das Theme bietet konfigurierbare Skip-Links für bessere Accessibility:

twig
{# base.html.twig #}
{% block base_body_inner %}
    {% if theme_config('guppy-header-skip-to-main-content') %}
        <a href="#content-main" class="skip-link">
            {{ 'skipLink.toMainContent'|trans|sw_sanitize }}
        </a>
    {% endif %}
    
    {% if theme_config('guppy-header-skip-to-main-nav') %}
        <a href="#main-navigation" class="skip-link">
            {{ 'skipLink.toMainNavigation'|trans|sw_sanitize }}
        </a>
    {% endif %}
    
    {% if theme_config('guppy-header-skip-to-search') %}
        <a href="#search" class="skip-link">
            {{ 'skipLink.toSearch'|trans|sw_sanitize }}
        </a>
    {% endif %}
    
    {{ parent() }}
{% endblock %}

Verfügbare Skip-Links:

  • guppy-header-skip-to-main-content: Sprung zum Hauptinhalt
  • guppy-header-skip-to-main-nav: Sprung zur Hauptnavigation
  • guppy-header-skip-to-search: Sprung zur Suche

USP-Banner-Integration

Das USP-Banner-System wird über Templates integriert:

twig
{# layout/_includes/usp-banner.html.twig #}
{% if theme_config('guppy-usp-active') %}
    <div class="usp-banner" data-usp-banner-plugin="true">
        {% if theme_config('guppy-usp-layout') == 'benefits' %}
            {% for i in 1..4 %}
                {% set benefit = theme_config('guppy-usp-layout-benefit' ~ i) %}
                {% if benefit %}
                    <div class="usp-item">
                        {{ benefit }}
                    </div>
                {% endif %}
            {% endfor %}
        {% else %}
            <div class="usp-item">
                <a href="{{ theme_config('guppy-usp-layout-link') }}" 
                   {% if theme_config('guppy-usp-layout-newTab') %}target="_blank"{% endif %}>
                    {{ theme_config('guppy-usp-layout-text') }}
                </a>
            </div>
        {% endif %}
    </div>
{% endif %}

Praktische Implementierung

Neuen Header-Typ erstellen

  1. Template erstellen:
twig
{# src/Resources/views/storefront/layout/header/header-custom.html.twig #}
{% sw_extends '@Storefront/storefront/layout/header/header.html.twig' %}

{% block layout_header_inner %}
    <div class="header-custom">
        {# Custom Header-Inhalt #}
    </div>
{% endblock %}
  1. Theme-Konfiguration erweitern:
json
"guppy-header": {
    "custom": {
        "options": [
            {"value": "custom", "label": {"de-DE": "Custom Header"}}
        ]
    }
}
  1. SCSS-Styling hinzufügen:
scss
.header-variant-custom {
    .header-custom {
        // Custom Header-Styles
    }
}

Neue Produktkarten-Variante

  1. Template erstellen:
twig
{# src/Resources/views/storefront/component/product/card/box-custom.html.twig #}
{% sw_extends '@Storefront/storefront/component/product/card/box-standard.html.twig' %}

{% block component_product_box %}
    <div class="product-box box-custom">
        {# Custom Produktkarte-Inhalt #}
    </div>
{% endblock %}
  1. Theme-Konfiguration erweitern:
json
"guppy-productcard-config": {
    "custom": {
        "options": [
            {"value": "custom", "label": {"de-DE": "Custom Produktkarte"}}
        ]
    }
}

Alert-Varianten konfigurieren

twig
{# utilities/alert.html.twig #}
{% set alertClass = 'alert-' ~ type %}
{% if theme_config('guppy-alert-alert-outline-active') %}
    {% set alertClass = alertClass ~ ' alert-outline' %}
{% endif %}

<div class="alert {{ alertClass }}" role="alert">
    {{ message }}
</div>

Theme-Konfiguration:

json
"guppy-alert-color-success": "#D3F2E7",
"guppy-alert-color-success-text": "dark",
"guppy-alert-alert-outline-active": true

Best Practices

Template-Vererbung

twig
{# Immer von der entsprechenden Shopware-Vorlage erben #}
{% sw_extends '@Storefront/storefront/layout/header/header.html.twig' %}

{# Spezifische Blöcke überschreiben #}
{% block layout_header_logo %}
    <div class="header-logo-custom">
        {{ parent() }}
    </div>
{% endblock %}

Theme-Konfiguration verwenden

twig
{# Immer Theme-Konfiguration für Varianten verwenden #}
{% if theme_config('guppy-component-variant') %}
    {% set variant = theme_config('guppy-component-variant') %}
{% endif %}

{# Fallback für Standard-Verhalten #}
{% if variant %}
    {# Custom Logik #}
{% else %}
    {{ parent() }}
{% endif %}

Barrierefreiheit berücksichtigen

twig
{# Immer semantische HTML-Elemente verwenden #}
<nav role="navigation" aria-label="{{ 'navigation.main'|trans }}">
    {# Navigation-Inhalt #}
</nav>

{# Skip-Links für wichtige Bereiche #}
<a href="#main-content" class="skip-link">
    {{ 'skipLink.toMainContent'|trans }}
</a>