Eigene Zahlungsmethode im Hyvä-Checkout registrieren
AI generated
Hyvä
phtml
Magento 2 · Hyvä Themes · Payment · Alpine.js
Eigene Zahlungsmethode im Hyvä-Checkout registrieren
vom Payment-Method-Model bis zur Alpine.js-Validierung

Wer eine eigene Zahlungsmethode im Hyvä-Checkout registrieren will, kommt mit den klassischen Knockout-Renderer-Listen aus dem Luma-Checkout nicht weiter. Hyvä-Checkout löst Payment-Templates über Block-Aliase in Layout-XML auf, während die Formularlogik komplett mit Alpine.js, phtml-Templates und PHP-ViewModels abgebildet wird. Dieser Artikel zeigt den vollständigen Weg von Payment-Method-Model über Template-Registrierung, Alpine-Validierung und serverseitige Hooks bis zu PCI-Compliance-Fragen für Magento 2.4.8-p4.

19 Min. Lesezeit Payment Method Model · di.xml · phtml · Alpine.js Magento 2.4.8-p4 · PHP 8.4 · Hyvä Themes · Tailwind v4

1. Wie Zahlungsmethoden im Hyvä-Checkout-Frontend gerendert werden

Der freie Hyvä-Standardtheme liefert bewusst keinen eigenen Checkout mit aus. In checkout_index_index.xml steht statt eines Layouts nur ein Hinweis, dass entweder Hyvä-Checkout, die Luma-Fallback-Checkout-Kompatibilitätsschicht oder eine alternative Lösung installiert sein muss. Für eine eigene Zahlungsmethode im Hyvä-Checkout ist das die entscheidende Weichenstellung: Nur mit dem Modul Hyva_Checkout (Composer-Paket hyva-themes/magento2-hyva-checkout) landet man tatsächlich in einem Alpine.js-basierten Payment-Step ohne Knockout.js, jQuery und UI-Components. Die Luma-Fallback-Checkout-Variante rendert die Zahlungsarten weiterhin über die klassische Knockout-Renderer-Liste aus checkout_index_index.xml mit js/view/payment/method-renderer/...-Komponenten. Dieser Weg wird hier bewusst nicht behandelt.

In Hyvä-Checkout wird jede verfügbare Zahlungsmethode als Kind-Block des Containers checkout.payment.methods aufgelöst. Der Block-Alias (as-Attribut) muss exakt dem Magento-Zahlungsmethodencode entsprechen, den Magento\Payment\Helper\Data::getPaymentMethods() zurückgibt. Gibt es keinen passenden Block-Alias für eine aktivierte Zahlungsmethode, bleibt die Methode in der Auswahl unsichtbar. Ein häufiger Debugging-Fehler bei einer neuen eigenen Zahlungsmethode im Hyvä-Checkout. Das zugehörige npm-Package hyva-checkout stellt die Build-Pipeline bereit, mit der Tailwind-Klassen und Alpine.js-Komponenten aus den Checkout-Templates kompiliert werden, ähnlich wie beim Haupttheme.

Der praktische Effekt: Statt eines JS-Bundles pro Zahlungsmethode, das über requirejs-config.js gemappt werden muss, reicht ein einziges phtml-Template plus ein Layout-XML-Eintrag. Der Block erhält die aktuelle Zahlungsmethode als Magento\Quote\Api\Data\PaymentMethodInterface-Instanz über $block->getData('method') injiziert. Damit ist die gesamte Rendering-Kette für eine eigene Zahlungsmethode im Hyvä-Checkout serverseitig deklarativ und ohne Knockout-Observable-Bindings beschreibbar.

2. Backend: eigenes Payment-Method-Model

Bevor überhaupt ein Template gerendert wird, braucht jede eigene Zahlungsmethode ein Backend-Model, das entweder Magento\Payment\Model\MethodInterface implementiert oder, der übliche Weg für Offline- und einfache Redirect-Methoden, Magento\Payment\Model\Method\AbstractMethod erweitert. Über protected $_code wird der eindeutige Methodencode definiert, $_isOffline steuert, ob nach Bestellabschluss eine Rechnung statt einer Zahlungsabbuchung erwartet wird, und $_canUseCheckout/$_canUseInternal legen fest, ob die Methode im Storefront-Checkout beziehungsweise im Admin-Grid-Bestellprozess sichtbar ist.

Die Registrierung selbst erfolgt über config.xml unterhalb von <default><payment>: ein Knoten mironsoft_advancepayment mit active, model, order_status, title, allowspecific und specificcountry. Erst dieser Eintrag macht die Methode für Magento\Payment\Helper\Data überhaupt sichtbar. Ohne ihn erscheint auch bei korrekt registriertem Hyvä-Checkout-Template keine Zahlungsoption. Sichtbarkeitsbedingungen werden über zwei Methoden gesteuert: canUseForCountry($countryCode) schränkt die Methode geografisch ein, canUseCheckout() beziehungsweise ein Override von isAvailable($quote) erlaubt zusätzliche Bedingungen wie einen Mindestbestellwert oder eine Kundengruppen-Einschränkung.

Im folgenden Beispiel wird eine eigene Zahlungsmethode im Hyvä-Checkout implementiert: Vorkasse mit 2 % Skonto, nur für DACH-Länder und ab einem Mindestbestellwert von 50 Euro verfügbar. assignData() übernimmt zusätzlich die vom Checkout-Formular übermittelten Felder in additional_information, worauf Abschnitt 6 aufbaut.


<?php

declare(strict_types=1);

namespace Mironsoft\Payment\Model;

use Magento\Framework\DataObject;
use Magento\Payment\Model\Method\AbstractMethod;
use Magento\Quote\Api\Data\CartInterface;

/**
 * Custom offline payment method: advance payment with early payment discount.
 * Registered under payment/mironsoft_advancepayment in config.xml.
 */
class AdvancePayment extends AbstractMethod
{
    /**
     * @var string
     */
    protected $_code = 'mironsoft_advancepayment';

    /**
     * @var bool
     */
    protected $_isOffline = true;

    /**
     * @var bool
     */
    protected $_canUseCheckout = true;

    /**
     * @var bool
     */
    protected $_canUseInternal = true;

    /**
     * Restrict the payment method to DACH countries configured in system config.
     *
     * @param string|null $countryCode
     * @return bool
     */
    public function canUseForCountry($countryCode): bool
    {
        $allowed = ['DE', 'AT', 'CH'];

        return in_array($countryCode, $allowed, true);
    }

    /**
     * Hide the method below a minimum order value, on top of the default checks.
     *
     * @param CartInterface|null $quote
     * @return bool
     */
    public function isAvailable($quote = null): bool
    {
        if (!parent::isAvailable($quote)) {
            return false;
        }

        if ($quote !== null && (float) $quote->getGrandTotal() < 50.0) {
            return false;
        }

        return true;
    }

    /**
     * Persist additional checkout data submitted by the Alpine.js payment form.
     *
     * @param DataObject $data
     * @return $this
     */
    public function assignData(DataObject $data): static
    {
        parent::assignData($data);

        $additional = $data->getData('additional_data') ?? [];

        $this->getInfoInstance()->setAdditionalInformation(
            'invoice_reference',
            (string) ($additional['invoice_reference'] ?? '')
        );
        $this->getInfoInstance()->setAdditionalInformation(
            'early_discount_accepted',
            (bool) ($additional['early_discount_accepted'] ?? false)
        );

        return $this;
    }
}

3. Frontend-Registrierung des Templates

Nachdem das Backend-Model registriert ist, muss die eigene Zahlungsmethode im Hyvä-Checkout-Frontend ein Template zugewiesen bekommen. Das geschieht in view/frontend/layout/hyva_checkout_components.xml des eigenen Moduls über einen referenceBlock auf checkout.payment.methods. Der neue Kind-Block bekommt als as-Attribut exakt den Zahlungsmethodencode mironsoft_advancepayment und referenziert das phtml-Template über die übliche Modulname::Pfad-Notation. Zusätzlich lässt sich über etc/frontend/di.xml der Block mit weiteren Konstruktor-Argumenten konfigurieren, etwa wenn ein ViewModel projektweit für mehrere Zahlungsarten wiederverwendet werden soll.

Über das arguments-Element im Layout-XML wird außerdem das PHP-ViewModel Mironsoft\Payment\ViewModel\AdvancePayment in den Block injiziert. Die im Hyvä-Kontext bevorzugte Alternative zu einer eigenen Block-Klasse. Hyvä-Checkout unterstützt seit Version 1.0.5 zusätzlich Metadaten-Argumente für Icons (icon/svg beziehungsweise icon/src für Rasterbilder ab 1.1.22) und Untertitel (metadata/subtitle), die ohne zusätzliches Template direkt in der Zahlungsartenliste erscheinen.

Wichtig für jede eigene Zahlungsmethode im Hyvä-Checkout: Stimmt der Block-Alias nicht exakt mit dem in config.xml definierten Methodencode überein, wird die Methode zwar vom Backend als verfügbar gemeldet, aber im Frontend nicht gerendert. Ohne Fehlermeldung. Das ist der häufigste Stolperstein bei der Template-Registrierung und lohnt sich, als Erstes zu prüfen, wenn eine neue Zahlungsart in der Checkout-Auswahl fehlt.


<?xml version="1.0"?>
<!-- Registers the custom payment method template with Hyva Checkout -->
<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.payment.methods">
            <!-- The "as" alias must match the Magento payment method code exactly -->
            <block name="checkout.payment.method.mironsoft_advancepayment"
                   as="mironsoft_advancepayment"
                   template="Mironsoft_Payment::component/payment/method/advancepayment.phtml">
                <arguments>
                    <!-- Inject the ViewModel used inside the phtml template -->
                    <argument name="advancePaymentViewModel" xsi:type="object">
                        Mironsoft\Payment\ViewModel\AdvancePayment
                    </argument>
                    <!-- Optional metadata rendered directly in the payment method list -->
                    <argument name="metadata" xsi:type="array">
                        <item name="subtitle" xsi:type="string">Zahlung per Vorkasse mit 2% Skonto</item>
                        <item name="icon" xsi:type="array">
                            <item name="svg" xsi:type="string">payment-icons/invoice</item>
                        </item>
                    </argument>
                </arguments>
            </block>
        </referenceBlock>
    </body>
</page>

4. Eigenes phtml-Template für die Zahlungsmethode erstellen

Das phtml-Template ist der Ort, an dem die eigene Zahlungsmethode im Hyvä-Checkout tatsächlich Formularfelder bekommt. Anders als im Luma-Checkout gibt es keine Knockout-Observable-Bindings. Der gesamte Zustand des Formulars lebt in einem Alpine.js x-data-Objekt, das direkt am Wurzel-Element des Templates definiert wird. Der Block liefert die aktuelle Zahlungsmethode als PaymentMethodInterface über $block->getData('method'), das injizierte ViewModel liefert projektspezifische Zusatzdaten wie Rabattbedingungen oder Freitextlabels.

Im Beispiel unten wird ein Textfeld für eine interne Bestellreferenz und eine Checkbox für die Skonto-Bedingungen abgebildet. Beide Felder sind über x-model an das Alpine-Component advancePaymentForm() gebunden (siehe Abschnitt 5), das als separates JS-File eingebunden wird. Wichtig für CSP-konforme Hyvä-Themes: Da x-data hier als HTML-Attribut und nicht als <script>-Block verwendet wird, ist kein Aufruf von $hyvaCsp->registerInlineScript() nötig. Dieser wäre nur bei echten Inline-<script>-Tags erforderlich.

Die Formularnamen (mironsoft_advancepayment[invoice_reference]) müssen dem Namensschema entsprechen, das Hyvä-Checkout beim Absenden des Bestellformulars erwartet und das im Backend als additional_data-Array an assignData() übergeben wird. Wer hier vom Namensschema abweicht, bekommt zwar ein funktionierendes Formular, aber leere Felder in additional_information.


<?php
/** @var Magento\Framework\View\Element\Template $block */
/** @var Magento\Quote\Api\Data\PaymentMethodInterface $method */
$method = $block->getData('method');
?>
<div class="mt-4 rounded-lg border border-gray-200 p-4"
     x-data="advancePaymentForm()"
     x-on:payment-method-changed.window="touched = false"
>
    <label class="block text-sm font-medium text-gray-700 mb-1">
        <?= $block->escapeHtml(__('Ihre interne Bestellreferenz')) ?>
    </label>
    <input
        type="text"
        name="mironsoft_advancepayment[invoice_reference]"
        x-model="invoiceReference"
        x-on:blur="touched = true"
        class="w-full rounded-md border-gray-300 focus:border-orange-500 focus:ring-orange-500"
        placeholder="<?= $block->escapeHtmlAttr(__('z.B. Kostenstelle 4711')) ?>"
    >

    <label class="flex items-start gap-2 mt-4 text-sm text-gray-700">
        <input
            type="checkbox"
            name="mironsoft_advancepayment[early_discount_accepted]"
            x-model="discountAccepted"
            class="mt-0.5 rounded border-gray-300 text-orange-600 focus:ring-orange-500"
        >
        <span><?= $block->escapeHtml(__('Ich zahle innerhalb von 7 Tagen und nutze 2% Skonto.')) ?></span>
    </label>

    <p class="mt-2 text-xs font-semibold text-red-600" x-show="touched && errorMessage !== ''" x-text="errorMessage" x-cloak></p>
</div>

5. Client-seitige Validierung der Zahlungsdaten vor Bestellabschluss

Für eine eigene Zahlungsmethode im Hyvä-Checkout reicht serverseitige Validierung allein nicht aus, weil Kunden sonst erst nach einem vollständigen Seiten-Roundtrip merken, dass ein Pflichtfeld fehlt. Hyvä-Checkout stellt dafür serverseitig das Interface EvaluationInterface mit der Methode evaluateCompletion() bereit, über das eine Zahlungsmethode den Bestellabschluss blockieren kann, solange nicht alle Bedingungen erfüllt sind. Diese serverseitige Prüfung sollte jedoch immer durch eine sofortige, rein clientseitige Alpine.js-Validierung ergänzt werden, damit Nutzer ohne Verzögerung Feedback bekommen.

Die Alpine-Komponente advancePaymentForm() wird global über Alpine.data() registriert und in einer eigenen JS-Datei ausgelagert, statt sie als riesiges Inline-Objekt im phtml zu pflegen. Getter wie isValid und errorMessage berechnen reaktiv, ob das Formular vollständig ist, ohne dass ein manueller Watcher nötig wäre. Der Bestellbutton im Payment-Step ruft vor dem eigentlichen Absenden validateBeforeSubmit() auf; liefert die Funktion false zurück, wird das Absenden verhindert und stattdessen ein Alpine-Event payment-validation-failed ausgelöst, auf das andere Komponenten reagieren können.

Diese Kombination aus sofortigem Alpine-Feedback und serverseitiger EvaluationInterface-Prüfung verhindert zwei typische Fehlerbilder: Kunden, die trotz unvollständiger Formulardaten eine Bestellung auslösen, und Kunden, die durch zu aggressive clientseitige Validierung blockiert werden, obwohl der Server die Daten eigentlich akzeptieren würde. Wichtig ist, dass beide Validierungsebenen dieselben Regeln abbilden. Sonst entstehen widersprüchliche Fehlermeldungen zwischen Frontend und Backend.


/**
 * Alpine component for client-side validation of the advance payment form.
 * Registered globally so the phtml template can bind via x-data="advancePaymentForm()".
 */
document.addEventListener('alpine:init', () => {
    Alpine.data('advancePaymentForm', () => ({
        invoiceReference: '',
        discountAccepted: false,
        touched: false,

        get isValid() {
            return this.invoiceReference.trim().length >= 4 && this.discountAccepted;
        },

        get errorMessage() {
            if (!this.touched) {
                return '';
            }
            if (this.invoiceReference.trim().length < 4) {
                return 'Bitte mindestens 4 Zeichen angeben.';
            }
            if (!this.discountAccepted) {
                return 'Bitte die Skonto-Bedingungen bestaetigen.';
            }
            return '';
        },

        /**
         * Called from the payment step before the "place order" button dispatches.
         * Returning false blocks the native submit handler.
         */
        validateBeforeSubmit() {
            this.touched = true;
            if (!this.isValid) {
                this.$dispatch('payment-validation-failed', { method: 'mironsoft_advancepayment' });
                return false;
            }
            return true;
        }
    }));
});

6. Serverseitige Order-Placement-Hooks

Sobald die Bestellung tatsächlich abgeschickt wird, landen die von Alpine.js gesammelten Formulardaten über assignData() in additional_information des Order-Payments. Wie in Abschnitt 2 gezeigt. Für weiterführende Logik, die über das reine Speichern hinausgeht, bietet sich ein Plugin auf Magento\Sales\Api\OrderManagementInterface::place() an. Ein afterPlace-Plugin kann beispielsweise den Bestellstatus abhängig vom Skonto-Flag anpassen oder eine Benachrichtigung an die Buchhaltung auslösen, sobald eine eigene Zahlungsmethode im Hyvä-Checkout mit abweichenden Konditionen verwendet wurde.

Alternativ lässt sich bei komplexeren Zahlungsarten mit externer Gateway-Anbindung auf Magento\Payment\Gateway\Command\CommandPoolInterface aufgesetzt werden. Dort ersetzt ein eigenes Command im Command-Pool die Order-Placement-Logik vollständig, statt sie über AbstractMethod abzubilden. Für Offline-Methoden wie im Beispiel ist ein Plugin auf OrderManagementInterface jedoch der schlankere und besser wartbare Weg, weil kein komplettes Gateway-Command-System aufgebaut werden muss.

Ein zentraler Punkt bei jeder eigenen Zahlungsmethode im Hyvä-Checkout: additional_information wird serialisiert in der Spalte sales_order_payment.additional_information gespeichert und ist über $payment->getAdditionalInformation('feldname') in jedem späteren Kontext. Admin-Grid, Rechnungserstellung, Observer. Wieder auslesbar. Sensible Werte gehören hier ausdrücklich nicht hinein, dazu mehr in Abschnitt 9.


<?php

declare(strict_types=1);

namespace Mironsoft\Payment\Plugin;

use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\OrderManagementInterface;
use Psr\Log\LoggerInterface;

/**
 * Persists advance-payment specific data on the order payment
 * once the order has been placed through the Hyva checkout.
 */
class PersistAdvancePaymentDataPlugin
{
    /**
     * @param LoggerInterface $logger
     */
    public function __construct(
        private readonly LoggerInterface $logger
    ) {
    }

    /**
     * Set a distinct order status for advance payments with accepted discount,
     * because the invoice amount differs from the quote grand total.
     *
     * @param OrderManagementInterface $subject
     * @param OrderInterface $order
     * @return OrderInterface
     */
    public function afterPlace(OrderManagementInterface $subject, OrderInterface $order): OrderInterface
    {
        $payment = $order->getPayment();

        if ($payment === null || $payment->getMethod() !== 'mironsoft_advancepayment') {
            return $order;
        }

        $discountAccepted = (bool) $payment->getAdditionalInformation('early_discount_accepted');

        if ($discountAccepted) {
            $order->setStatus('pending_advance_discount');
            $this->logger->info(sprintf(
                'Order #%s placed with 2%% early payment discount, invoice reference: %s',
                $order->getIncrementId(),
                (string) $payment->getAdditionalInformation('invoice_reference')
            ));
        }

        return $order;
    }
}

7. Redirect-basierte Zahlungsarten

Viele externe Payment-Gateways erwarten, dass der Kunde nach dem Bestellabschluss auf eine gehostete Zahlungsseite weitergeleitet wird. Für eine solche eigene Zahlungsmethode im Hyvä-Checkout implementiert das Payment-Method-Model die Methode getOrderPlaceRedirectUrl() aus MethodInterface, die Hyvä-Checkout nach erfolgreichem place()-Aufruf automatisch respektiert und den Browser dorthin weiterleitet, statt die Standard-Success-Seite anzuzeigen. Die Rückkehr vom Gateway läuft über einen eigenen Controller unterhalb von Controller\Redirect\Response, der die Signatur des Gateways verifiziert und je nach Ergebnis eine Rechnung erstellt oder die Bestellung storniert.

Bricht der Kunde die Zahlung auf der externen Seite ab oder läuft die Session ab, ist die Wiederherstellung des Warenkorbs entscheidend für die Conversion. Ein Controller Controller\Redirect\Cancel ruft dafür Magento\Checkout\Model\Session::restoreQuote() auf, wodurch die zuvor in eine Order umgewandelte Quote wieder aktiv und im Checkout nutzbar wird, statt dass der Kunde von vorn beginnen muss. Ohne diesen Schritt bleibt der Warenkorb leer und die Bestellung hängt im Status pending_payment fest.

Für Fehlerfälle, in denen das Gateway einen asynchronen Webhook statt eines Browser-Redirects sendet, sollte die Verifizierung strikt getrennt von der reinen Redirect-Logik erfolgen: ein eigener, von der CSRF-Prüfung ausgenommener Controller nimmt Server-zu-Server-Callbacks entgegen, prüft eine Signatur oder ein HMAC-Token und aktualisiert die Order über OrderManagementInterface, unabhängig davon, ob der Kunde den Browser-Tab überhaupt noch geöffnet hat.

8. Fehlerbehandlung und Fehleranzeige im Frontend

Für eine eigene Zahlungsmethode im Hyvä-Checkout gibt es zwei unterschiedliche Fehlerkanäle, die bewusst getrennt behandelt werden sollten. Magentos Magento\Framework\Message\ManagerInterface mit addErrorMessage() ist der richtige Weg für Fehler, die einen vollständigen Seiten-Reload nach sich ziehen. Etwa eine abgelehnte Zahlung nach Redirect-Rückkehr oder eine Session-Time-out-Situation. Diese Meldungen werden über den globalen Message-Block gerendert und funktionieren unabhängig vom Alpine-Zustand der Seite.

Für alles, was während der Interaktion mit dem Formular passiert. Ein leeres Pflichtfeld, ein ungültiges Format, eine nicht akzeptierte Checkbox. Ist ein rein lokaler Alpine-Fehlerzustand die bessere Wahl, wie in Abschnitt 5 gezeigt. Der Vorteil: Die Fehlermeldung erscheint sofort, ohne Server-Request, und verschwindet automatisch wieder, sobald die Eingabe korrigiert wird. Wichtig ist, dass Fehlertexte für Endkunden verständlich formuliert sind und keine technischen Details wie Exception-Klassennamen oder Gateway-Fehlercodes preisgeben. Diese gehören stattdessen ins Log via Psr\Log\LoggerInterface.

Bei asynchronen Requests, etwa wenn eine Validierung serverseitig über EvaluationInterface läuft, sollte ein dritter Zustand berücksichtigt werden: der Ladezustand während der Anfrage. Ein einfaches x-data="{ loading: false }" mit :disabled="loading" auf dem Bestellbutton verhindert Doppelklicks und macht dem Kunden sichtbar, dass gerade etwas passiert, statt dass die Seite scheinbar untätig wirkt.

9. Sicherheit und PCI-Compliance-Überlegungen

Der wichtigste Grundsatz für jede eigene Zahlungsmethode im Hyvä-Checkout mit Kartendaten: Sensible Zahlungsdaten wie vollständige Kartennummern oder CVV-Codes dürfen niemals im Alpine-x-data-Zustand oder gar in localStorage landen. Alpine-Zustände sind über die Browser-DevTools jederzeit einsehbar, und localStorage überlebt sogar den Tab-Wechsel. Beides disqualifiziert diese Speicherorte für PCI-DSS-relevante Daten. Stattdessen übernehmen Tokenisierungs-SDKs der jeweiligen Payment-Gateways (etwa gehostete Iframe-Felder oder Hosted-Fields-Komponenten) die direkte Übertragung der Kartendaten an den Gateway-Server, ohne dass sie den eigenen Shop-Server oder das Alpine-Frontend überhaupt durchlaufen.

Nur das vom Gateway zurückgegebene Token wird anschließend über das reguläre Formularfeld an assignData() übergeben und in additional_information gespeichert. Niemals die Rohdaten der Karte. Diese Trennung reduziert den PCI-DSS-Scope des eigenen Shops erheblich, weil keine Kartendaten den eigenen Server berühren. Externe Payment-Skripte, die für Hosted Fields oder Iframe-Widgets benötigt werden, müssen zusätzlich CSP-konform eingebunden werden: die entsprechenden Domains gehören in etc/csp_whitelist.xml, echte Inline-Scripts erfordern in Hyvä-Themes zusätzlich den Aufruf von $hyvaCsp->registerInlineScript().

Ein häufiger Fehler in der Praxis: Aus Bequemlichkeit wird die Content-Security-Policy für die gesamte Checkout-Seite gelockert, statt gezielt einzelne Gateway-Domains freizugeben. Das untergräbt den eigentlichen Schutzzweck der CSP und sollte in jedem Code-Review für eine neue eigene Zahlungsmethode im Hyvä-Checkout explizit geprüft werden. Am besten mit einer dedizierten CSP-Konfiguration pro Zahlungsart statt einer pauschalen Ausnahme für die komplette Domain.

Die folgende Tabelle stellt den klassischen Knockout-Renderer-Listen-Ansatz aus dem Luma-Checkout dem Hyvä-Checkout-Template-Ansatz gegenüber, bezogen auf typische Aufgaben bei der Integration einer eigenen Zahlungsmethode im Hyvä-Checkout.

Aufgabe Knockout-Renderer-Liste (Luma) Hyvä-Checkout-Template Vorteil
Zahlungsmethode registrieren js/view/payment/method-renderer/*.js in checkout_index_index.xml Block-Alias in hyva_checkout_components.xml Kein Knockout-Bundle, kein RequireJS-Mapping
Formular-State verwalten ko.observable()-Ketten im ViewModel Alpine.data() mit lokalem x-data-State Direkte Reaktivität, kein virtuelles Rebuild
Felder ein-/ausblenden data-bind="visible: ..." x-show / x-if Deklarativ im Markup, kein Bundle-Rebuild
Template zuordnen requirejs-config.js + Component-Registrierung Ein phtml + ein Block-Alias in Layout-XML Ein einziger Ort für die Zuordnung
Bestellbutton bei Fehlern sperren Globales Knockout-computed im Payment-ViewModel :disabled + lokale Alpine-Validierung + EvaluationInterface Sofortiges Feedback ohne globale Bindings

Mironsoft

Magento-2- und Hyvä-Theme-Entwicklung mit Fokus auf Checkout und Payment

Eigene Zahlungsmethode im Hyvä-Checkout gesucht?

Wir implementieren eigene Zahlungsmethoden im Hyvä-Checkout von Payment-Method-Model über Alpine.js-Formulare bis zur PCI-konformen Gateway-Anbindung. Inklusive Redirect-Handling und serverseitiger Order-Hooks.

Payment-Integration

Backend-Model, Template-Registrierung und Alpine-Validierung für eigene Zahlungsmethoden

Checkout-Audit

Bestehende Hyvä-Checkout-Integrationen auf Sicherheit und CSP-Konformität prüfen

Gateway-Anbindung

Tokenisierung, Redirect-Flows und Webhook-Verifizierung für externe Payment-Gateways

10. Zusammenfassung

Eine eigene Zahlungsmethode im Hyvä-Checkout zu registrieren, folgt einem klaren, wiederholbaren Muster: ein Payment-Method-Model erweitert AbstractMethod und wird über config.xml unter payment/ aktiviert, ein Block-Alias in hyva_checkout_components.xml ordnet ein phtml-Template genau dieser Methode zu, und Alpine.js übernimmt die komplette clientseitige Formularlogik ohne Knockout.js, jQuery oder UI-Components. Sichtbarkeitsbedingungen wie canUseForCountry() und Mindestbestellwerte steuern, wann die Methode überhaupt erscheint, während assignData() und ein OrderManagementInterface-Plugin die übermittelten Formulardaten in additional_information persistieren.

Für redirect-basierte Gateways kommt getOrderPlaceRedirectUrl() und eine saubere Wiederherstellung des Warenkorbs über restoreQuote() hinzu, während Fehlerbehandlung bewusst zwischen serverseitigem Message-Manager und lokalem Alpine-Fehlerzustand getrennt wird. Sicherheitsseitig gilt: keine Kartendaten im Alpine-State oder in localStorage, Tokenisierung über das Gateway-SDK, und eine gezielte, CSP-konforme Einbindung externer Payment-Skripte statt einer pauschalen Lockerung der Content-Security-Policy. Wer diese neun Bausteine konsequent zusammensetzt, bekommt eine eigene Zahlungsmethode im Hyvä-Checkout, die wartbar, performant und PCI-konform bleibt.

Eigene Zahlungsmethode im Hyvä-Checkout: Das Wichtigste auf einen Blick

Backend-Model & Sichtbarkeit

AbstractMethod, config.xml unter payment/, canUseForCountry() und isAvailable() für Sichtbarkeitsregeln.

Frontend-Registrierung

Block-Alias in hyva_checkout_components.xml muss exakt dem Zahlungsmethodencode entsprechen.

Validierung & Hooks

Alpine.data() für sofortiges Feedback, EvaluationInterface serverseitig, OrderManagementInterface-Plugin für Persistierung.

Sicherheit & PCI

Keine Kartendaten im Alpine-State oder localStorage. Tokenisierung über Gateway-SDK, CSP-Whitelist statt globaler Lockerung.

11. FAQ: Eigene Zahlungsmethode im Hyvä-Checkout

1Unterschied eigene Zahlungsmethode Hyvä vs. Luma?
Luma nutzt eine Knockout-Renderer-Liste mit JS-Komponente pro Methode. Hyvä-Checkout ordnet per Block-Alias direkt ein phtml-Template zu, die Logik läuft über Alpine.js.
2Muss ich Hyva_Checkout kaufen?
Ja, für die Alpine-basierte Registrierung wird das Modul Hyva_Checkout benötigt. Der freie Standardtheme bringt keinen eigenen Checkout mit.
3Welche Klasse für eine eigene Zahlungsmethode erweitern?
AbstractMethod für Offline-Methoden. Für Gateway-Integrationen mit Command-Pool eher Method\\Adapter mit CommandPoolInterface.
4Wie Template registrieren?
Per referenceBlock auf checkout.payment.methods in hyva_checkout_components.xml, mit as-Attribut gleich dem Zahlungsmethodencode.
5Zahlungsmethode erscheint nicht, obwohl aktiv?
Meist stimmt der Block-Alias nicht exakt mit dem Methodencode überein. Ohne passenden Alias bleibt die Methode unsichtbar.
6Client-seitige Validierung ohne Knockout?
Alpine.data()-Komponente mit reaktiven Gettern isValid/errorMessage und einer validateBeforeSubmit()-Methode vor dem Absenden.
7Zusatzdaten in additional_information speichern?
assignData(DataObject $data) überschreiben, additional_data auslesen, per setAdditionalInformation() speichern.
8Wie funktionieren Redirect-Zahlungsarten?
getOrderPlaceRedirectUrl() aus MethodInterface implementieren. Nach place() leitet Hyvä-Checkout automatisch zum Gateway weiter.
9Kreditkartendaten im Alpine-State halten?
Nein. Hosted-Fields- oder Iframe-Tokenisierung nutzen, nur das Token landet in additional_information.
10Wie Fehlermeldungen anzeigen?
Message\\ManagerInterface für Reload-Fehler, lokaler Alpine-Fehlerzustand mit x-show/x-text für Formularfehler während der Eingabe.