Zum Inhalt springen

Shopware 6 App System vs. Plugin: Was ist der Unterschied und was soll ich nutzen?

Veröffentlicht am 15. Mai 2025 | ca. 1 Min. Lesezeit |

Seit Shopware 6.4 gibt es offiziell zwei Wege, den Shop zu erweitern: das klassische Plugin und das App System. Beide können Funktionen hinzufügen, Daten verwalten und Prozesse automatisieren — aber sie tun es auf fundamental unterschiedliche Weise. Wer ein Projekt plant, muss früh entscheiden, welchen Weg er geht, denn die Architekturen sind nicht kompatibel.

Das Plugin-Modell

Plugins sind PHP-Pakete, die direkt in den Shopware-Prozess geladen werden. Sie haben Zugriff auf alle Symfony-Dienste, den Dependency Injection Container, die Datenbank und alle Shopware-interna.

Typische Plugin-Struktur

MyPlugin/
├── composer.json
├── src/
│   ├── MyPlugin.php          # Plugin-Klasse
│   ├── Core/
│   │   └── Content/          # Custom Entities, DAL-Erweiterungen
│   ├── Service/              # Business Logic
│   └── Resources/
│       ├── config/
│       │   └── services.xml  # Service-Definitionen
│       └── views/            # Twig-Templates
└── Migration/                # Datenbank-Migrationen

Plugin-Klasse

<?php

declare(strict_types=1);

namespace MyPlugin;

use Shopware\Core\Framework\Plugin;
use Shopware\Core\Framework\Plugin\Context\InstallContext;
use Shopware\Core\Framework\Plugin\Context\UninstallContext;

class MyPlugin extends Plugin
{
    public function install(InstallContext $installContext): void
    {
        // Einmalige Initialisierung beim Installieren
    }

    public function uninstall(UninstallContext $uninstallContext): void
    {
        if ($uninstallContext->keepUserData()) {
            return;
        }

        // Datenbank-Cleanup
    }
}

Was Plugins können

  • Eigene Entities und DAL-Definitionen anlegen
  • Bestehende Entities mit eigenen Feldern erweitern
  • Symfony-Dienste registrieren und überschreiben
  • Event-Subscriber für alle Shopware-Events
  • Eigene Admin-Komponenten (Vue.js) ins Backend einbinden
  • Eigene Storefront-Templates mit Template-Inheritance
  • Direkte Datenbankoperationen mit vollem Zugriff

Plugins laufen im gleichen PHP-Prozess wie Shopware. Das bedeutet: direkter Zugriff auf alle Ressourcen, aber auch das Risiko, den gesamten Shop durch einen Fehler lahmzulegen.

Das App System

Das App System wurde eingeführt, um Erweiterungen zu ermöglichen, die außerhalb des Shopware-Prozesses laufen. Eine App ist ein externer Service, der über Webhooks und die Admin-API kommuniziert.

Typische App-Struktur

MyApp/
├── manifest.xml              # App-Manifest (kein PHP!)
├── Resources/
│   ├── views/                # Twig-Templates (für Storefront-Blöcke)
│   └── app/
│       └── administration/   # Admin-Erweiterungen
└── (externer Webserver)      # Dein eigener Service

manifest.xml

Die zentrale Datei einer App definiert alles deklarativ:

<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/shopware/shopware/trunk/src/Core/Framework/App/Manifest/Schema/manifest-2.0.xsd">
    <meta>
        <name>MyApp</name>
        <label>Meine App</label>
        <description>Eine Demo-App</description>
        <author>Wunner Software</author>
        <copyright>(c) 2025 Wunner Software</copyright>
        <version>1.0.0</version>
        <license>proprietary</license>
    </meta>

    <permissions>
        <read>order</read>
        <read>customer</read>
        <create>order_tag</create>
    </permissions>

    <webhooks>
        <webhook name="order-placed"
                 url="https://my-app.example.com/webhook/order-placed"
                 event="checkout.order.placed"/>
    </webhooks>

    <setup>
        <registrationUrl>https://my-app.example.com/register</registrationUrl>
        <!-- Hardcoded secrets are for local development only.
             In production/Store apps, the secret is exchanged automatically during the registration handshake. -->
        <secret>my-secret-for-hmac-validation</secret>
    </setup>
</manifest>

Webhook-Handler (externer Service, z.B. Symfony)

<?php

declare(strict_types=1);

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class WebhookController extends AbstractController
{
    #[Route('/webhook/order-placed', methods: ['POST'])]
    public function orderPlaced(Request $request): Response
    {
        // HMAC-Signatur prüfen
        // shopware-shop-signature is the correct header for incoming webhooks.
        // (shopware-app-signature is used for responses FROM the app, not incoming requests.)
        $signature = $request->headers->get('shopware-shop-signature');
        $body = $request->getContent();

        if (!$this->validateSignature($signature, $body)) {
            return new Response('Unauthorized', Response::HTTP_UNAUTHORIZED);
        }

        $data = json_decode($body, true);
        $orderId = $data['data']['payload']['id'] ?? null;

        if ($orderId !== null) {
            // Eigene Business-Logik: z.B. ERP-Integration
            $this->erpService->syncOrder($orderId);
        }

        return new Response('', Response::HTTP_OK);
    }

    private function validateSignature(?string $signature, string $body): bool
    {
        if ($signature === null) {
            return false;
        }

        $expected = hash_hmac('sha256', $body, 'my-secret-for-hmac-validation');

        return hash_equals($expected, $signature);
    }
}

Admin-API-Aufrufe aus der App

Die App erhält beim Registrierungsprozess einen API-Key und kann dann die Shopware-Admin-API nutzen:

<?php

declare(strict_types=1);

namespace App\Service;

use Symfony\Contracts\HttpClient\HttpClientInterface;

class ShopwareApiClient
{
    public function __construct(
        private readonly HttpClientInterface $httpClient,
        private readonly string $shopUrl,
        private readonly string $accessToken,
    ) {
    }

    public function getOrder(string $orderId): array
    {
        $response = $this->httpClient->request('GET', sprintf('%s/api/order/%s', $this->shopUrl, $orderId), [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken,
                'Content-Type' => 'application/json',
            ],
        ]);

        return $response->toArray();
    }

    public function addTagToOrder(string $orderId, string $tagId): void
    {
        $this->httpClient->request('POST', sprintf('%s/api/order/%s/tags', $this->shopUrl, $orderId), [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken,
                'Content-Type' => 'application/json',
            ],
            'json' => [['id' => $tagId]],
        ]);
    }
}

Direkter Vergleich

Kriterium Plugin App
Laufzeitumgebung Im Shopware-Prozess Externer Service
Programmiersprache PHP (erzwungen) Beliebig (PHP, Node.js, Python...)
Datenbankzugriff Direkt (DAL/SQL) Nur via Admin-API
Performance-Einfluss Direkt auf Shop Asynchron via Webhooks
Deployment Auf dem Shop-Server Eigener Server/Cloud
Shopware Cloud kompatibel Nein Ja
Template-Overrides Vollständig Begrenzt (Blocks)
Admin-Erweiterungen Vollständige Vue.js-Komponenten Begrenzt (iFrame, Module)
Fehlerrisiko für Shop Hoch (gleicher Prozess) Niedrig (isoliert)
Entwicklungskomplexität Mittel-hoch Mittel (mehr Infrastruktur)

Wann Plugin, wann App?

Plugin ist die richtige Wahl, wenn...

  • tiefer Eingriff in Shopware-Core-Logik nötig ist (z.B. Preisberechnung, Checkout-Flow)
  • eigene DAL-Entities benötigt werden, die Shopware direkt verwalten soll
  • der Shop auf einem selbstverwalteten Server läuft
  • umfangreiche Storefront-Anpassungen (Template-Inheritance) gemacht werden
  • kein externer Server betrieben werden soll

App ist die richtige Wahl, wenn...

  • der Shop auf Shopware Cloud oder bei einem Hoster läuft, der keine Plugins erlaubt
  • die Erweiterung mit externen Systemen kommuniziert (ERP, CRM, Warenwirtschaft)
  • die Logik in einer anderen Sprache oder einem bestehenden Service läuft
  • Isolation und Ausfallsicherheit wichtig sind (ein App-Fehler bremst den Shop nicht)
  • das Produkt als SaaS an mehrere Shop-Betreiber verkauft werden soll

Hybride Ansätze

In der Praxis kombiniert man oft beide Modelle:

  • Ein leichtes Plugin registriert Custom Fields oder Flow-Actions
  • Der eigentliche Business-Service läuft als App auf eigenem Server
  • Kommunikation läuft über die Admin-API und Webhooks

Das ist besonders bei komplexen B2B-Integrationsprojekten sinnvoll, bei denen Shopware als Frontend und Bestellsystem dient, aber ERP und Lager extern verwaltet werden.

Fazit

Das Plugin-Modell bleibt für lokale Shopware-Installationen die mächtigere Option, weil es direkten Zugriff auf alle Shopware-interna hat. Das App System ist flexibler in der Wahl der Technologie, isolierter und cloud-kompatibel — aber auf die Admin-API beschränkt. Wer neue Projekte plant, sollte ernsthaft das App System evaluieren, besonders wenn eine externe Service-Architektur ohnehin angedacht ist.

Thomas Wunner

Thomas Wunner

Fachinformatiker für Anwendungsentwicklung mit Ausbildereignungsprüfung und über 14 Jahre Erfahrung im Aufbau skalierbarer Webanwendungen mit Symfony und Shopware. Abseits der Tastatur ist Thomas als Rettungsschwimmer in der Wasserwacht aktiv, legt als DJ auf und erkundet die Umgebung auf dem Motorrad.

Kommentare

Kommentare werden von Remark42 bereitgestellt. Beim Laden werden Daten an unseren Kommentar-Server übertragen.