Blog · Shopware 6

Widerrufsbutton in Shopware 6. Kostenlose Anleitung mit Code.

Shopware-6-Händler arbeiten mit Twig, Symfony und einer sauber getrennten Storefront-Architektur. Das ist gut, weil wir den Widerrufsbutton sauber über ein Plugin einhängen können, ohne Core-Dateien anzufassen. Hier der komplette Weg.

Was das Gesetz ab 19.06.2026 verlangt

§ 356a BGB, verkündet im BGBl. I Nr. 31 vom 5.2.2026, verlangt für jeden B2C-Shop in der EU einen zweistufigen Widerrufsbutton. Stufe 1 heißt Vertrag widerrufen. Stufe 2 heißt Widerruf bestätigen. Dazwischen ein Formular mit Name plus Kontaktmittel als Pflichtfelder, danach eine Eingangsbestätigung per E-Mail auf einem dauerhaften Datenträger nach § 126b BGB.

Kein Login, keine Scroll-Barriere. Verfügbar während der gesamten Widerrufsfrist. Das Abmahn-Risiko bei Verstössen liegt nach RVG bei 500 bis 2.000 €, plus einer automatischen Fristverlängerung auf zwölf Monate und vierzehn Tage nach § 356 Abs. 3 BGB.

Die zwei Wege für Shopware 6

Weg A: Twig-Template-Extension direkt in deinem Theme. Schnell, aber gebunden an dein Theme. Bei Theme-Updates musst du aufpassen.

Weg B: Eigenes Storefront-Plugin, das ein Twig-Snippet registriert. Sauber, update-sicher, kann per Admin deaktiviert werden. Ist der empfohlene Shopware-Weg.

Weg A: Twig-Template-Extension im Theme

Shopware 6 nutzt Block-basierte Twig-Templates. Du kannst jeden Block überschreiben oder erweitern. Der Footer lebt in @Storefront/storefront/layout/footer/footer.html.twig. Wir hängen uns an den Block base_footer_inner_container.

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

{% block base_footer_inner_container %}
    {{ parent() }}

    <script
        src="https://widerrufbutton.net/widget/v1/wh.js"
        data-shop-id="{{ config('WiderrufButton.config.shopId') }}"
        data-position="footer"
        data-lang="de"
        async
        defer
    ></script>
{% endblock %}

Der Aufruf config(...) greift auf die Plugin-Konfiguration zu. Wenn du keine Konfiguration aufbauen willst, kannst du auch direkt den Widget-Key reinschreiben. Für eine saubere Lösung braucht es aber Weg B.

Weg B: Eigenes Plugin

Ein Shopware-6-Plugin ist im Wesentlichen ein Symfony-Bundle mit einer composer.json, einer Plugin-Klasse und einer services.xml für die Dependency-Injection.

Die Mindest-Struktur sieht so aus:

custom/plugins/WiderrufButton/
├── composer.json
├── src/
│   ├── WiderrufButton.php
│   ├── Resources/
│   │   ├── config/
│   │   │   ├── config.xml
│   │   │   └── services.xml
│   │   └── views/
│   │       └── storefront/
│   │           └── layout/
│   │               └── footer/
│   │                   └── footer.html.twig

Die config.xml definiert das Eingabefeld für den Widget-Key im Shopware-Admin:

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/shopware/platform/trunk/src/Core/System/SystemConfig/Schema/config.xsd">
    <card>
        <title>WiderrufButton</title>
        <input-field>
            <name>shopId</name>
            <label>Widget-Key</label>
            <helpText>Aus dem WiderrufButton-Dashboard</helpText>
        </input-field>
    </card>
</config>

Die services.xml bleibt leer, solange du keine eigenen Services brauchst. Das Twig-Template überschreibt wie in Weg A den Footer-Block, ruft aber die Plugin-Konfiguration via config('WiderrufButton.config.shopId') auf.

Plugin aktivieren und testen

Im Shopware-Verzeichnis die Befehle in dieser Reihenfolge:

bin/console plugin:refresh
bin/console plugin:install --activate WiderrufButton
bin/console theme:compile
bin/console cache:clear

Danach erscheint das Plugin im Admin unter Erweiterungen. Dort den Widget-Key aus deinem WiderrufButton-Dashboard eintragen. Speichern. Shop öffnen, Footer prüfen.

HTTP-Cache und CSP beachten

Shopware 6 cached aggressiv. Nach Theme-Compile den HTTP-Cache leeren, sonst siehst du das Script nicht sofort. In der Shopware-Konfiguration ist das bin/console http:cache:clear.

Wenn du eine Content Security Policy aktiv hast, muss widerrufbutton.net in den script-src- und connect-src-Direktiven stehen. Der Browser lädt das Script von dort und schickt den Widerruf an die API-Route auf derselben Domain.

Warum Shadow DOM wichtig ist

Shopware-Themes bringen eigenes CSS mit. Ohne Kapselung würde der Button-Style mit dem Theme kollidieren, die Farben falsch laufen, das Modal an der falschen Stelle erscheinen. Das Widget läuft deshalb im Shadow DOM. Sein CSS ist komplett isoliert, Shopware-Styles können nichts überschreiben, und dein Theme bleibt unberührt.

Dasselbe gilt in die andere Richtung: Der Button kann deinem Theme nichts tun. Keine globalen Styles, keine Klassennamen, die kollidieren, keine Schriftarten, die ungewollt überschrieben werden.

Mehrsprachigkeit und Sales Channels

Shopware erlaubt mehrere Sales Channels mit unterschiedlichen Domänen. Für jede Domäne brauchst du im WiderrufButton-Dashboard einen eigenen Shop-Eintrag, damit die CORS-Prüfung gegen die korrekte Origin läuft. Die Widget-Keys unterscheiden sich, und du musst pro Sales Channel den richtigen Key an die Plugin-Konfiguration binden.

Details dazu stehen auf der Produktseite und in der Anleitung.

Checkliste vor dem Go-Live

  • Widget-Key im Admin eingetragen und gespeichert
  • Theme neu kompiliert, HTTP-Cache geleert
  • Button im Footer sichtbar, ohne Scrollen erreichbar
  • Formular-Submit mit Test-Daten, E-Mail kommt innerhalb von Sekunden
  • Content Security Policy erlaubt die Widget-Domäne
  • Im Dashboard unter Widerrufe erscheint der Test-Eintrag

Shopware-kompatibel, update-sicher, unter 15 KB

WiderrufButton funktioniert mit jedem Shopware-6-Theme, ohne Theme-Code anzufassen. Ein Plugin, ein Widget-Key, fertig.

Jetzt kostenlos starten

14 Tage kostenlos • Keine Kreditkarte erforderlich