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

Category Attribute: Bonus-Multiplikator pro Kategorie

Category Attribute: Bonus-Multiplikator pro Kategorie

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

catalog_category ist - genau wie catalog_product aus Kapitel 19 - eine eigenständige, bereits fertig eingerichtete EAV-Entität mit eigenem Entity-Type-Code und eigenen Wertetabellen (catalog_category_entity_decimal usw.). loyalty_bonus_category (Typ decimal, Default 0.0) ist der zweite von zwei Parametern, die PointsCalculator::calculatePoints() aus Kapitel 5 bereits als $categoryBonus entgegennimmt - ein additiver Bonus-Punktesatz, kein Multiplikator wie beim Produkt.

Der Setup-Patch für das Kategorie-Attribut

app/code/Mironsoft/Loyalty/Setup/Patch/Data/InstallCategoryLoyaltyAttribute.php
<?php

declare(strict_types=1);

namespace Mironsoft\Loyalty\Setup\Patch\Data;

use Magento\Catalog\Model\Category;
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

/**
 * Registers the loyalty_bonus_category decimal attribute on catalog_category.
 */
class InstallCategoryLoyaltyAttribute implements DataPatchInterface
{
    /**
     * @param ModuleDataSetupInterface $moduleDataSetup Provides the setup connection for the patch.
     * @param EavSetupFactory $eavSetupFactory Creates the EavSetup helper used to register the attribute.
     */
    public function __construct(
        private readonly ModuleDataSetupInterface $moduleDataSetup,
        private readonly EavSetupFactory $eavSetupFactory
    ) {
    }

    /**
     * Adds the loyalty_bonus_category attribute to the existing catalog_category entity.
     *
     * @return void
     */
    public function apply(): void
    {
        $this->moduleDataSetup->getConnection()->startSetup();

        /** @var \Magento\Eav\Setup\EavSetup $eavSetup */
        $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]);

        $eavSetup->addAttribute(Category::ENTITY, 'loyalty_bonus_category', [
            'type' => 'decimal',
            'label' => 'Loyalty Bonus',
            'input' => 'text',
            'required' => false,
            'default' => '0.0000',
            'global' => ScopedAttributeInterface::SCOPE_WEBSITE,
            'group' => 'General Information',
            'sort_order' => 100,
            'visible' => true,
            'user_defined' => true,
        ]);

        $this->moduleDataSetup->getConnection()->endSetup();
    }

    /**
     * @return array<int, string>
     */
    public static function getDependencies(): array
    {
        return [];
    }

    /**
     * @return array<int, string>
     */
    public function getAliases(): array
    {
        return [];
    }
}

Ein wichtiger Unterschied zum Produkt-Attribut

Anders als in Kapitel 19 steht der Scope hier von Anfang an auf SCOPE_WEBSITE statt SCOPE_GLOBAL - eine bewusste Entscheidung, kein Versehen. Kategorien bilden in vielen Magento-Shops unterschiedliche Sortimente pro Website ab (z. B. B2C- versus B2B-Website auf derselben Installation); ein Bonus, der auf Website-Ebene unterschiedlich hoch ausfallen kann, spiegelt diese Realität direkt wider, ohne dass Kapitel 25 hier noch nachträglich etwas ändern müsste.

group => 'General Information' statt 'General' ist kein Tippfehler: Das Standard-Attribut-Set für Kategorien nennt seine erste Gruppe tatsächlich anders als das Standard-Set für Produkte. Ein falscher Gruppenname sorgt nicht für einen Fehler beim Patch-Lauf, sondern nur dafür, dass Magento eine neue, leere Gruppe mit diesem Namen anlegt - das Attribut erscheint dann in einem unerwarteten, meist leeren Tab im Kategorie-Formular.

Achtung: catalog_category kennt - anders als catalog_product - keinen apply_to-Schlüssel; es gibt nur einen einzigen "Kategorietyp". Wird er trotzdem im Array mitgegeben, wird er von addAttribute() stillschweigend ignoriert, was beim Debuggen leicht zu falschen Annahmen führt.

Vererbung im Kategoriebaum ist kein EAV-Feature

Ein oft missverstandener Punkt: Ein Wert für loyalty_bonus_category "vererbt" sich nicht automatisch von einer übergeordneten Kategorie an ihre Unterkategorien, nur weil beide Kategorien sind. EAV kennt keine Baumstruktur-Logik - jede Kategorie speichert ihren eigenen, unabhängigen Wert (oder NULL, wenn keiner gesetzt wurde). Eine tatsächliche Vererbung müsste die aufrufende Code-Stelle selbst implementieren, etwa indem sie beim Fehlen eines Werts entlang des path-Felds der Kategorie nach oben wandert - eine Überlegung, die Kapitel 27 wieder aufgreift, wenn es um Konflikte zwischen Kategorie- und Produkt-Bonus geht.

bin/magento setup:upgrade
bin/magento indexer:reindex catalog_category_flat
bin/magento cache:flush

Tipp: Da loyalty_bonus_category pro Website unterschiedlich sein kann, lohnt es sich, den Wert im Admin für jede relevante Website tatsächlich einzeln zu prüfen - das Website-Auswahl-Dropdown im Kategorie-Formular erscheint erst, sobald im Shop mehr als eine Website konfiguriert ist, und wird bei einer Single-Website-Installation leicht übersehen, obwohl der Scope technisch korrekt gesetzt ist.

Mit Produkt- und Kategorie-Attribut abgeschlossen wechselt Kapitel 21 die Entität: Der Kunde bekommt zwei neue Attribute - einen Punktestand und eine Treue-Stufe - und damit den ersten Fall in diesem Block, der ein eigenes Source Model braucht.