AGB-Checkbox im Hyvä-Checkout rechtssicher umsetzen
AI generated
Hyvä
phtml
Checkout · Recht · Alpine.js · PHP-Plugin
AGB-Checkbox im Hyvä-Checkout
rechtssicher, mehrfach und serverseitig geprüft implementieren

Eine einzelne, vorausgewählte oder mit der Datenschutzerklärung kombinierte AGB-Checkbox im Checkout ist ein rechtliches Risiko, das im Hyvä-Theme durch fehlende Serverprüfung zusätzlich verschärft wird. Dieser Beitrag zeigt, wie dieses Pflichtfeld über Magentos checkout_agreements-Mechanismus, eine erweiterte Alpine.js-Komponente für mehrere Pflichtfelder und ein serverseitiges PHP-Plugin so implementiert wird, dass Kunden aktiv zustimmen müssen und eine Bestellung ohne echte Bestätigung technisch unmöglich bleibt.

14 Min. Lesezeit checkout_agreements · Alpine.js · CheckoutAgreementsListInterface Magento 2.4.8-p4 · PHP 8.4 · Hyvä Themes

1. Rechtlicher Hintergrund: Button-Lösung und Checkbox-Pflicht

Die sogenannte Button-Lösung aus § 312j BGB verlangt, dass Verbraucher im Bestellprozess eine kostenpflichtige Bestellung nur über eine eindeutig beschriftete Schaltfläche auslösen können und dass ihnen unmittelbar vor der Bestellung die wesentlichen Vertragsinformationen klar und verständlich dargestellt werden. Eine AGB-Checkbox ist die technische Umsetzung eines Teils dieser Anforderung: Der Kunde muss aktiv, durch eine eigene Handlung, bestätigen, dass er die Allgemeinen Geschäftsbedingungen, die Widerrufsbelehrung und in der Regel auch die Datenschutzerklärung zur Kenntnis genommen hat. Eine vorausgewählte Checkbox erfüllt dieses Kriterium nicht, weil keine aktive Handlung des Kunden stattgefunden hat, selbst wenn er sie theoretisch hätte deaktivieren können.

Technisch ergeben sich daraus konkrete Anforderungen an jedes solche Zustimmungsfeld im Checkout: Es darf niemals mit dem Attribut checked vorbelegt sein, die verlinkten Dokumente müssen über target="_blank" und rel="noopener" in einem neuen Tab geöffnet werden, damit der Kunde beim Nachlesen nicht seinen gefüllten Warenkorb oder bereits eingegebene Adressdaten verliert, und die Bestellung darf erst nach Aktivierung der Checkbox möglich sein. Magentos Standard-Checkout-Block für Vereinbarungen liefert die Grundlage dafür, muss in einem Hyvä-Theme aber bewusst angepasst werden, weil die Rendering-Schicht komplett von Knockout.js auf Alpine.js umgestellt ist und die Validierungslogik dadurch an anderer Stelle greift.

Dieser Beitrag beschreibt die technische und organisatorische Umsetzung einer rechtssicheren AGB-Checkbox im Hyvä-Checkout, ersetzt aber keine individuelle Rechtsberatung. Die konkrete Formulierung der Einwilligungstexte, die Reichweite der Datenschutzerklärung und die Frage, welche Checkboxen für ein bestimmtes Geschäftsmodell zwingend erforderlich sind, sollten vor dem Livegang von einer auf E-Commerce spezialisierten Rechtsberatung geprüft werden.

2. Der Magento-Standard: checkout_agreements im Detail

Magento bringt mit dem Modul Magento_CheckoutAgreements bereits einen eingebauten Mechanismus für Vereinbarungen mit, auf dem jede AGB-Checkbox-Implementierung aufsetzen sollte, statt bei null zu beginnen. Zentral ist das Interface CheckoutAgreementsListInterface mit der Methode getList(int $storeId): AgreementInterface[], die alle für einen Store aktiven Vereinbarungen zurückgibt. Jede AgreementInterface-Instanz kapselt Name, Inhalt, Checkbox-Text, Darstellungshöhe und vor allem den Modus: MODE_MANUAL zeigt die Checkbox im Checkout an und erzwingt die aktive Bestätigung, MODE_AUTO gilt als automatisch akzeptiert und blendet keine Checkbox ein.

Für ein rechtssicheres Zustimmungsfeld ist ausschließlich der manuelle Modus relevant, weil nur er eine sichtbare, aktiv zu bestätigende Checkbox erzeugt. Der automatische Modus ist im Kern für unkritische Hinweise gedacht und sollte für AGB, Widerrufsbelehrung oder Datenschutz nicht verwendet werden, auch wenn er in der Admin-Konfiguration unter Stores > Terms and Conditions technisch auswählbar bleibt. Beim Absenden der Bestellung übergibt der Checkout die IDs aller angehakten Vereinbarungen als agreement_ids, und der Server prüft über Magento\CheckoutAgreements\Model\AgreementsValidator, ob für jede aktive, manuelle Vereinbarung auch tatsächlich eine passende ID mitgeschickt wurde.

Dieser eingebaute Validator ist der entscheidende Vorteil des Standardmechanismus: Jede zusätzliche Pflicht-Checkbox, die über CheckoutAgreementsListInterface registriert wird, profitiert automatisch von einer serverseitigen Prüfung, ohne dass dafür eigener Validierungscode geschrieben werden muss. Erst wenn eine Checkbox bewusst außerhalb dieses Mechanismus abgebildet wird, etwa weil sie eine eigenständige, vom AGB-Text unabhängige Einwilligung darstellt, ist ein eigenes Validierungs-Plugin erforderlich.

3. Wie Hyvä die AGB-Checkbox über Alpine.js rendert

In Luma rendert eine Knockout.js-ViewModel-Bindung die Liste der Vereinbarungen und synchronisiert den Checkbox-Status über Observables mit dem Place-Order-Button. Hyvä ersetzt diese Schicht vollständig durch eine Alpine.js-Komponente, die dieselben Daten aus CheckoutAgreementsListInterface per Block-ViewModel in das Template injiziert, den Aktivierungsstatus aber lokal über x-data hält, statt über ein globales Observable-Muster. Jede Checkbox wird dabei pro aktiver, manueller Vereinbarung einzeln aus dem Template geloopt und bindet über x-model an ein eigenes Feld im Alpine-Datenobjekt.

Der folgende, vereinfachte Ausschnitt zeigt das Grundmuster, wie es in einer Hyvä-typischen checkout-agreements.phtml zum Einsatz kommt: Ein Alpine-Store hält den kombinierten Zustand aller Vereinbarungen, ein computed Property allChecked fasst den Status zusammen, und der Place-Order-Button bindet sein disabled-Attribut direkt an dieses Property, statt auf einen separaten Klick-Handler zu warten.


// checkout-agreements.phtml (Alpine data initialisation, adapted from Hyva's default pattern)
document.addEventListener('alpine:init', () => {
  Alpine.store('checkoutAgreements', {
    // One boolean per manual agreement id, keyed by agreement id
    checkedMap: {},

    // Called once per rendered agreement checkbox on init
    register(agreementId) {
      if (!(agreementId in this.checkedMap)) {
        this.checkedMap[agreementId] = false;
      }
    },

    toggle(agreementId) {
      this.checkedMap[agreementId] = !this.checkedMap[agreementId];
    },

    // Place-order button reads this getter to enable/disable itself
    get allChecked() {
      return Object.values(this.checkedMap).every(Boolean);
    }
  });
});

Diese Grundstruktur reicht für eine einzelne, kombinierte Zustimmungs-Checkbox aus, stößt aber an ihre Grenzen, sobald AGB, Datenschutzerklärung und ein optionaler Newsletter-Opt-in fachlich getrennt behandelt werden sollen. Der Store kennt bislang nur eine anonyme Liste von IDs, aber keine semantische Unterscheidung, welche Checkbox für welchen Zweck steht, und liefert dementsprechend auch keine individuelle Fehlermeldung pro Checkbox.

4. Mehrere Pflichtfelder: AGB, Datenschutz und Newsletter getrennt

Eine kombinierte Checkbox, die AGB-Zustimmung und Kenntnisnahme der Datenschutzerklärung in einem einzigen Satz und einem einzigen Kontrollkästchen bündelt, gilt in der Praxis als riskant, weil sie dem Kunden keine getrennte, bewusste Entscheidung über zwei inhaltlich unterschiedliche Erklärungen ermöglicht. Empfehlenswert ist stattdessen eine eigenständige AGB-Checkbox für die Allgemeinen Geschäftsbedingungen samt Widerrufsbelehrung, eine zweite Pflicht-Checkbox für die Kenntnisnahme der Datenschutzerklärung und optional eine dritte, ausdrücklich nicht vorausgewählte Checkbox für einen Newsletter-Opt-in.

Um das im Hyvä-Checkout abzubilden, wird die einfache Alpine-Store-Struktur aus Abschnitt 3 durch eine dedizierte Alpine-Komponente ersetzt, die jedes Pflichtfeld einzeln modelliert, einen eigenen Fehlerzustand pro Feld führt und erst dann die Bestellung freigibt, wenn alle Pflichtfelder aktiv bestätigt wurden. Wichtig dabei: Für die Anzeige von Fehlertexten wird ausschließlich x-text verwendet, niemals eine direkte Mustache-Interpolation im Markup, da Hyvä-Templates serverseitig in PHP gerendert werden und Alpine seine Bindungen erst clientseitig auflöst.


// checkout-consent.phtml (extended Alpine component for multiple mandatory checkboxes)
document.addEventListener('alpine:init', () => {
  Alpine.data('checkoutConsent', () => ({
    agbChecked: false,
    privacyChecked: false,
    newsletterOptIn: false, // optional, never pre-checked
    showAgbError: false,
    showPrivacyError: false,

    // Both mandatory checkboxes must be actively checked before order placement
    get canPlaceOrder() {
      return this.agbChecked && this.privacyChecked;
    },

    // Called from @click.prevent on the place-order button wrapper
    validateBeforeSubmit() {
      this.showAgbError = !this.agbChecked;
      this.showPrivacyError = !this.privacyChecked;
      return this.canPlaceOrder;
    },

    agbErrorText() {
      return 'Bitte bestaetigen Sie die Allgemeinen Geschaeftsbedingungen.';
    },

    privacyErrorText() {
      return 'Bitte bestaetigen Sie die Kenntnisnahme der Datenschutzerklaerung.';
    }
  }));
});

Der Aufruf validateBeforeSubmit() ersetzt keine serverseitige Prüfung, sondern verbessert ausschließlich die Nutzerführung: Der Kunde sieht sofort, welches Pflichtfeld noch fehlt, ohne auf eine Fehlermeldung nach einem fehlgeschlagenen Serveraufruf warten zu müssen. Die eigentliche Absicherung gegen eine Umgehung erfolgt zwingend auf Serverseite, wie in Abschnitt 6 beschrieben.

5. PHP-Plugin: Zusätzliche Checkbox über CheckoutAgreementsListInterface

Für Pflichtfelder, die inhaltlich zu einer klassischen Vereinbarung passen, etwa eine separate Datenschutz-Checkbox, ist es sinnvoll, sie als reguläre Vereinbarung über CheckoutAgreementsListInterface zu registrieren, statt einen komplett eigenständigen Mechanismus zu bauen. Der Vorteil: Diese zusätzliche Datenschutz-Checkbox wird automatisch von Hyväs Standard-Rendering erfasst und profitiert vom bereits erwähnten AgreementsValidator, ohne dass für die serverseitige Grundprüfung zusätzlicher Code notwendig wäre.

Ein afterGetList-Plugin auf CheckoutAgreementsListInterface hängt dazu programmatisch eine weitere AgreementInterface-Instanz an das zurückgegebene Array an. Die Instanz wird über die zugehörige Factory erzeugt, damit sie exakt dieselbe Datenstruktur besitzt wie über die Admin-Oberfläche gepflegte Vereinbarungen, und erhält eine eindeutige, negative oder außerhalb des Admin-Wertebereichs liegende ID, um Kollisionen mit administrativ gepflegten Einträgen zu vermeiden.


<?php

declare(strict_types=1);

namespace Mironsoft\CheckoutCompliance\Plugin;

use Magento\CheckoutAgreements\Api\CheckoutAgreementsListInterface;
use Magento\CheckoutAgreements\Api\Data\AgreementInterface;
use Magento\CheckoutAgreements\Api\Data\AgreementInterfaceFactory;

/**
 * Adds a dedicated, always-required privacy consent checkbox to the checkout agreements list.
 */
class AddPrivacyAgreementPlugin
{
    private const PRIVACY_AGREEMENT_ID = -101;

    public function __construct(
        private readonly AgreementInterfaceFactory $agreementFactory
    ) {
    }

    /**
     * Appends a synthetic, non-admin-managed privacy agreement to the native agreement list.
     *
     * @param CheckoutAgreementsListInterface $subject
     * @param AgreementInterface[] $result
     * @return AgreementInterface[]
     */
    public function afterGetList(CheckoutAgreementsListInterface $subject, array $result): array
    {
        /** @var AgreementInterface $privacyAgreement */
        $privacyAgreement = $this->agreementFactory->create();
        $privacyAgreement->setAgreementId(self::PRIVACY_AGREEMENT_ID);
        $privacyAgreement->setName('privacy-consent');
        $privacyAgreement->setContent('Hinweis auf die geltende Datenschutzerklaerung.');
        $privacyAgreement->setCheckboxText('Ich habe die Datenschutzerklaerung zur Kenntnis genommen.');
        $privacyAgreement->setMode(AgreementInterface::MODE_MANUAL);
        $privacyAgreement->setIsHtml(false);
        $privacyAgreement->setIsActive(true);

        $result[] = $privacyAgreement;

        return $result;
    }
}

Diese Herangehensweise ist bewusst auf Vereinbarungen beschränkt, die inhaltlich in das Schema von AgreementInterface passen. Eine optionale Newsletter-Checkbox gehört semantisch nicht in diese Liste, weil sie gerade kein verpflichtendes Zustimmungsfeld im engeren Sinne ist, sondern eine freiwillige Einwilligung, die separat über ein eigenes Feld verwaltet werden sollte.

6. Serverseitige Validierung: Client-Bypass zuverlässig verhindern

Jede Alpine.js-Validierung, so sorgfältig sie auch implementiert ist, lässt sich clientseitig umgehen: Ein technisch versierter Kunde kann den Place-Order-Request direkt über die REST- oder GraphQL-Schnittstelle abschicken und dabei jede JavaScript-Prüfung im Browser vollständig ignorieren. Für jedes Pflichtfeld, das nicht über den nativen agreement_ids-Mechanismus aus Abschnitt 5 abgedeckt ist, etwa weil sie als eigenständiges Extension Attribute auf dem Payment-Objekt modelliert wurde, ist deshalb ein serverseitiges Plugin zwingend erforderlich, das den Bestellabschluss blockiert.

Der naheliegende Ansatzpunkt ist ein before-Plugin auf Magento\Checkout\Api\PaymentInformationManagementInterface::savePaymentInformationAndPlaceOrder. Das Plugin liest das übergebene PaymentInterface-Objekt aus, prüft dessen Extension Attributes auf ein zuvor über extension_attributes.xml deklariertes Flag und wirft eine LocalizedException, sobald ein Pflichtfeld nicht aktiv bestätigt wurde. Dadurch ist es unerheblich, ob die Anfrage über den regulären Hyvä-Checkout, eine mobile App oder ein manuell konstruiertes REST-Payload kommt: Ohne bestätigte AGB-Checkbox wird die Bestellung serverseitig abgelehnt.


<?php

declare(strict_types=1);

namespace Mironsoft\CheckoutCompliance\Plugin;

use Magento\Checkout\Api\PaymentInformationManagementInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Quote\Api\Data\PaymentInterface;

/**
 * Blocks order placement server-side when a mandatory consent checkbox was not submitted,
 * preventing any client-side-only bypass of the terms and privacy checkboxes.
 */
class ValidateConsentBeforePlaceOrderPlugin
{
    /**
     * Rejects the request before it reaches core order-placement logic.
     *
     * @param PaymentInformationManagementInterface $subject
     * @param int $cartId
     * @param PaymentInterface $paymentMethod
     * @param mixed $billingAddress
     * @return void
     * @throws LocalizedException
     */
    public function beforeSavePaymentInformationAndPlaceOrder(
        PaymentInformationManagementInterface $subject,
        int $cartId,
        PaymentInterface $paymentMethod,
        $billingAddress = null
    ): void {
        $extensionAttributes = $paymentMethod->getExtensionAttributes();

        // getPrivacyConsent() is generated from extension_attributes.xml for PaymentInterface
        $privacyConfirmed = $extensionAttributes !== null
            && $extensionAttributes->getPrivacyConsent() === true;

        if (!$privacyConfirmed) {
            throw new LocalizedException(
                __('Please confirm the privacy consent checkbox before placing the order.')
            );
        }
    }
}

Ein wichtiges Detail: Dieses Plugin ersetzt den bereits vorhandenen AgreementsValidator nicht, sondern ergänzt ihn. Beide Mechanismen greifen typischerweise parallel, weil ein reguläres Zustimmungsfeld über agreement_ids abgesichert wird, während zusätzliche, eigenständige Zustimmungen über Extension Attributes eine zweite, unabhängige Prüflinie bilden.

7. Layout-XML: Platzierung in checkout_index_index

Die zusätzliche Checkbox wird, wie alle Hyvä-Anpassungen laut Projektvorgabe, ausschließlich über Layout-XML gesteuert und niemals hart in ein bestehendes Core-Template geschrieben. Ein eigener Block wird per referenceBlock relativ zum vorhandenen Vereinbarungs-Block positioniert, sodass das zusätzliche Feld optisch und im DOM direkt neben oder unterhalb der nativen Checkboxen erscheint. Die bestehende Iteration über $block->getChildNames() im übergeordneten Container bleibt dabei unverändert erhalten.

Im zugehörigen Template wird der Alpine-Wrapper aus Abschnitt 4 eingebunden, die Fehlerdarstellung erfolgt über bedingte Tailwind-Klassen, und jeder Inline-Script-Block wird unmittelbar im Anschluss über $hyvaCsp->registerInlineScript() für die Content Security Policy freigegeben, wie es die CSP-Vorgaben des Themes verlangen.


<!-- app/design/frontend/Mironsoft/default/Mironsoft_CheckoutCompliance/layout/checkout_index_index.xml -->
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="checkout.root">
            <block name="checkout.consent.checkboxes"
                   template="Mironsoft_CheckoutCompliance::checkout/consent-checkboxes.phtml"
                   after="checkout.payment.agreements"/>
        </referenceBlock>
    </body>
</page>

<!-- app/design/frontend/Mironsoft/default/Mironsoft_CheckoutCompliance/templates/checkout/consent-checkboxes.phtml -->
<div x-data="checkoutConsent()" class="mt-4 space-y-3">
    <label class="flex items-start gap-2">
        <input type="checkbox"
               x-model="agbChecked"
               :class="showAgbError ? 'border-red-500 ring-1 ring-red-500' : 'border-gray-300'"
               class="mt-1 rounded" />
        <span>Ich akzeptiere die
            <a class="underline" href="/agb" target="_blank" rel="noopener">AGB</a> und die
            <a class="underline" href="/widerrufsrecht" target="_blank" rel="noopener">Widerrufsbelehrung</a>.
        </span>
    </label>
    <p x-show="showAgbError" x-text="agbErrorText()" class="text-sm text-red-600"></p>
</div>

<script>
    // Alpine.data('checkoutConsent', ...) is registered in the JS module shown in section 4
</script>
<?php /* @noEscape */ echo $hyvaCsp->registerInlineScript(); ?>

Da das Template nur den Alpine-Wrapper und die Checkbox-Markup ausliefert, während die eigentliche Logik in einer separaten, versionierten JavaScript-Datei liegt, bleibt die Wartbarkeit hoch: Änderungen an der Zustimmungslogik erfordern kein erneutes Static-Content-Deployment des phtml-Templates, sondern nur ein Rebuild des JavaScript-Bundles.

8. Fehlerzustände: Tailwind-Styling und CSP-konforme Validierung

Eine AGB-Checkbox ohne sichtbares Fehlerfeedback verleitet Kunden dazu, den Bestellbutton mehrfach erfolglos zu klicken, ohne zu verstehen, warum nichts passiert. Im gezeigten Template steuert die Klasse :class="showAgbError ? 'border-red-500 ring-1 ring-red-500' : 'border-gray-300'" die visuelle Fehlermarkierung, während der Text darunter über x-show und x-text nur dann erscheint, wenn validateBeforeSubmit() das jeweilige Feld als fehlend markiert hat. Wichtig ist, konsequent x-text statt einer direkten Mustache-Interpolation im Markup zu verwenden, weil Hyvä-Templates serverseitig in PHP ausgeliefert werden und ungeschützte doppelte geschweifte Klammern im PHP-Rendering-Kontext zu Konflikten führen können.

Für Barrierefreiheit sollte jede Pflicht-Checkbox zusätzlich aria-invalid="true" erhalten, sobald der Fehlerzustand aktiv ist, und der Fokus sollte per x-effect automatisch auf die erste fehlerhafte Checkbox springen, wenn der Kunde versucht, ohne Bestätigung abzusenden. Jeder Inline-Script-Block, der zur Steuerung dieser Zustände eingesetzt wird, muss unmittelbar von einem Aufruf von $hyvaCsp->registerInlineScript() gefolgt werden, da Hyväs Content Security Policy sonst jedes nicht registrierte Inline-Skript im Produktivbetrieb blockiert und die gesamte Validierungslogik lautlos ausfällt.

Da die eigentliche Prüf-Logik bereits vollständig im JavaScript-Modul aus Abschnitt 4 und im Template aus Abschnitt 7 abgebildet ist, kommt an dieser Stelle kein weiterer Code hinzu. Entscheidend ist die konsequente Kombination aus visueller Rückmeldung im Frontend und der in Abschnitt 6 beschriebenen, unabhängigen serverseitigen Absicherung desselben Pflichtfelds.

9. AGB-Checkbox-Patterns im Vergleich

Die folgende Übersicht stellt gängige, rechtlich riskante Umsetzungen eines Zustimmungsfelds den empfohlenen, rechtssicheren Hyvä-Mustern gegenüber. Der Unterschied liegt selten in der Optik, sondern fast immer in der Frage, ob eine aktive Handlung erzwungen und serverseitig geprüft wird.

Aspekt Rechtlich riskanter Ansatz Rechtssicheres Hyvä-Pattern Vorteil
Vorbelegung Checkbox mit checked vorausgewählt Immer deaktiviert, aktive Bestätigung nötig Erfüllt Anforderung an aktive Handlung
AGB und Datenschutz Eine kombinierte Checkbox für beides Getrennte Checkboxen für AGB und Datenschutz Getrennte, bewusste Einzelentscheidung
Link-Verhalten Link ohne target="_blank", Checkout-State verloren target="_blank" rel="noopener", Checkout bleibt erhalten Kein Datenverlust beim Nachlesen
Validierung Nur clientseitige Alpine.js-Prüfung Zusätzliches PHP-Plugin serverseitig Kein Bypass über direkte API-Requests
Fehleranzeige Kein sichtbares Feedback bei fehlendem Häkchen Roter Rahmen, Inline-Fehlertext, Fokus-Sprung Kunde versteht Abbruchgrund sofort

In der Praxis reicht es selten, nur eine Zeile dieser Tabelle umzusetzen. Erst das Zusammenspiel aus fehlender Vorbelegung, getrennten Checkboxen, korrektem Link-Verhalten, doppelter Validierung und klarer Fehleranzeige macht eine AGB-Checkbox im Hyvä-Checkout tatsächlich belastbar.

10. Zusammenfassung

Eine rechtssichere AGB-Checkbox im Hyvä-Checkout ist kein einzelnes Checkbox-Attribut, sondern das Zusammenspiel mehrerer Ebenen: Der rechtliche Rahmen der Button-Lösung verlangt eine aktive, nicht vorausgewählte Bestätigung. Magentos checkout_agreements-Mechanismus liefert über CheckoutAgreementsListInterface und den eingebauten AgreementsValidator die Grundlage für serverseitig geprüfte Vereinbarungen. Hyvä ersetzt die Knockout.js-Bindung durch eine Alpine.js-Komponente, die für mehrere getrennte Pflichtfelder wie AGB, Datenschutz und optionalen Newsletter-Opt-in erweitert werden kann, ohne die Hyvä-Blockstruktur oder $block->getChildNames() anzutasten.

Der entscheidende Punkt, der in vielen Umsetzungen fehlt, ist die serverseitige Absicherung zusätzlicher, nicht über agreement_ids abgedeckter Checkboxen: Ein Plugin auf PaymentInformationManagementInterface verhindert zuverlässig, dass eine manipulierte API-Anfrage die clientseitige Alpine-Validierung des Pflichtfelds umgeht. Layout-XML-Platzierung und Tailwind-gestützte Fehlerzustände runden die Umsetzung ab, ersetzen aber keine abschließende Prüfung der konkreten Texte und Pflichtfelder durch eine auf E-Commerce-Recht spezialisierte Rechtsberatung.

AGB-Checkbox im Hyvä-Checkout: das Wichtigste auf einen Blick

Rechtlicher Rahmen

Button-Lösung nach § 312j BGB verlangt eine aktive, niemals vorausgewählte Bestätigung vor kostenpflichtiger Bestellung.

Magento-Mechanismus

CheckoutAgreementsListInterface und AgreementsValidator liefern serverseitig geprüfte Vereinbarungen im manuellen Modus.

Alpine.js-Komponente

Getrennte Pflichtfelder für AGB und Datenschutz, eigener Fehlerzustand pro Feld, ausschließlich über x-text ausgegeben.

Serverseitige Prüfung

Plugin auf PaymentInformationManagementInterface blockiert die Bestellung, wenn eine Pflicht-Checkbox nicht bestätigt wurde.

11. FAQ: AGB-Checkbox im Hyvä-Checkout

1Was ist die Button-Lösung?
Sie verlangt eine eindeutig beschriftete Bestell-Schaltfläche und klare Vertragsinformationen vor der Bestellung. Diese Checkbox setzt einen Teil davon um, indem sie eine aktive Bestätigung erzwingt statt sie stillschweigend zu unterstellen.
2Darf die Checkbox vorausgewählt sein?
Nein. Eine vorausgewählte Checkbox erfüllt die Anforderung an eine aktive Handlung nicht. Das Alpine-Feld muss immer mit false initialisiert werden.
3Eine Checkbox für AGB und Datenschutz?
Riskant. Empfohlen wird eine eigene Checkbox für AGB samt Widerrufsbelehrung und eine separate Pflicht-Checkbox für die Datenschutzerklärung.
4Wie funktioniert checkout_agreements?
CheckoutAgreementsListInterface::getList() liefert Vereinbarungen mit Modus manuell oder automatisch. Im manuellen Modus werden agreement_ids übermittelt und vom AgreementsValidator serverseitig geprüft.
5Wie rendert Hyvä die Checkbox?
Über eine Alpine.js-Komponente statt Knockout.js. Die Vereinbarungsdaten kommen weiterhin aus CheckoutAgreementsListInterface, der Checkbox-Status wird lokal über x-data gehalten.
6Zusätzliche Pflicht-Checkbox hinzufügen?
Über ein afterGetList-Plugin auf CheckoutAgreementsListInterface, das per Factory eine weitere AgreementInterface-Instanz mit eindeutiger ID anhängt und so vom bestehenden AgreementsValidator profitiert.
7Reicht clientseitige Validierung?
Nein. Sie verbessert nur die Nutzerführung, verhindert aber keinen direkten API-Request. Ein serverseitiges PHP-Plugin ist zusätzlich zwingend erforderlich.
8Client-Bypass verhindern?
Mit einem before-Plugin auf PaymentInformationManagementInterface::savePaymentInformationAndPlaceOrder, das die Extension Attributes prüft und bei fehlender Bestätigung eine LocalizedException wirft.
9Fehler barrierefrei anzeigen?
Roter Rahmen per bedingter Tailwind-Klasse, Fehlertext über x-show und x-text, aria-invalid und automatischer Fokus-Sprung. Inline-Skripte immer mit $hyvaCsp->registerInlineScript() registrieren.
10Ersetzt das eine Rechtsberatung?
Nein. Die konkrete Formulierung der Texte und Pflichtfelder sollte von einer auf E-Commerce-Recht spezialisierten Rechtsberatung geprüft werden.

Mironsoft

Hyvä-Checkout-Anpassungen, Compliance und Alpine.js-Komponenten

AGB-Checkbox im Checkout wasserdicht umsetzen?

Wir analysieren euren bestehenden Hyvä-Checkout, prüfen die aktuelle AGB-Checkbox-Umsetzung und implementieren getrennte Pflichtfelder samt serverseitiger PHP-Validierung, ganz ohne Knockout.js oder zusätzliche JavaScript-Frameworks.

Compliance-Review

Prüfung der bestehenden Checkbox- und Vereinbarungslogik im Checkout

Alpine.js-Umsetzung

Mehrere Pflichtfelder, Fehlerzustände und CSP-konforme Inline-Skripte

Server-Absicherung

PHP-Plugins gegen clientseitigen Bypass der Checkout-Validierung