Ein PrestaShop-9-Modul entwickeln: vom Grundgerüst bis zur Produktion
Ein PrestaShop-Modul kann äußerst klein sein.
Im einfachsten Fall enthält das Modulverzeichnis eine PHP-Hauptdatei mit demselben Namen wie das Verzeichnis.
Ein Produktionsmodul benötigt jedoch häufig wesentlich mehr:
- Dienste;
- Hooks;
- Datenbanktabellen;
- Symfony-Controller;
- CLI-Befehle;
- Konfiguration;
- Protokolle;
- Upgrade-Skripte;
- Sicherheitsprüfungen;
- Tests.
PrestaShop 9 verwendet Symfony 6.4 und setzt die Migration der Plattform zu einer modernen Symfony-Architektur fort. Dadurch wird ein sauberer, dienstorientierter Modulentwurf wichtiger denn je.
Dieser Leitfaden führt durch die Architektur eines umfassenden PrestaShop-9-Moduls und endet nicht bei „Hello World“.
Versionshinweis: Dieser Leitfaden wurde am 22. September 2026 anhand der aktuellen PrestaShop-9-Entwicklerdokumentation überprüft.
1. Die Verantwortung des Moduls festlegen
Legen Sie vor dem Erstellen von Dateien fest, wofür das Modul zuständig ist.
Ein gutes Modul hat einen klaren geschäftlichen Zweck.
Beispiele:
Bestandsfilterung
Lieferantenimport
Sicherheitsüberwachung
Upselling-Regeln
Bestellexport
Vermeiden Sie ein Modul, das nach und nach für nicht zusammenhängende Funktionen zuständig wird.
Wenn ein Modul Folgendes enthält:
- SEO;
- Bestand;
- Sicherheit;
- Versand;
- Analysen;
- Import;
wird seine Wartung und Prüfung schwierig.
2. Den technischen Namen wählen
Das PrestaShop-Modultutorial verlangt einen technischen Modulnamen aus alphanumerischen Kleinbuchstaben und Ziffern.
Zum Beispiel:
mymodule
Die Hauptdatei des Moduls muss denselben Namen haben:
/modules/mymodule/mymodule.php
Die offizielle Dokumentation rät von Unterstrichen in technischen Namen ab, da sie mit Übersetzungsdomänen nicht gut funktionieren.
3. Mit einer sauberen Ordnerstruktur beginnen
Eine auf den Produktionsbetrieb ausgerichtete Struktur könnte so aussehen:
mymodule/
├── mymodule.php
├── composer.json
├── config/
│ ├── services.yml
│ └── routes.yml
├── src/
│ ├── Controller/
│ ├── Service/
│ ├── Repository/
│ ├── Command/
│ ├── Domain/
│ └── ApiPlatform/
├── views/
│ ├── templates/
│ ├── css/
│ └── js/
├── sql/
│ ├── install.php
│ └── uninstall.php
├── upgrade/
└── translations/
Sie benötigen nicht sofort jeden Ordner.
Ergänzen Sie die Struktur, sobald eine Zuständigkeit entsteht.
4. Die Hauptklasse des Moduls klein halten
Die Hauptklasse des Moduls sollte nicht die gesamte Geschäftslogik enthalten.
Sie sollte Dinge koordinieren wie:
- Metadaten;
- Installation;
- Hook-Registrierung;
- Einstiegspunkte für die Konfiguration.
Vermeiden Sie es, Folgendes zu schreiben:
2.000 Zeilen
innerhalb von:
class MyModule extends Module
Verschieben Sie die Anwendungslogik in Dienste.
5. Eine einfache Modulhauptklasse
Ein minimales Modul beginnt etwa so:
<?php
if (!defined('_PS_VERSION_')) {
exit;
}
class MyModule extends Module
{
public function __construct()
{
$this->name = 'mymodule';
$this->version = '1.0.0';
$this->author = 'Your Company';
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l('My Module');
$this->description = $this->l('Example PrestaShop 9 module.');
}
}
Die tatsächliche Produktionsklasse enthält in der Regel mehr Metadaten und Installationslogik.
6. Die Installation vor den Funktionen entwerfen
Entscheiden Sie, was die Installation erstellt.
Mögliche Ressourcen sind:
- Hooks;
- Konfigurationsschlüssel;
- Datenbanktabellen;
- Tabs;
- Berechtigungen.
Ein Fehlschlag der Installation sollte sauber behandelt werden.
Zum Beispiel:
public function install()
{
return parent::install()
&& $this->registerHook('displayHeader')
&& $this->installDatabase();
}
Wenn die Datenbankerstellung fehlschlägt, lassen Sie das Modul nicht halb installiert zurück, ohne das Problem zu melden.
7. Hooks gezielt registrieren
Hooks ermöglichen es Modulen, auf PrestaShop-Ereignisse zu reagieren oder Inhalte anzuzeigen.
Die PrestaShop-Konvention unterscheidet:
actionSomething
von:
displaySomething
Action-Hooks reagieren auf Ereignisse.
Display-Hooks rendern Inhalte.
Registrieren Sie Hooks während der Installation:
$this->registerHook('displayHeader');
Implementieren Sie anschließend:
public function hookDisplayHeader(array $params)
{
// logic
}
8. Aufwendige Arbeit in globalen Hooks vermeiden
Ein Hook kann auf jeder Seite ausgeführt werden.
Platzieren Sie keine:
- Anfragen an Lieferanten-APIs;
- riesigen Datenbankabfragen;
- vollständigen Katalogscans;
in einem globalen Display-Hook.
Ein Display-Hook sollte idealerweise bereits vorbereitete Daten rendern.
Wenn Daten aktualisiert werden müssen, verwenden Sie:
- Cache;
- Cron;
- Warteschlange;
- Hintergrund-Worker.
9. Dienste für die Geschäftslogik erstellen
Eine Dienstklasse sollte eine Anwendungszuständigkeit abbilden.
Beispiel:
ProductSyncService
IntegrityScanner
UpsellRuleEvaluator
StockFilterService
Der Controller sollte den Dienst aufrufen.
Der Dienst sollte nicht von HTTP abhängen, sofern seine Aufgabe dies nicht erfordert.
Dadurch lässt sich der Code wiederverwenden über:
- Backoffice;
- CLI;
- Cron;
- API.
10. Dependency Injection verwenden
Die Symfony-Architektur von PrestaShop 9 unterstützt Dependency Injection.
Anstatt:
$repo = new ProductRepository();
$logger = new Logger();
in jeder Methode zu verwenden, injizieren Sie die Abhängigkeiten.
Konzeptionell:
public function __construct(
ProductRepository $repository,
LoggerInterface $logger
) {
$this->repository = $repository;
$this->logger = $logger;
}
Zu den Vorteilen gehören:
- Testbarkeit;
- klare Abhängigkeiten;
- einfacherer Austausch;
- Container-Validierung.
11. Dienste konfigurieren
Eine typische Dienstdatei eines Moduls könnte Folgendes verwenden:
services:
_defaults:
public: false
autowire: true
autoconfigure: true
Vendor\Module\:
resource: '../src/'
Passen Sie die Ressourcengrenzen sorgfältig an.
Registrieren Sie Klassen, die keine Dienste sein sollten, nicht automatisch.
12. PrestaShop-9-Controller müssen Dienste sein
Die aktuelle PrestaShop-9-Dokumentation weist ausdrücklich darauf hin, dass moderne Controller als Dienste definiert werden müssen.
Ein Controller kann folgendermaßen konfiguriert werden:
services:
Vendor\Module\Controller\Admin\ExampleController:
autowire: true
autoconfigure: true
tags:
- { name: controller.service_arguments }
oder über die Standardwerte der Dienste.
Ist der Controller nicht korrekt registriert, schlägt er fehl.
13. Controller schlank halten
Ein Controller sollte:
- die Anfrage entgegennehmen;
- autorisieren;
- Eingaben validieren;
- den Dienst aufrufen;
- die Antwort zurückgeben.
Schreiben Sie kein direktes SQL und keine Importlogik unmittelbar in Controller-Methoden.
Schlanke Controller erleichtern beim Modul:
- das Testen;
- die Wiederverwendung;
- die Wartung.
14. Routen für moderne Seiten verwenden
Moderne Backoffice-Seiten sollten Symfony-Routing verwenden.
Eine Routendatei könnte konzeptionell so aussehen:
mymodule_dashboard:
path: /mymodule/dashboard
methods: [GET]
defaults:
_controller: 'Vendor\Module\Controller\Admin\DashboardController::index'
Verwenden Sie Routennamen einheitlich.
Vermeiden Sie Kollisionen mit anderen Modulen.
15. Konfigurationsseiten mit Blick auf den Geltungsbereich erstellen
Ein einfaches Modul kann Einstellungen in der PrestaShop-Konfiguration speichern.
Entscheiden Sie jedoch, ob Werte:
- global gelten;
- für eine Shopgruppe gelten;
- shopspezifisch sind.
Multistore-Fehler entstehen häufig dadurch, dass der Geltungsbereich ignoriert wird.
Eine Einstellung wie:
URL der Lieferanten-API
kann für jeden Shop unterschiedlich sein.
Eine andere Einstellung wie:
globaler Lizenzserver
kann gemeinsam genutzt werden.
Definieren Sie zuerst die fachliche Bedeutung.
16. Datenbanktabellen für Skalierbarkeit entwerfen
Benötigt das Modul Persistenz, entwerfen Sie Tabellen anhand tatsächlicher Zugriffsmuster.
Für eine Warteschlangentabelle:
CREATE TABLE ps_mymodule_queue (
id_queue BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
id_shop INT UNSIGNED NOT NULL,
status VARCHAR(32) NOT NULL,
payload LONGTEXT NULL,
attempts INT UNSIGNED NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
PRIMARY KEY (id_queue)
);
Fragen Sie anschließend, welche Abfragen ausgeführt werden.
Wenn Worker häufig nach Folgendem filtern:
id_shop + status
fügen Sie einen passenden Index hinzu.
17. Ungeprüfte Benutzereingaben in SQL vermeiden
Verketten Sie niemals nicht vertrauenswürdige Werte zu SQL.
Schlecht:
$sql = "SELECT * FROM table WHERE name = '" . $_GET['name'] . "'";
Verwenden Sie PrestaShop-Datenbankhelfer und sicheres Escaping oder gegebenenfalls parametrisierte DBAL-Abfragen.
Auch Lieferantendaten sind nicht vertrauenswürdig.
Ein entfernter XML-Feed sollte nicht allein deshalb als sicher gelten, weil er von einem Geschäftspartner stammt.
18. Upgrade-Skripte für Schemaänderungen hinzufügen
Ein Produktionsmodul entwickelt sich weiter.
Fügen Sie bei Schemaänderungen versionierte Upgrade-Logik hinzu.
Beispiel:
upgrade/upgrade-1.1.0.php
Das Upgrade sollte:
- eine zusammenhängende Änderung vornehmen;
- Fehler eindeutig zurückmelden;
- nach Möglichkeit sicher erneut ausführbar sein.
Verstecken Sie Datenbankmigrationen nicht in beliebigem Laufzeitcode.
19. Codeversion und Datenmigrationslogik trennen
Eine Fehlerbehebung, die nur PHP ändert, erfordert nicht zwingend eine Datenbankmigration.
Eine Schemaänderung dagegen schon.
Beispiele, die eine Migration erfordern:
- neue Tabelle;
- neue Spalte;
- neuer Index;
- neuer erforderlicher Konfigurationsschlüssel.
Halten Sie die Versionierung aussagekräftig.
20. CLI-Befehle für aufwendige Aufgaben hinzufügen
PrestaShop verwendet die Symfony-Console-Komponente.
Modulentwickler können eigene Befehle hinzufügen.
Verwenden Sie die CLI für:
- Importe;
- Exporte;
- Integritätsprüfungen;
- Bereinigung;
- Bildverarbeitung;
- Warteschlangen-Worker.
Ein Befehl kann über Cron geplant werden.
Das ist wesentlich sicherer, als von einem Administrator zu verlangen, einen Browser-Tab geöffnet zu halten.
21. Nützliche Exit-Codes zurückgeben
CLI-Befehle sollten Folgendes zurückgeben:
0 = Erfolg
Wert ungleich null = Fehler
Dadurch können:
- Cron;
- Monitoring;
- CI/CD;
Fehler erkennen.
Geben Sie nicht „fehlgeschlagen“ aus und melden dennoch Erfolg zurück.
22. Lange Befehle mit Sperren versehen
Cron-Ausführungen können sich überschneiden.
Wenn der Befehl jede Minute ausgeführt wird, aber drei Minuten dauert, können doppelte Worker entstehen.
Verwenden Sie:
- Datenbank-Lease;
- Symfony-Sperre;
- Redis-Sperre;
- Dateisystemsperre.
Die Sperre sollte nach Abstürzen wiederherstellbar sein.
23. Stapelverarbeitung fortsetzbar machen
Verarbeiten Sie nicht Millionen von Datensätzen als einen einzigen undurchsichtigen Vorgang.
Speichern Sie:
Cursor
verarbeitet
fehlgeschlagen
Wiederholung
Dann zwingt ein Absturz den Auftrag nicht dazu, wieder bei null zu beginnen.
24. Strukturierten Kontext protokollieren
Protokolle sollten beantworten:
- welcher Shop?
- welches Produkt?
- welcher Auftrag?
- welche externe ID?
- welcher Fehler?
Beispiel:
[run=203]
[shop=2]
[product=119019]
Zuordnung der Lieferantenkategorie fehlt
Das ist wesentlich nützlicher als:
Etwas ist schiefgelaufen
25. Keine Geheimnisse protokollieren
Schreiben Sie niemals:
- API-Token;
- Passwort;
- OAuth-Client-Secret;
- Zahlungsdaten;
in Protokolle.
Bereinigen Sie den Ausnahmekontext, bevor Sie ihn speichern.
26. Bei Bedarf API-Ressourcen hinzufügen
PrestaShop-9-Module können Ressourcen über die neue Admin-API bereitstellen.
Die Konvention lautet:
src/ApiPlatform/Resources
Verwenden Sie dies, wenn das Modul eine strukturierte externe Integration benötigt.
Erstellen Sie keinen eigenen öffentlichen PHP-Endpunkt, nur weil sich damit schneller ein Prototyp bauen lässt.
27. Eng begrenzte API-Scopes definieren
Wenn Ihr Modul Folgendes bereitstellt:
Sicherheitsprüfung ausführen
Prüfbericht lesen
erstellen Sie getrennte Scopes wie:
security_scan_run
security_report_read
Verlangen Sie keine sachfremden Kernberechtigungen.
28. Datei-Uploads validieren
Wenn das Modul Dateien importiert, prüfen Sie:
- Größe;
- Dateiendung;
- MIME-Typ;
- erfolgreiches Parsen.
Ein Dateiname mit der Endung .xml beweist nicht, dass die Datei gültiges XML enthält.
Eine .jpg-URL kann HTML zurückgeben.
Validieren Sie den tatsächlichen Inhalt.
29. Entfernte Downloads absichern
Entfernte URLs können Risiken durch serverseitige Anfragefälschung verursachen.
Wenn Administratoren oder Lieferanten URLs angeben, beschränken Sie gefährliche Ziele.
Erlauben Sie einem Modul nicht, ohne Schutzmaßnahmen beliebige interne Netzwerkadressen abzurufen.
Verwenden Sie:
- URL-Validierung;
- Positivlisten für URL-Schemata;
- Zeitlimit;
- Begrenzungen der Antwortgröße.
30. Multistore ausdrücklich berücksichtigen
Bei jeder Abfrage sollte gefragt werden:
Ist dieser Datensatz global oder shopspezifisch?
Bei shopspezifischen Daten nehmen Sie id_shop in Folgendes auf:
- Tabelle;
- Index;
- Eindeutigkeitsbedingungen;
- Cache-Schlüssel.
Beispiel:
UNIQUE(id_shop, supplier_key)
kann dort richtig sein, wo:
UNIQUE(supplier_key)
einen anderen Shop fälschlich blockieren würde.
31. Den Shopkontext in Cron testen
CLI-Aufträge haben keinen von einer Person ausgewählten Backoffice-Shopkontext.
Setzen oder übergeben Sie den Shopkontext ausdrücklich.
Verlassen Sie sich nicht auf den Shop, den ein Mitarbeiter zuletzt ausgewählt hat.
32. Saubere Fehlerantworten erstellen
Ajax- oder API-Aufrufe sollten strukturierte Fehler zurückgeben.
Beispiel:
{
"success": false,
"code": "CATEGORY_MAPPING_MISSING",
"message": "Supplier category 341 is not mapped."
}
Das lässt sich leichter verarbeiten als eine unverarbeitete Symfony-Ausnahmeseite.
33. Die Installation aus dem Release-ZIP testen
Entwicklungsumgebungen können Paketierungsfehler verbergen.
Vor der Veröffentlichung:
- ZIP erstellen;
- auf einer sauberen PrestaShop-9-Instanz installieren;
- konfigurieren;
- kritische Funktionen ausführen.
Das deckt Folgendes auf:
- fehlende Composer-Dateien;
- falsche Groß- und Kleinschreibung in Dateinamen;
- fehlende Assets;
- nicht berücksichtigte Build-Dateien.
34. Upgrades von früheren Versionen testen
Eine Neuinstallation allein reicht nicht aus.
Installieren Sie:
v1.0.0
mit realistischen Daten.
Aktualisieren Sie anschließend auf:
v1.1.0
Überprüfen Sie:
- Schema;
- Konfiguration;
- Geschäftsdaten;
- Hooks.
Viele Produktionsfehler treten nur bei Upgrades auf.
35. Statische Analyse hinzufügen
Verwenden Sie Werkzeuge wie:
- PHPStan;
- PHP CS Fixer;
- Prüfungen von Coding-Standards.
Statische Analyse erkennt:
- falsche Argumenttypen;
- fehlende Klassen;
- unmögliche Zweige;
- Probleme mit Werten, die null sein können.
Das ist besonders wertvoll, wenn Sie mehrere PHP-Versionen unterstützen.
36. Automatisierte Tests hinzufügen
Nicht alles benötigt einen vollständigen Browsertest.
Verwenden Sie:
- Unit-Tests für Dienste;
- Repository-Tests für Persistenz;
- Integrationstests für Installation und Upgrade;
- Funktionstests für Controller.
Konzentrieren Sie sich zuerst auf Abläufe, die Geschäftsdaten beschädigen können.
Beispiele:
- Bestellexport;
- Bestandsaktualisierung;
- Produkterstellung.
37. Nur unterstützen, was Sie tatsächlich testen
Geben Sie nicht Folgendes an:
PrestaShop 1.7–9.x
wenn Sie diesen Bereich nicht tatsächlich testen.
Ein engeres Kompatibilitätsversprechen, das funktioniert, ist besser als ein breites, das Supportanfragen erzeugt.
38. Betriebsanforderungen dokumentieren
Wenn Ihr Modul Folgendes benötigt:
- Cron;
- CLI;
- beschreibbares Verzeichnis;
- API-Schlüssel;
- PHP-Erweiterung;
geben Sie dies klar an.
Administratoren sollten Betriebsanforderungen nicht erst durch Fehlermeldungen entdecken.
39. Das Verhalten bei der Deinstallation planen
Entscheiden Sie, was Deinstallation bedeutet.
Soll sie Folgendes löschen:
- die Konfiguration?
- den Warteschlangenverlauf?
- die Audit-Datensätze?
- die fachlichen Zuordnungen?
Erwägen Sie bei wichtigen Daten eine gesonderte Option „Daten löschen“, statt automatisch alles zu vernichten.
40. Checkliste für ein produktionsreifes Modul
Architektur
- kleine Modulhauptklasse
- Geschäftslogik in Diensten
- getrennte Repositories
- schlanke Controller
- injizierte Abhängigkeiten
Datenbank
- Installationsschema
- nützliche Indizes
- Upgrade-Migrationen
- Multistore-Bedingungen
Hintergrundverarbeitung
- CLI-Befehl
- Sperrung
- Stapelverarbeitung
- Wiederholungsstatus
- Fortschrittsverfolgung
Sicherheit
- Autorisierung
- CSRF, wo erforderlich
- sicheres SQL
- Dateivalidierung
- Bereinigung von Geheimnissen
Veröffentlichung
- saubere ZIP-Installation getestet
- Upgrade getestet
- statische Analyse
- Tests kritischer Abläufe
- Deinstallation getestet
Häufig gestellte Fragen
Was ist die Mindeststruktur eines PrestaShop-Moduls?
Ein Modul benötigt einen Ordner und eine PHP-Hauptdatei mit demselben technischen Namen. Produktionsmodule ergänzen in der Regel Dienste, Routen, Controller und weitere Strukturelemente.
Darf der technische Name Unterstriche enthalten?
Das offizielle PrestaShop-9-Tutorial rät von Unterstrichen ab, da sie mit Übersetzungsdomänen nicht korrekt funktionieren.
Sind Symfony-Controller in PrestaShop 9 Dienste?
Ja. Die aktuelle Dokumentation besagt, dass PrestaShop-9-Controller als Dienste konfiguriert werden müssen.
Sollte die Geschäftslogik in der Modulhauptklasse liegen?
Nutzen Sie für umfangreiche Geschäftslogik bevorzugt Dienste. Konzentrieren Sie die Hauptklasse auf den Modullebenszyklus und die Integrationspunkte.
Kann ein Modul Konsolenbefehle hinzufügen?
Ja. PrestaShop verwendet Symfony Console, und Module können eigene Befehle bereitstellen.
Können Module die Admin-API erweitern?
Ja. PrestaShop 9 kann Modul-API-Ressourcen automatisch aus src/ApiPlatform/Resources laden, wenn das Modul installiert und aktiviert ist.
Sollten lange Importe in einem Controller ausgeführt werden?
Nein. Verwenden Sie CLI, Cron oder Warteschlangen-Worker mit Stapelverarbeitung und Fortschrittsverfolgung.
Was sollte ich vor dem Verkauf eines Moduls testen?
Mindestens: saubere Installation, Konfiguration, kritische Funktionen, Upgrade, gegebenenfalls Multistore-Verhalten, Paketierung und Deinstallation.