Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Zahlungsart im Checkout: die Knockout.js-Frontend-Komponente registrieren

Zahlungsart im Checkout: die Knockout.js-Frontend-Komponente registrieren

~8 Min. Lesezeit Zuletzt aktualisiert am 9. August 2026

Server-seitig ist "Mit Treuepunkten bezahlt" jetzt vollständig: registriert (Kapitel 62), verfügbarkeitsgeprüft (Kapitel 64), buchungsfähig (Kapitel 63). Ohne eine Frontend-Komponente taucht sie im Payment-Step trotzdem nicht auf - und diese Komponente bricht mit einer Grundregel dieses Projekts.

Eine bewusste, eng begrenzte Ausnahme von "kein Knockout.js"

Achtung: CLAUDE.md ist eindeutig: kein Knockout.js, kein jQuery, keine UI Components im Hyvä-Storefront - Alpine.js statt dessen. Kapitel 60 hat bereits gezeigt, dass diese Regel für view/adminhtml gar nicht gilt, weil der gesamte Magento-Admin seit Version 2.0 auf Knockout.js aufbaut, unabhängig vom Hyvä-Theme-Wechsel im Frontend. Dieses Kapitel ist etwas anderes: Die Dateien unten liegen unter view/frontend/ - und verstoßen dort trotzdem bewusst gegen die Regel. Der Grund: Magentos eigener Checkout (Magento_Checkout) ist selbst eine in sich geschlossene Knockout.js-Single-Page-Application. Jeder Schritt - Versandadresse, Versandart, Zahlungsart, Übersicht - wird über UI-Component-Layout-XML und Knockout-View-Models gerendert, komplett unabhängig davon, welches Theme die restlichen Storefront-Seiten ausliefert. Eine Zahlungsart-Frontend-Komponente MUSS sich in genau dieses System einfügen, weil es keinen anderen Einhängepunkt für den Payment-Step gibt - solange der Shop Magentos eigenen Core-Checkout nutzt (und keine separate, Hyvä-eigene Checkout-Erweiterung installiert ist, die diesen Schritt komplett ersetzt, was in diesem Projekt nach aktuellem Stand nicht der Fall ist). Diese Ausnahme bleibt strikt auf view/frontend/web/js/view/payment/... und das zugehörige Template begrenzt - kein einziges anderes Storefront-Template dieses Moduls (Kapitel 53, 56/57, 59) nutzt Knockout.js, und das bleibt so.

Layout-XML: Registrierung des Renderers

Seit Magento 2.3 registrieren offizielle Zahlungsarten (z. B. Magento_OfflinePayments, Scheck/Nachnahme) ihren Renderer direkt über Layout-XML statt über das ältere rendererList.push()-Muster mit requirejs-config.js-Mixins. Dieses Kapitel folgt dem moderneren Weg:

app/code/Mironsoft/Loyalty/view/frontend/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">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="checkout" xsi:type="array">
                            <item name="children" xsi:type="array">
                                <item name="steps" xsi:type="array">
                                    <item name="children" xsi:type="array">
                                        <item name="billing-step" xsi:type="array">
                                            <item name="children" xsi:type="array">
                                                <item name="payment" xsi:type="array">
                                                    <item name="children" xsi:type="array">
                                                        <item name="renders" xsi:type="array">
                                                            <item name="children" xsi:type="array">
                                                                <item name="mironsoft_loyalty_points" xsi:type="array">
                                                                    <item name="component" xsi:type="string">Mironsoft_Loyalty/js/view/payment/method-renderer/points-redemption-method</item>
                                                                    <item name="methods" xsi:type="array">
                                                                        <item name="mironsoft_loyalty_points" xsi:type="array">
                                                                            <item name="isBillingAddressRequired" xsi:type="boolean">false</item>
                                                                        </item>
                                                                    </item>
                                                                </item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

Tipp: Das ältere rendererList.push()-Muster (eigene view/frontend/web/js/view/payment-method-renderer-list.js plus requirejs-config.js-Mixin auf Magento_Checkout/js/view/payment/renderer-list-registration) funktioniert weiterhin und ist in älteren Drittanbieter-Zahlungsarten häufig zu finden - für neuen Code ist die Layout-XML-Variante oben vorzuziehen, weil sie keinen eigenen RequireJS-Modul-Umweg braucht.

Die Knockout-View-Model-Komponente

Der RequireJS-Modulpfad Mironsoft_Loyalty/js/view/payment/method-renderer/points-redemption-method löst automatisch zur Datei view/frontend/web/js/view/payment/method-renderer/points-redemption-method.js auf - dieselbe Vendor_Modul/js/...-Konvention wie bei jedem anderen RequireJS-Modul in Magento:

app/code/Mironsoft/Loyalty/view/frontend/web/js/view/payment/method-renderer/points-redemption-method.js
define([
    'jquery',
    'Magento_Checkout/js/view/payment/default',
    'Magento_Checkout/js/model/quote',
    'Magento_Checkout/js/model/totals',
    'mage/url'
], function ($, Component, quote, totals, url) {
    'use strict';

    /**
     * Checkout-module Knockout.js view model for the "Mit Treuepunkten bezahlt"
     * payment step - NOT Hyvä/Alpine.js code, see the surrounding chapter text
     * for why this file exists at all in an otherwise Alpine.js-only project.
     * Everything this component needs (points balance, conversion rate) arrives
     * pre-baked via window.checkoutConfig, set by PointsRedemptionConfigProvider
     * (chapter 62).
     */
    return Component.extend({
        defaults: {
            template: 'Mironsoft_Loyalty/payment/points-redemption-form'
        },

        /**
         * Reads the payment method code this renderer is registered for.
         *
         * @return {String}
         */
        getCode: function () {
            return window.checkoutConfig.mironsoftLoyalty.methodCode;
        },

        /**
         * Reads the customer's current points balance from the checkout config.
         *
         * @return {Number}
         */
        getPointsBalance: function () {
            return window.checkoutConfig.mironsoftLoyalty.pointsBalance;
        },

        /**
         * Sends the requested points amount to the ApplyPoints controller
         * (chapter 63) and refreshes the checkout totals afterward, so the
         * grand total shown to the customer matches what chapter 39's
         * server-side plugin has already applied.
         *
         * @param {Number} points Points the customer wants to redeem
         * @return {void}
         */
        applyPoints: function (points) {
            $.ajax({
                url: url.build('mironsoft_loyalty/ajax/applypoints'),
                type: 'POST',
                data: {points: points},
                dataType: 'json'
            }).done(function (response) {
                if (response.success) {
                    totals.isLoading(true);
                    quote.totals.valueHasMutated();
                    totals.isLoading(false);
                }
            });
        }
    });
});
app/code/Mironsoft/Loyalty/view/frontend/web/template/payment/points-redemption-form.html
<div class="payment-method" data-bind="css: {'_active': (getCode() === isChecked())}">
    <div class="payment-method-title field choice">
        <input type="radio"
               name="payment[method]"
               class="radio"
               data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()"/>
        <label class="label" data-bind="attr: {'for': getCode()}">
            <span data-bind="i18n: 'Mit Treuepunkten bezahlt'"></span>
        </label>
    </div>
    <div class="payment-method-content" data-bind="visible: getCode() === isChecked()">
        <p data-bind="text: getPointsBalance() + ' Punkte verfügbar'"></p>
        <button type="button" class="action primary" data-bind="click: function() { applyPoints(getPointsBalance()); }">
            <span data-bind="i18n: 'Alle Punkte einlösen'"></span>
        </button>
    </div>
</div>

Achtung: Stimmt der Schlüssel im renders-Array der Layout-XML (mironsoft_loyalty_points) nicht exakt mit dem Methodencode aus PointsRedemptionConfigProvider::METHOD_CODE überein, erscheint keine Fehlermeldung in der Browser-Konsole - die Zahlungsart fehlt einfach stillschweigend in der Liste, obwohl isAvailable() (Kapitel 64) true zurückgibt. Kapitel 70 nimmt diese Falle noch einmal auf.

Damit ist die Zahlungsart im Checkout vollständig sichtbar und funktionsfähig. Block 8 wendet sich jetzt der zweiten Hälfte zu: eigenen Versandarten, beginnend wieder ganz am Anfang mit den Grundlagen.