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

Adding a "My Points" Customer Account Menu Item

Adding a "My Points" Customer Account Menu Item

~6 Min. Lesezeit Zuletzt aktualisiert am August 9, 2026

The history page (chapter 45) is now reachable, but linked from nowhere - a customer would have to guess the URL. This chapter adds a navigation link to the "My Account" sidebar, already visible on the history page thanks to <update handle="customer_account"/> from chapter 51, plus a points balance summary on the account dashboard - the latter by reusing the PointsBalance view model from chapter 48, without a single new PHP class.

Core modules like Magento_Sales ("My Orders") and Magento_Catalog ("Wish List") add their links exactly this way: as a Magento\Framework\View\Element\Html\Link\Current block inside the customer-account-navigation container, registered in default.xml so the link appears on every "My Account" subpage, not just the history page itself:

app/code/Mironsoft/Loyalty/view/frontend/layout/default.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>
        <referenceContainer name="customer-account-navigation">
            <block class="Magento\Framework\View\Element\Html\Link\Current"
                   name="customer-account-navigation-loyalty-history-link"
                   after="customer-account-navigation-orders-link">
                <arguments>
                    <argument name="path" xsi:type="string">mironsoft_loyalty/history/index</argument>
                    <argument name="label" xsi:type="string" translate="true">My Points</argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

Tipp: The path value deliberately uses the technical route mironsoft_loyalty/history/index from chapter 45, not the pretty URL from chapter 46. "My Account" pages carry a noindex by default anyway (see the robots meta settings under Content > Design > Configuration) and are never linked to externally - the SEO motivation behind the pretty URL from chapter 46 simply doesn't apply here. Html\Link\Current also automatically sets a class="current" as soon as the current request matches this exact path - picked up again in chapter 54 for aria-current.

The name/after reference - and why it isn't mandatory

after="customer-account-navigation-orders-link" is an optional positioning hint (Magento's layout sorting system, the same principle as sortOrder on plugins, chapter 43) - without it, the link would simply land somewhere in the container, usually at the end. The exact block name of the orders link can differ slightly between Magento minor versions; bin/magento dev:di:info won't help here (that's a layout, not a DI, concept) - instead, view-source: on the delivered page shows the actually rendered block names as HTML comments, provided template hints are enabled (Stores > Configuration > Advanced > Developer > Debug).

Points balance on the dashboard: reuse instead of rebuilding

The customer dashboard (Magento_Customer, layout handle customer_account_index) gets a second instance of the PointsBalance view model from chapter 48 - exactly the reason that view model was deliberately built with no coupling to any specific page:

app/code/Mironsoft/Loyalty/view/frontend/layout/customer_account_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>
        <referenceContainer name="content">
            <block class="Magento\Framework\View\Element\Template"
                   name="loyalty.points.balance.dashboard"
                   template="Mironsoft_Loyalty::widget/points-balance.phtml"
                   before="-">
                <arguments>
                    <argument name="view_model" xsi:type="object">Mironsoft\Loyalty\ViewModel\PointsBalance</argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

Two different block name values (loyalty.points.balance from chapter 51 vs. loyalty.points.balance.dashboard here), but the same template and the same view model - Magento requires unique block names per page, not per module, and two entirely independent pages are free to reference the same view model as many times as they like.

Achtung: before="-" places the block as the first child in the content container - on a dashboard heavily extended by other modules (order status widgets, a newsletter box, ...) this can lead to an unexpected positioning conflict if another module uses the same trick. In practice it's worth checking the actual order with template hints enabled before a production rollout, rather than blindly relying on before="-".

Tipp: Chapter 53 finally shows the actual .phtml templates behind all these layout files - Tailwind classes in this project's Hyvä style, responsive, with Alpine.js for the small interactive pieces.