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

Layout-XML für die neuen Seiten

Layout-XML für die neuen Seiten

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

Drei Controller aus diesem Block rendern eine volle Seite: History\Index (Kapitel 45), Catalog\Index und Catalog\View (Kapitel 49). Jeder braucht eine Layout-XML-Datei, deren Name aus Route-ID, Controller- und Actionname folgt - {route_id}_{controller}_{action}, wobei route_id hier mironsoft_loyalty ist, der interne frontName-Wert aus Kapitel 45, unabhängig von der hübschen Store-URL aus Kapitel 46.

Neue Layout-Handles aus Block 6

app/code/Mironsoft/Loyalty/view/frontend/layout/
├── mironsoft_loyalty_history_index.xml   # History\Index
├── mironsoft_loyalty_catalog_index.xml    # Catalog\Index
└── mironsoft_loyalty_catalog_view.xml     # Catalog\View
                                            # (KEINE Datei für redeem_index - siehe unten)

history_index: mit Account-Navigation

<update handle="customer_account"/> zieht automatisch die komplette "Mein Konto"-Seitenstruktur inklusive Sidebar-Navigation ein - kein eigenes Markup dafür nötig, dasselbe Handle, das jede Core-"Mein Konto"-Unterseite (Bestellungen, Adressen, ...) referenziert.

app/code/Mironsoft/Loyalty/view/frontend/layout/mironsoft_loyalty_history_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"
      layout="2columns-left">
    <update handle="customer_account"/>
    <body>
        <referenceBlock name="page.main.title">
            <arguments>
                <argument name="page_title" xsi:type="string" translate="true">My Points History</argument>
            </arguments>
        </referenceBlock>
        <referenceContainer name="content">
            <block class="Magento\Framework\View\Element\Template"
                   name="loyalty.history"
                   template="Mironsoft_Loyalty::history/index.phtml">
                <arguments>
                    <argument name="view_model" xsi:type="object">Mironsoft\Loyalty\ViewModel\PointsHistory</argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

Mironsoft\Loyalty\ViewModel\PointsHistory ist ein weiterer, kleiner ViewModel nach demselben Muster wie PointsBalance (Kapitel 48): injiziert CustomerSession und PointsLedgerRepositoryInterface (Kapitel 6) und stellt getEntries(): array (PointsLedgerInterface[]) für das Template bereit. Der Code folgt exakt dem in Kapitel 48 gezeigten Muster und wird hier nicht wiederholt.

catalog_index und catalog_view

app/code/Mironsoft/Loyalty/view/frontend/layout/mironsoft_loyalty_catalog_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"
      layout="1column">
    <body>
        <referenceContainer name="content">
            <block class="Magento\Framework\View\Element\Template"
                   name="loyalty.catalog.list"
                   template="Mironsoft_Loyalty::catalog/index.phtml">
                <arguments>
                    <argument name="view_model" xsi:type="object">Mironsoft\Loyalty\ViewModel\RewardCatalog</argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>
app/code/Mironsoft/Loyalty/view/frontend/layout/mironsoft_loyalty_catalog_view.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"
      layout="1column">
    <body>
        <referenceContainer name="content">
            <block class="Magento\Framework\View\Element\Template"
                   name="loyalty.catalog.detail"
                   template="Mironsoft_Loyalty::catalog/view.phtml">
                <arguments>
                    <argument name="view_model" xsi:type="object">Mironsoft\Loyalty\ViewModel\RewardDetail</argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

Beide nutzen bewusst layout="1column" statt 2columns-left: Anders als die Historie-Seite sind Katalog und Detailseite auch für Gäste gedacht (Kapitel 49) und gehören inhaltlich nicht zu "Mein Konto", brauchen also keine Account-Sidebar.

Warum es keine redeem_index.xml gibt

Achtung: Redeem\Index (Kapitel 50) rendert nie eine Seite - jeder Codepfad in execute() endet mit einem Redirect-Result, nie mit einem Page-Result. Eine Layout-Datei für den Handle mironsoft_loyalty_redeem_index anzulegen wäre nicht nur überflüssig, sondern ein Zeichen für ein Missverständnis: POST-Actions, die etwas verändern, sollten grundsätzlich mit einer Weiterleitung enden statt mit gerendertem HTML - sonst würde ein erneutes Absenden per Browser-"Zurück"-Taste (das berüchtigte "Formular erneut senden?"-Problem) die Prämie ein zweites Mal einlösen. Dieselbe Regel gilt für jede schreibende Action in Magento, nicht nur für dieses Modul.

Tipp: bin/magento setup:upgrade ist für neue Layout-XML-Dateien nicht erforderlich - Layout wird zur Laufzeit aus dem Dateisystem gelesen, nicht in der Datenbank gepflegt. Ein einfaches bin/cache-clean layout reicht, um eine neue oder geänderte Datei sichtbar zu machen (siehe die Deploy-Sequenz in CLAUDE.md, die für CSS-Änderungen einen zusätzlichen Static-Content-Schritt vorschreibt - für reine Layout-XML-Änderungen entfällt der).