Eigenes Magento 2 Modul
Schritt für Schritt erstellen
Ein sauberes Magento 2 Modul besteht nicht nur aus registration.php und module.xml. Für produktiven Code gehören Konfiguration, ACL, Admin-Menüpunkt, Layout XML, ViewModel und klare Dependency Injection dazu.
Inhaltsverzeichnis
1. Ziel des Moduls
Ein Magento 2 Modul erstellen bedeutet mehr als ein paar Dateien unter app/code abzulegen. Ein Modul ist eine eigenständige Funktionseinheit mit Name, Registrierung, Konfiguration, Berechtigungen und klaren Einstiegspunkten. In diesem Tutorial bauen wir ein kleines Modul Mironsoft_HelloModule, das eine Frontend-Seite ausgibt und über den Adminbereich aktiviert oder deaktiviert werden kann.
Der Fokus liegt auf einer Struktur, die auch in echten Projekten Bestand hat. Das Modul bekommt registration.php, etc/module.xml, etc/config.xml, etc/adminhtml/system.xml, etc/acl.xml, eine eigene Frontend-Route, einen Controller, Layout XML, ein Hyvä-kompatibles Template und ein ViewModel. Genau so sollte man ein Magento 2 Modul erstellen, wenn es nicht nur als Demo, sondern als wartbare Erweiterung gedacht ist.
Wir verwenden bewusst keine Luma-spezifischen UI Components, kein Knockout.js und kein jQuery. Für Frontend-Logik wäre in Hyvä Alpine.js die passende Wahl. In diesem Beispiel reicht serverseitiges Rendering mit einem ViewModel. Das ist schnell, testbar und passt gut zu Magento 2.4.8 mit PHP 8.4.
2. Modulstruktur anlegen
Die Modulstruktur liegt bei Magento standardmäßig unter app/code/Vendor/Module. Für dieses Tutorial ist der vollständige Pfad app/code/Mironsoft/HelloModule. Der Vendor ist Mironsoft, das Modul heißt HelloModule, der vollständige Modulname lautet Mironsoft_HelloModule. Diese Schreibweise ist wichtig, weil sie in XML-Dateien, ACL-Ressourcen, Konfiguration und CLI-Ausgaben wieder auftaucht.
Wenn du ein Magento 2 Modul erstellen willst, solltest du die Verzeichnisse von Anfang an sauber trennen. Globale Konfiguration liegt in etc. Admin-spezifische Konfiguration liegt in etc/adminhtml. Frontend-Routen liegen in etc/frontend. Templates gehören in view/frontend/templates, Layout XML in view/frontend/layout. Diese Konvention macht spätere Erweiterungen nachvollziehbar.
app/code/Mironsoft/HelloModule/
├── Controller/
│ └── Index/
│ └── Index.php
├── etc/
│ ├── acl.xml
│ ├── config.xml
│ ├── module.xml
│ ├── adminhtml/
│ │ └── system.xml
│ └── frontend/
│ └── routes.xml
├── registration.php
├── ViewModel/
│ └── Hello.php
└── view/
└── frontend/
├── layout/
│ └── hellomodule_index_index.xml
└── templates/
└── hello.phtml
Die erste Datei ist app/code/Mironsoft/HelloModule/registration.php. Sie registriert das Modul beim Magento Component Registrar. Ohne diese Datei erkennt Magento die Erweiterung nicht.
<?php
declare(strict_types=1);
use Magento\Framework\Component\ComponentRegistrar;
ComponentRegistrar::register(
ComponentRegistrar::MODULE,
'Mironsoft_HelloModule',
__DIR__
);
Danach folgt app/code/Mironsoft/HelloModule/etc/module.xml. Diese Datei beschreibt das Modul für Magento. In einfachen Modulen reicht der Name. Wenn dein Modul von anderen Modulen abhängt, würdest du hier sequence ergänzen.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Mironsoft_HelloModule"/>
</config>
Nach diesen beiden Dateien kann Magento das Modul grundsätzlich erkennen. In einer Mark-Shust-Umgebung verwendest du dafür den Wrapper, nicht direkt php bin/magento. Der typische Ablauf ist bin/magento module:status, bin/magento setup:upgrade und danach Cache leeren. In echten Projekten gehört anschließend auch Codequalität dazu: PHPStan, PHPCS und gezielte Tests.
3. Konfiguration, Systembereich und ACL
Ein produktives Magento 2 Modul sollte eigene Einstellungen enthalten. Dadurch kann der Shopbetreiber Funktionen aktivieren, Texte ändern oder Verhalten steuern, ohne Code anzufassen. Für unser Beispiel gibt es eine Einstellung enabled und einen Begrüßungstext. Die Standardwerte definieren wir in app/code/Mironsoft/HelloModule/etc/config.xml.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
<default>
<hellomodule>
<general>
<enabled>1</enabled>
<headline>Willkommen bei Mironsoft</headline>
</general>
</hellomodule>
</default>
</config>
Damit die Einstellung im Adminbereich sichtbar wird, braucht das Modul app/code/Mironsoft/HelloModule/etc/adminhtml/system.xml. Hier entsteht ein eigener Konfigurationsbereich mit eigenem Menüpunkt. Genau diesen Schritt vergessen viele Entwickler, wenn sie ein Magento 2 Modul erstellen. Das Ergebnis ist dann ein Modul ohne saubere Bedienoberfläche.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<tab id="mironsoft" translate="label" sortOrder="900">
<label>Mironsoft</label>
</tab>
<section id="hellomodule" translate="label" sortOrder="10"
showInDefault="1" showInWebsite="1" showInStore="1">
<label>Hello Module</label>
<tab>mironsoft</tab>
<resource>Mironsoft_HelloModule::config</resource>
<group id="general" translate="label" sortOrder="10"
showInDefault="1" showInWebsite="1" showInStore="1">
<label>General Settings</label>
<field id="enabled" translate="label" type="select" sortOrder="10"
showInDefault="1" showInWebsite="1" showInStore="1">
<label>Enabled</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
<field id="headline" translate="label" type="text" sortOrder="20"
showInDefault="1" showInWebsite="1" showInStore="1">
<label>Headline</label>
<comment>Displayed on the frontend example page.</comment>
</field>
</group>
</section>
</system>
</config>
Der Eintrag resource verweist auf eine ACL-Ressource. Dafür braucht das Modul app/code/Mironsoft/HelloModule/etc/acl.xml. Ohne ACL kann Magento die Admin-Berechtigung nicht sauber prüfen. Wer ein Magento 2 Modul erstellen will, sollte ACL von Anfang an mitdenken, auch bei kleinen Modulen.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Magento_Backend::stores">
<resource id="Magento_Backend::stores_settings">
<resource id="Magento_Config::config">
<resource id="Mironsoft_HelloModule::config"
title="Mironsoft Hello Module Configuration"
sortOrder="10"/>
</resource>
</resource>
</resource>
</resource>
</resources>
</acl>
</config>
4. Route, Controller, Layout und Hyvä Template
Als nächstes bekommt das Modul eine Frontend-Seite. Die Route definieren wir in app/code/Mironsoft/HelloModule/etc/frontend/routes.xml. Der frontName bestimmt die URL. In diesem Beispiel lautet sie /hellomodule. Der Controller liegt danach unter Controller/Index/Index.php.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="standard">
<route id="hellomodule" frontName="hellomodule">
<module name="Mironsoft_HelloModule"/>
</route>
</router>
</config>
Der Controller sollte dünn bleiben. Er erzeugt nur das Page-Result und enthält keine Geschäftslogik. Das passt zu moderner Magento-Architektur: Controller orchestrieren HTTP, ViewModels liefern Daten für Templates, Services enthalten Fachlogik.
<?php
declare(strict_types=1);
namespace Mironsoft\HelloModule\Controller\Index;
use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\Controller\ResultInterface;
use Magento\Framework\View\Result\PageFactory;
/**
* Renders the hello module frontend page.
*/
final class Index implements HttpGetActionInterface
{
public function __construct(
private readonly PageFactory $pageFactory
) {}
/**
* Creates the page result for the hello module route.
*/
public function execute(): ResultInterface
{
return $this->pageFactory->create();
}
}
Das Layout XML verbindet die Route mit dem Template. Der Handle ergibt sich aus Route, Controller und Action: hellomodule_index_index.xml. Die Datei liegt unter app/code/Mironsoft/HelloModule/view/frontend/layout/hellomodule_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>
<referenceContainer name="content">
<block class="Magento\Framework\View\Element\Template"
name="mironsoft.hellomodule.page"
template="Mironsoft_HelloModule::hello.phtml">
<arguments>
<argument name="view_model" xsi:type="object">Mironsoft\HelloModule\ViewModel\Hello</argument>
</arguments>
</block>
</referenceContainer>
</body>
</page>
5. ViewModel statt Block-Logik
In Hyvä-Projekten ist ein ViewModel meistens die bessere Wahl als eine eigene Block-Klasse. Das ViewModel implementiert ArgumentInterface und liefert typisierte Methoden für das Template. So bleibt die Darstellung schlank und die Datenlogik testbar. Wenn du ein Magento 2 Modul erstellen willst, das zu Hyvä passt, ist diese Trennung besonders wichtig.
Unser ViewModel liest die Konfiguration aus. Dafür nutzt es ScopeConfigInterface. Die Pfade definieren wir als Konstanten. So vermeidest du Magic Strings im Code und kannst die Werte später leichter wiederverwenden.
<?php
declare(strict_types=1);
namespace Mironsoft\HelloModule\ViewModel;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\View\Element\Block\ArgumentInterface;
use Magento\Store\Model\ScopeInterface;
/**
* Provides configuration values for the hello module template.
*/
final class Hello implements ArgumentInterface
{
/**
* Defines the enabled configuration path.
*/
private const string XML_PATH_ENABLED = 'hellomodule/general/enabled';
/**
* Defines the headline configuration path.
*/
private const string XML_PATH_HEADLINE = 'hellomodule/general/headline';
public function __construct(
private readonly ScopeConfigInterface $scopeConfig
) {}
/**
* Checks whether the module output should be visible.
*/
public function isEnabled(): bool
{
return $this->scopeConfig->isSetFlag(
self::XML_PATH_ENABLED,
ScopeInterface::SCOPE_STORE
);
}
/**
* Returns the configured frontend headline.
*/
public function getHeadline(): string
{
return (string) $this->scopeConfig->getValue(
self::XML_PATH_HEADLINE,
ScopeInterface::SCOPE_STORE
);
}
}
Zum Schluss kommt das Template app/code/Mironsoft/HelloModule/view/frontend/templates/hello.phtml. Es nutzt keine externen Skripte, kein jQuery und keine Luma-Abhängigkeiten. Werte werden escaped. Falls ein Inline-script nötig wäre, müsste in einem Hyvä-CSP-Theme direkt danach $hyvaCsp->registerInlineScript() stehen. In diesem Beispiel brauchen wir kein JavaScript.
<?php
declare(strict_types=1);
use Magento\Framework\Escaper;
use Magento\Framework\View\Element\Template;
use Mironsoft\HelloModule\ViewModel\Hello;
/**
* @var Template $block
* @var Escaper $escaper
* @var Hello $viewModel
*/
$viewModel = $block->getData('view_model');
?>
<?php if ($viewModel && $viewModel->isEnabled()): ?>
<section class="mx-auto max-w-3xl px-4 py-12">
<div class="rounded-lg border border-slate-200 bg-white p-6 shadow-sm">
<p class="text-sm font-semibold uppercase tracking-wide text-blue-700">
Mironsoft Hello Module
</p>
<h2 class="mt-2 text-2xl font-bold text-slate-900">
<?= $escaper->escapeHtml($viewModel->getHeadline()) ?>
</h2>
<p class="mt-3 text-sm leading-6 text-slate-700">
Dieses Template wird über Layout XML eingebunden und erhält seine Daten aus einem ViewModel.
</p>
</div>
</section>
<?php endif; ?>
Nach dem Anlegen der Dateien aktivierst du das Modul über die Magento-CLI im Docker-Wrapper. In diesem Projekt bedeutet das: bin/magento setup:upgrade, danach Cache leeren. Für Frontend-Änderungen im Theme wäre die Deploy-Sequenz mit Tailwind-Build, statischen Dateien und Cache relevant. Bei einem reinen Modul-Template reicht in Entwicklung oft Cache Clean, abhängig von Modus und Umgebung.
6. Vergleich: Minimal-Modul vs. produktives Modul
Viele Tutorials zeigen nur registration.php und module.xml. Das reicht, um ein Modul sichtbar zu machen, aber nicht für produktive Arbeit. Ein echtes Modul braucht klare Konfiguration, Berechtigungen, eine saubere View-Schicht und nachvollziehbare Erweiterungspunkte. Wer ein Magento 2 Modul erstellen will, sollte deshalb von Anfang an eine vollständige Struktur wählen.
| Bereich | Minimal-Modul | Produktives Modul |
|---|---|---|
| Registrierung | registration.php, module.xml | Zusätzlich klare Dependencies und Versionierungsstrategie |
| Konfiguration | Oft keine Einstellungen | config.xml, system.xml, ACL und eigener Admin-Bereich |
| Frontend | Block enthält oft Logik | Layout XML, Template und ViewModel sauber getrennt |
| Wartbarkeit | Schnell gebaut, schwer erweiterbar | Klare Pfade, testbare Klassen und stabile Verträge |
Der Unterschied zeigt sich spätestens beim zweiten Feature. Ein Minimal-Modul wird schnell unübersichtlich, weil Konfiguration, Ausgabe und Logik ineinanderlaufen. Ein produktives Modul hat mehr Dateien, aber weniger versteckte Abhängigkeiten. Genau das macht Magento-Entwicklung langfristig schneller.
Mironsoft
Magento 2 Module, Hyvä Themes und technische Architektur
Ein Magento 2 Modul sauber entwickeln lassen?
Wir entwickeln Magento 2 Erweiterungen mit Konfiguration, ACL, Service Contracts, ViewModels und Hyvä-kompatibler Ausgabe. Sauber genug für Wartung, Tests und spätere Erweiterungen.
Modulstruktur
registration.php, module.xml, config.xml, system.xml und ACL
Frontend
Layout XML, ViewModels und Hyvä Templates ohne Luma-Ballast
Qualität
PHP 8.4, Dependency Injection, Tests und klare Erweiterungspunkte
8. Zusammenfassung
Ein eigenes Magento 2 Modul erstellen heißt, eine klare, erweiterbare Struktur aufzubauen. Die Basis besteht aus registration.php und module.xml. Für ein professionelles Modul kommen config.xml, system.xml, acl.xml, Routen, Controller, Layout XML, Template und ViewModel hinzu.
Der wichtigste Architekturpunkt ist die Trennung der Verantwortlichkeiten. Controller bleiben dünn, ViewModels liefern Daten, Templates rendern HTML und Konfiguration liegt im Adminbereich. So bleibt das Modul wartbar und passt zu Magento 2.4.8, PHP 8.4 und Hyvä.
Magento 2 Modul erstellen — Das Wichtigste auf einen Blick
Pfad
app/code/Mironsoft/HelloModule mit klarer Vendor- und Modulstruktur.
Pflichtbasis
registration.php und etc/module.xml registrieren das Modul.
Admin
config.xml, system.xml und acl.xml machen Einstellungen bedienbar und berechtigbar.
Hyvä
Daten über ViewModels bereitstellen, Templates schlank halten und kein jQuery oder Knockout.js laden.
9. FAQ: Eigenes Magento 2 Modul erstellen
1 Welche Dateien braucht ein Magento 2 Modul mindestens?
registration.php und etc/module.xml. Für produktiven Code kommen Konfiguration, ACL, Routen, Layout XML und ViewModels dazu.2 Wo liegt ein eigenes Magento 2 Modul?
app/code/Vendor/Module, zum Beispiel app/code/Mironsoft/HelloModule.3 Warum braucht ein Modul system.xml?
4 Wofür ist acl.xml zuständig?
5 Block oder ViewModel für Hyvä?
ArgumentInterface meistens besser. Block-Klassen sollten nicht mit Geschäftslogik gefüllt werden.6 Wie aktiviert man ein neues Modul?
bin/magento setup:upgrade und danach Cache leeren.7 Was macht routes.xml?
frontName wird Teil der URL.8 Wie heißt der Layout-Handle?
hellomodule/index/index heißt die Layout-Datei hellomodule_index_index.xml.