Shopware 6 Development
Core Architecture
Shopware 6 is a PHP/Symfony platform. Clarify which layer is being targeted before generating code:
| Layer |
Tech |
Where |
| Core / PHP |
PHP 8.2+, Symfony 7.4 (SW 6.7) / Symfony 7.0 (SW 6.6) |
src/ — Services, DAL, Events |
| Storefront |
Twig 3, SCSS, Vanilla JS, Vite dev server (6.7.11+) |
src/Resources/views/storefront/ |
| Admin |
Vue 3, Pinia, Meteor components (mt-*), Vite build |
src/Resources/app/administration/ |
| App System |
manifest.xml (schema 3.0 in 6.7), App Scripts |
External server or Twig scripts (no PHP needed) |
Plugin vs App System: Use Plugin for self-hosted installs needing direct PHP/DB access. Use App System for SaaS/multi-tenant or when targeting the Shopware Store.
Which version is this?
Ask or infer the target version before generating code. The current line is 6.7.13.x; 6.8 is planned
for 2027. 6.7 broke a lot of plugin-facing API, so code that is correct for 6.6 is often wrong for 6.7:
| Topic |
SW 6.6 |
SW 6.7 |
| Payment handler |
Synchronous/AsynchronousPaymentHandlerInterface |
AbstractPaymentHandler |
| Admin components |
sw-button, sw-card, sw-text-field |
mt-button, mt-card, mt-text-field |
| Admin state |
Vuex Shopware.State (deprecated) |
Pinia Shopware.Store only |
| Admin build |
Webpack |
Vite |
EntityExtension |
getDefinitionClass() |
plus abstract getEntityName() |
| Plugin custom entities |
entities.xml |
removed, use EntityDefinition |
IdsCollection |
Shopware\Core\Framework\Test\ |
Shopware\Core\Test\Stub\Framework\ |
Full list in references/migration-6.7.md. When the version is unknown,
target 6.7 and mention what differs on 6.6.
Plugin Structure
PluginName/
├── composer.json
├── src/
│ ├── PluginName.php # Bootstrap class
│ ├── Resources/
│ │ ├── config/
│ │ │ └── services.xml # Symfony DI container
│ │ ├── views/
│ │ │ └── storefront/ # Twig template overrides
│ │ └── app/
│ │ └── administration/ # Vue.js admin extensions
│ └── Migration/ # Database migrations
└── tests/
Plugin Bootstrap
<?php declare(strict_types=1);
namespace VendorName\PluginName;
use Shopware\Core\Framework\Plugin;
class PluginName extends Plugin {}
Only extend install(), activate(), deactivate(), uninstall() when lifecycle actions are needed (e.g., creating payment methods, dropping tables on uninstall).
Five Core Workflows
1. Register a Service (DI)
<!-- services.xml -->
<service id="VendorName\PluginName\Service\MyService">
<argument type="service" id="product.repository"/>
</service>
Common tags: kernel.event_subscriber, twig.extension, console.command, messenger.message_handler, shopware.entity.definition, shopware.entity.extension, shopware.rule.definition, shopware.payment.method.sync, shopware.payment.method.async, shopware.cms.element.
2. Listen to Events (Subscriber)
class ProductSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return ['product.written' => 'onProductWritten'];
}
public function onProductWritten(EntityWrittenEvent $event): void
{
foreach ($event->getWriteResults() as $result) {
$id = $result->getPrimaryKey();
}
}
}
3. DAL Read & Write
// Read
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('active', true));
$criteria->addAssociation('manufacturer');
$result = $this->productRepository->search($criteria, $context);
// Write
$this->productRepository->upsert([
['id' => $id, 'name' => 'New Name'],
], $context);
4. Override a Storefront Template
{# Mirrors original path under views/storefront/ #}
{% sw_extends '@Storefront/storefront/page/product-detail/index.html.twig' %}
{% block page_product_detail_content %}
<div class="my-banner">Custom content</div>
{{ parent() }}
{% endblock %}
5. Decorate a Service
<service id="VendorName\PluginName\Decorator\MyDecorator"
decorates="original.service.id">
<argument type="service"
id="VendorName\PluginName\Decorator\MyDecorator.inner"/>
</service>
Karpathy Principles — Clarify Before Coding
Surface these assumptions before generating code:
- Version? SW 6.5 vs 6.6 (API and Vue component differences exist)
- Plugin or App System? Plugin = PHP server; App = manifest.xml + external/no server
- Layer? PHP/Core, Storefront, Admin, or headless/Store API
- Read or write? Repository
search() vs upsert()/create()/update()
- Entity or extension? New table vs extending existing entity
Write only the minimum code that solves the problem. Shopware's DI and event system handle most complexity.
DAL Quick Reference
// Criteria
$criteria->addFilter(new EqualsFilter('active', true));
$criteria->addFilter(new ContainsFilter('name', 'shirt'));
$criteria->addFilter(new RangeFilter('price', [RangeFilter::GTE => 10]));
$criteria->addAssociation('manufacturer');
$criteria->addSorting(new FieldSorting('name', FieldSorting::ASCENDING));
$criteria->setLimit(25)->setOffset(0);
// Context
$context = Context::createDefaultContext(); // system
// OR inject SalesChannelContext from route / event
// IDs only (faster, no hydration)
$ids = $this->repo->searchIds($criteria, $context)->getIds();
Admin Vue.js Quick Reference
// Register module
Shopware.Module.register('my-module', {
type: 'plugin',
routes: { index: { component: 'my-module-index', path: 'index' } },
navigation: [{ label: 'my-module.title', path: 'my.module.index', icon: 'default-shopping-paper-bag' }],
});
// Override existing component
Shopware.Component.override('sw-product-detail', {
methods: {
async saveProduct() {
await this.$super('saveProduct'); // call original
},
},
});
CLI Commands
bin/console plugin:install --activate PluginName
bin/console database:migrate --all PluginName
bin/console cache:clear
bin/console plugin:refresh
bin/build-administration.sh
bin/build-storefront.sh
bin/console theme:compile
php vendor/bin/phpunit --testsuite=unit
vendor/bin/phpstan analyse src --level=8
Additional Resources
Reference Files
Load these when working on specific areas:
- references/dal.md — DAL: EntityDefinition, Criteria, Aggregations, custom fields, Entity Extensions (extend core entities)
- references/admin.md — Admin: Vue modules, components, overrides, naming conventions, ACL privileges, filter/inline edit, search config
- references/storefront.md — Storefront: Twig inheritance, SCSS/theme variables, JavaScript plugins, controllers
- references/themes.md — Themes: theme.json (config fields, colors, fonts, media), SCSS Bootstrap overrides, theme inheritance, ThemeInterface, CLI commands
- references/cart.md — Cart: CartDataCollector, CartProcessor, CartValidator + custom errors, discount line items, price manipulation, Tax Provider
- references/seo-mail.md — SEO: SeoUrlRoute, sitemap URL provider; Mail: custom mail templates (migration + send); Documents (custom PDF types); Order State Machine (transitions, events)
- references/plugin-structure.md — Full plugin anatomy: services.xml, lifecycle hooks, composer.json, console commands, scheduled tasks
- references/api.md — Admin API & Store API: CRUD, bulk, filters; context token lifecycle, Cart/Checkout/Account Store API, TypeScript client pattern
- references/testing.md — PHPUnit unit/integration, StaticEntityRepository, ProductBuilder, Jest, Cypress, assertSame vs assertEquals
- references/app-system.md — App System: manifest.xml, webhook HMAC verification, registration handshake, App Scripts (Twig-based, no server)
- references/security.md — Security: route scopes, CSRF protection, input validation, authorization by customer, SQL injection prevention
- references/integrations.md — Integrations: Payment Handler (
AbstractPaymentHandler), shipping costs (cart processor, not a calculator tag), CMS Elements, Rule Builder conditions, Flow Builder events
- references/performance.md — Performance: HTTP Cache (tags, invalidation), Message Queue (async processing), Elasticsearch/OpenSearch, object cache
- references/devops.md — DevOps: structured logging, PHPStan, php-cs-fixer, CI/CD, deployment, debugging, media handling, upgrade safety
- references/migration-6.7.md — 6.6 to 6.7 migration: breaking changes across Core/DAL, Admin, Storefront, cache, API, hosting, plus what 6.7.x added (Vite dev server, Twig UX components, MCP server)
- references/advanced.md — Advanced: PHP Attributes entities (SW 6.6.3+), Flysystem (public/private file storage), Redis (cache/queue), Rate Limiter (compiler pass + RateLimiter service), Data Indexer, Field Inheritance (variants), In-App Purchases
Examples
Working code examples in examples/:
- examples/custom-entity/ — Runnable plugin: Definition, Entity, Collection, Migration, versioned FK to
product, uninstall cleanup
- examples/storefront-subscriber/ — Runnable plugin: page subscriber, sales channel repository, Twig override, snippets
1---2name: shopware63description: Shopware 6 development across plugins, apps and themes: DAL entities, migrations, custom fields and entity extensions, Storefront (Twig, SCSS, JS plugin system), Admin (Vue 3, Meteor Admin SDK), Admin API and Store API, cart processors, collectors and validators, payment and shipping handlers, rule builder conditions, CMS elements, App System manifests and webhooks, SEO URLs, mail templates, state machines, message queue, Elasticsearch, HTTP cache, PHPUnit and Jest testing, security and deployment. Use when the user asks to create a Shopware plugin, subscriber, custom entity or admin module, override a Storefront template, decorate a service, write a DAL migration, or handle any other Shopware 6 development task.4---56# Shopware 6 Development78## Core Architecture910Shopware 6 is a PHP/Symfony platform. Clarify which layer is being targeted before generating code:1112| Layer | Tech | Where |13|---|---|---|14| **Core / PHP** | PHP 8.2+, Symfony 7.4 (SW 6.7) / Symfony 7.0 (SW 6.6) | `src/` — Services, DAL, Events |15| **Storefront** | Twig 3, SCSS, Vanilla JS, Vite dev server (6.7.11+) | `src/Resources/views/storefront/` |16| **Admin** | Vue 3, Pinia, Meteor components (`mt-*`), Vite build | `src/Resources/app/administration/` |17| **App System** | manifest.xml (schema 3.0 in 6.7), App Scripts | External server or Twig scripts (no PHP needed) |1819**Plugin vs App System:** Use Plugin for self-hosted installs needing direct PHP/DB access. Use App System for SaaS/multi-tenant or when targeting the Shopware Store.2021### Which version is this?2223Ask or infer the target version before generating code. The current line is **6.7.13.x**; 6.8 is planned24for 2027. 6.7 broke a lot of plugin-facing API, so code that is correct for 6.6 is often wrong for 6.7:2526| Topic | SW 6.6 | SW 6.7 |27|---|---|---|28| Payment handler | `Synchronous`/`AsynchronousPaymentHandlerInterface` | `AbstractPaymentHandler` |29| Admin components | `sw-button`, `sw-card`, `sw-text-field` | `mt-button`, `mt-card`, `mt-text-field` |30| Admin state | Vuex `Shopware.State` (deprecated) | Pinia `Shopware.Store` only |31| Admin build | Webpack | Vite |32| `EntityExtension` | `getDefinitionClass()` | plus abstract `getEntityName()` |33| Plugin custom entities | `entities.xml` | removed, use `EntityDefinition` |34| `IdsCollection` | `Shopware\Core\Framework\Test\` | `Shopware\Core\Test\Stub\Framework\` |3536Full list in **[references/migration-6.7.md](references/migration-6.7.md)**. When the version is unknown,37target 6.7 and mention what differs on 6.6.3839---4041## Plugin Structure4243```44PluginName/45├── composer.json46├── src/47│ ├── PluginName.php # Bootstrap class48│ ├── Resources/49│ │ ├── config/50│ │ │ └── services.xml # Symfony DI container51│ │ ├── views/52│ │ │ └── storefront/ # Twig template overrides53│ │ └── app/54│ │ └── administration/ # Vue.js admin extensions55│ └── Migration/ # Database migrations56└── tests/57```5859### Plugin Bootstrap6061```php62<?php declare(strict_types=1);6364namespace VendorName\PluginName;6566use Shopware\Core\Framework\Plugin;6768class PluginName extends Plugin {}69```7071Only extend `install()`, `activate()`, `deactivate()`, `uninstall()` when lifecycle actions are needed (e.g., creating payment methods, dropping tables on uninstall).7273---7475## Five Core Workflows7677### 1. Register a Service (DI)7879```xml80<!-- services.xml -->81<service id="VendorName\PluginName\Service\MyService">82 <argument type="service" id="product.repository"/>83</service>84```8586Common tags: `kernel.event_subscriber`, `twig.extension`, `console.command`, `messenger.message_handler`, `shopware.entity.definition`, `shopware.entity.extension`, `shopware.rule.definition`, `shopware.payment.method.sync`, `shopware.payment.method.async`, `shopware.cms.element`.8788### 2. Listen to Events (Subscriber)8990```php91class ProductSubscriber implements EventSubscriberInterface92{93 public static function getSubscribedEvents(): array94 {95 return ['product.written' => 'onProductWritten'];96 }9798 public function onProductWritten(EntityWrittenEvent $event): void99 {100 foreach ($event->getWriteResults() as $result) {101 $id = $result->getPrimaryKey();102 }103 }104}105```106107### 3. DAL Read & Write108109```php110// Read111$criteria = new Criteria();112$criteria->addFilter(new EqualsFilter('active', true));113$criteria->addAssociation('manufacturer');114$result = $this->productRepository->search($criteria, $context);115116// Write117$this->productRepository->upsert([118 ['id' => $id, 'name' => 'New Name'],119], $context);120```121122### 4. Override a Storefront Template123124```twig125{# Mirrors original path under views/storefront/ #}126{% sw_extends '@Storefront/storefront/page/product-detail/index.html.twig' %}127128{% block page_product_detail_content %}129 <div class="my-banner">Custom content</div>130 {{ parent() }}131{% endblock %}132```133134### 5. Decorate a Service135136```xml137<service id="VendorName\PluginName\Decorator\MyDecorator"138 decorates="original.service.id">139 <argument type="service"140 id="VendorName\PluginName\Decorator\MyDecorator.inner"/>141</service>142```143144---145146## Karpathy Principles — Clarify Before Coding147148Surface these assumptions before generating code:149150- **Version?** SW 6.5 vs 6.6 (API and Vue component differences exist)151- **Plugin or App System?** Plugin = PHP server; App = manifest.xml + external/no server152- **Layer?** PHP/Core, Storefront, Admin, or headless/Store API153- **Read or write?** Repository `search()` vs `upsert()`/`create()`/`update()`154- **Entity or extension?** New table vs extending existing entity155156Write only the minimum code that solves the problem. Shopware's DI and event system handle most complexity.157158---159160## DAL Quick Reference161162```php163// Criteria164$criteria->addFilter(new EqualsFilter('active', true));165$criteria->addFilter(new ContainsFilter('name', 'shirt'));166$criteria->addFilter(new RangeFilter('price', [RangeFilter::GTE => 10]));167$criteria->addAssociation('manufacturer');168$criteria->addSorting(new FieldSorting('name', FieldSorting::ASCENDING));169$criteria->setLimit(25)->setOffset(0);170171// Context172$context = Context::createDefaultContext(); // system173// OR inject SalesChannelContext from route / event174175// IDs only (faster, no hydration)176$ids = $this->repo->searchIds($criteria, $context)->getIds();177```178179---180181## Admin Vue.js Quick Reference182183```js184// Register module185Shopware.Module.register('my-module', {186 type: 'plugin',187 routes: { index: { component: 'my-module-index', path: 'index' } },188 navigation: [{ label: 'my-module.title', path: 'my.module.index', icon: 'default-shopping-paper-bag' }],189});190191// Override existing component192Shopware.Component.override('sw-product-detail', {193 methods: {194 async saveProduct() {195 await this.$super('saveProduct'); // call original196 },197 },198});199```200201---202203## CLI Commands204205```bash206bin/console plugin:install --activate PluginName207bin/console database:migrate --all PluginName208bin/console cache:clear209bin/console plugin:refresh210bin/build-administration.sh211bin/build-storefront.sh212bin/console theme:compile213php vendor/bin/phpunit --testsuite=unit214vendor/bin/phpstan analyse src --level=8215```216217---218219## Additional Resources220221### Reference Files222223Load these when working on specific areas:224225- **[references/dal.md](references/dal.md)** — DAL: EntityDefinition, Criteria, Aggregations, custom fields, **Entity Extensions** (extend core entities)226- **[references/admin.md](references/admin.md)** — Admin: Vue modules, components, overrides, **naming conventions**, **ACL privileges**, **filter/inline edit**, search config227- **[references/storefront.md](references/storefront.md)** — Storefront: Twig inheritance, SCSS/theme variables, JavaScript plugins, controllers228- **[references/themes.md](references/themes.md)** — Themes: **theme.json** (config fields, colors, fonts, media), SCSS Bootstrap overrides, **theme inheritance**, ThemeInterface, CLI commands229- **[references/cart.md](references/cart.md)** — Cart: **CartDataCollector**, **CartProcessor**, **CartValidator** + custom errors, **discount line items**, price manipulation, Tax Provider230- **[references/seo-mail.md](references/seo-mail.md)** — SEO: **SeoUrlRoute**, sitemap URL provider; Mail: **custom mail templates** (migration + send); **Documents** (custom PDF types); **Order State Machine** (transitions, events)231- **[references/plugin-structure.md](references/plugin-structure.md)** — Full plugin anatomy: services.xml, lifecycle hooks, composer.json, console commands, scheduled tasks232- **[references/api.md](references/api.md)** — Admin API & Store API: CRUD, bulk, filters; **context token lifecycle**, **Cart/Checkout/Account Store API**, TypeScript client pattern233- **[references/testing.md](references/testing.md)** — PHPUnit unit/integration, **StaticEntityRepository**, **ProductBuilder**, Jest, Cypress, assertSame vs assertEquals234- **[references/app-system.md](references/app-system.md)** — App System: **manifest.xml**, **webhook HMAC verification**, **registration handshake**, **App Scripts** (Twig-based, no server)235- **[references/security.md](references/security.md)** — Security: route scopes, **CSRF protection**, input validation, authorization by customer, SQL injection prevention236- **[references/integrations.md](references/integrations.md)** — Integrations: **Payment Handler** (`AbstractPaymentHandler`), **shipping costs** (cart processor, not a calculator tag), **CMS Elements**, **Rule Builder** conditions, Flow Builder events237- **[references/performance.md](references/performance.md)** — Performance: **HTTP Cache** (tags, invalidation), **Message Queue** (async processing), **Elasticsearch/OpenSearch**, object cache238- **[references/devops.md](references/devops.md)** — DevOps: **structured logging**, PHPStan, php-cs-fixer, CI/CD, deployment, debugging, **media handling**, upgrade safety239- **[references/migration-6.7.md](references/migration-6.7.md)** — **6.6 to 6.7 migration**: breaking changes across Core/DAL, Admin, Storefront, cache, API, hosting, plus what 6.7.x added (Vite dev server, Twig UX components, MCP server)240- **[references/advanced.md](references/advanced.md)** — Advanced: **PHP Attributes entities** (SW 6.6.3+), **Flysystem** (public/private file storage), **Redis** (cache/queue), **Rate Limiter** (compiler pass + RateLimiter service), **Data Indexer**, **Field Inheritance** (variants), **In-App Purchases**241242### Examples243244Working code examples in `examples/`:245246- **[examples/custom-entity/](examples/custom-entity/)** — Runnable plugin: Definition, Entity, Collection, Migration, versioned FK to `product`, uninstall cleanup247- **[examples/storefront-subscriber/](examples/storefront-subscriber/)** — Runnable plugin: page subscriber, sales channel repository, Twig override, snippets