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

Admin-Formular-Anpassungen für den neuen Produkttyp

Admin-Formular-Anpassungen für den neuen Produkttyp

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

Kapitel 73 hat den Typ technisch funktionsfähig gemacht. Ohne ein Feld, in dem eingetragen werden kann, WIE VIELE Punkte ein Paket enthält, bleibt er trotzdem nutzlos. Dieses Kapitel ergänzt genau dieses Pflichtfeld - über zwei Data Patches statt UI-Component-Handarbeit, ganz im deklarativen Stil, den Kapitel 13 (Block 2) bereits für die Reward-Entity etabliert hat.

Ein eigenes Attribut-Set

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

declare(strict_types=1);

namespace Mironsoft\Loyalty\Setup\Patch\Data;

use Magento\Catalog\Model\Product;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

/**
 * Creates a dedicated "Punkte-Paket" attribute set (cloned from Default) with
 * its own "Punkte-Paket-Details" attribute group, so
 * loyalty_points_package_amount (the next patch) has a natural home instead
 * of cluttering the Default set that every other product type shares.
 */
class InstallPointsPackageAttributeSet implements DataPatchInterface
{
    /**
     * @param ModuleDataSetupInterface $moduleDataSetup Provides the setup connection for the patch
     * @param EavSetupFactory $eavSetupFactory Creates the EavSetup helper used to manage attribute sets
     */
    public function __construct(
        private readonly ModuleDataSetupInterface $moduleDataSetup,
        private readonly EavSetupFactory $eavSetupFactory,
    ) {
    }

    /**
     * Clones the Default attribute set into a new "Punkte-Paket" set and adds
     * a dedicated attribute group to it.
     *
     * @return void
     */
    public function apply(): void
    {
        $this->moduleDataSetup->getConnection()->startSetup();

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

        $defaultSetId = (int) $eavSetup->getAttributeSetId(Product::ENTITY, 'Default');
        $eavSetup->addAttributeSet(Product::ENTITY, 'Punkte-Paket', $defaultSetId, 100);

        $attributeSetId = (int) $eavSetup->getAttributeSetId(Product::ENTITY, 'Punkte-Paket');
        $eavSetup->addAttributeGroup(Product::ENTITY, $attributeSetId, 'Punkte-Paket-Details', 10);

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

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

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

addAttributeSet() klont das übergebene $skeletonId - hier die ID des Default-Sets - inklusive aller bestehenden Gruppen und Attribute. Ein Punkte-Paket-Produkt behält dadurch automatisch Name, SKU, Preis, Beschreibung und alle anderen Standardfelder; nur die neue Gruppe Punkte-Paket-Details kommt hinzu.

Die Punkte-Menge als Pflichtfeld

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

declare(strict_types=1);

namespace Mironsoft\Loyalty\Setup\Patch\Data;

use Magento\Catalog\Model\Product;
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;
use Mironsoft\Loyalty\Model\Product\Type\PointsPackage;

/**
 * Registers the required loyalty_points_package_amount integer attribute,
 * scoped via apply_to to the loyalty_points_package product type only
 * (chapter 71's decisive argument for a dedicated type), and attaches it to
 * the "Punkte-Paket" attribute set/group from the previous patch.
 */
class InstallPointsPackageAmountAttribute 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 loyalty_points_package_amount to catalog_product and wires it into
     * the "Punkte-Paket" attribute set's dedicated group.
     *
     * @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(Product::ENTITY, 'loyalty_points_package_amount', [
            'type' => 'int',
            'label' => 'Points Amount',
            'input' => 'text',
            'required' => true,
            'global' => ScopedAttributeInterface::SCOPE_GLOBAL,
            'group' => 'Punkte-Paket-Details',
            'sort_order' => 10,
            'visible' => true,
            'user_defined' => true,
            'apply_to' => PointsPackage::TYPE_CODE,
            'used_in_product_listing' => false,
        ]);

        $attributeSetId = (int) $eavSetup->getAttributeSetId(Product::ENTITY, 'Punkte-Paket');
        $attributeGroupId = (int) $eavSetup->getAttributeGroupId(Product::ENTITY, $attributeSetId, 'Punkte-Paket-Details');
        $attributeId = (int) $eavSetup->getAttributeId(Product::ENTITY, 'loyalty_points_package_amount');

        $eavSetup->addAttributeToGroup(Product::ENTITY, $attributeSetId, $attributeGroupId, $attributeId, 10);

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

    /**
     * @return array<int, string>
     */
    public static function getDependencies(): array
    {
        return [\Mironsoft\Loyalty\Setup\Patch\Data\InstallPointsPackageAttributeSet::class];
    }

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

required => true allein reicht nicht aus, um das Feld korrekt einzugrenzen - addAttribute() hängt ein neues Attribut standardmäßig nur an das Default-Set (Kapitel 19 hat das schon einmal gezeigt). Der explizite addAttributeToGroup()-Aufruf am Ende verankert das Attribut zusätzlich in der neuen Punkte-Paket-Gruppe.

Achtung: Zwei unabhängige Filter, nicht einer: Damit loyalty_points_package_amount im Admin tatsächlich erscheint, müssen BEIDE Bedingungen gleichzeitig erfüllt sein - das Produkt trägt den Typ-Code loyalty_points_package (geprüft über apply_to) UND das Attribut-Set Punkte-Paket ist ausgewählt (geprüft über die Set/Gruppen-Zuordnung). Typ und Attribut-Set sind in Magento zwei komplett getrennte Entscheidungen im Produktformular - ein Redakteur könnte theoretisch den Typ "Punkte-Paket" mit dem Set "Default" kombinieren. Dann fehlt das Pflichtfeld im Formular komplett, ohne Fehlermeldung, weil apply_to zwar passt, aber die Set/Gruppen-Zuordnung nicht existiert. Praxis-Empfehlung: eine kurze interne Redaktionsrichtlinie ("Punkte-Paket-Produkte immer mit Typ UND Set 'Punkte-Paket' anlegen") ersetzt hier keine technische Absicherung, ist aber der pragmatischste erste Schritt.

Optionale Fieldset-Beschriftung

Ohne weiteren Eingriff rendert Magento die neue Attributgruppe bereits als eigenes, aufklappbares Fieldset im Produktformular - benannt nach dem Gruppennamen. Wer die Darstellung darüber hinaus feinjustieren möchte (Reihenfolge relativ zu anderen Fieldsets, Sichtbarkeitsbedingungen, Feldtyp-Overrides jenseits des EAV-input-Werts), greift zu einer UI-Component-Erweiterung von product_form.xml:

app/code/Mironsoft/Loyalty/view/adminhtml/ui_component/product_form.xml
<?xml version="1.0"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <fieldset name="punkte-paket-details">
        <settings>
            <label translate="true">Punkte-Paket</label>
            <collapsible>true</collapsible>
            <sortOrder>90</sortOrder>
        </settings>
    </fieldset>
</form>

Tipp: Die vollständige UI-Component-Mechanik hinter product_form.xml - Data Provider, Modifiers, dataScope, Feldsichtbarkeit per JavaScript - sprengt den Rahmen dieses Kapitels und wird in der separaten Serie "Admin-Grids & Formulare in Magento 2" dieses Katalogs vertieft, genau wie schon beim Reward-Grid in Kapitel 16 und beim Page-Builder-Formular in Kapitel 59.

Mit Attribut-Set, Pflichtfeld und optionaler Fieldset-Beschriftung lässt sich ein Punkte-Paket jetzt vollständig im Admin anlegen. Kapitel 75 kümmert sich als Nächstes um die Storefront-Seite dieses Produkts.