tenbruggencate / multibrand-lite
Shopware 6 multi-brand layer: serve up to 5 brand domains from one shop, hostname-resolved brand tokens injected into the page head.
Package info
bitbucket.org/Bruggencate/sw-plugin-multibrand-lite
Type:shopware-platform-plugin
pkg:composer/tenbruggencate/multibrand-lite
Requires
- php: >=8.1
- shopware/core: ~6.7
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.94
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11.0
- shopware/storefront: ~6.7
- dev-main
- 2.1.0
- 2.0.0
- 1.5.0
- 1.4.1
- 1.4.0
- 1.3.1
- 1.3.0
- 1.2.2
- 1.2.1
- dev-feat/suite-catalog-lite-pro-pairings
- dev-feat/rename-to-lite-package
- dev-feat/tb-suite-card
- dev-docs/cross-promotion
- dev-docs/lite-pro-strategy-resync-2
- dev-docs/handbook-sync
- dev-docs/lite-pro-strategy-resync
- dev-docs/readme-branding
- dev-chore/refresh-screenshots-v1.4.1
- dev-chore/audit-fixes-v1.4.0
- dev-chore/docs-screenshots-v1.3.1
- dev-chore/ux-polish-v1.3.0
- dev-chore/packagist-description-and-multi-sc-fix
- dev-chore/initial-extraction
This package is auto-updated.
Last update: 2026-05-24 01:04:37 UTC
README
Multi-Brand Lite
![]()
Hostname-driven brand layer for Shopware 6. One Shopware instance serves multiple brand domains; each request resolves to a brandKey in Twig and a set of --brand-* CSS custom properties in the page head.
License: MIT ยท Shopware: 6.7.x ยท PHP: 8.1 / 8.2
๐ฌ๐ง English ยท ๐ณ๐ฑ Nederlands ยท ๐ฉ๐ช Deutsch
Lite tier โ and what's coming in Pro
Multi-Brand Lite (this package, tenbruggencate/multibrand-lite) is the free tier of the Multi-Brand family. It handles the foundation: hostname-based brand resolution, per-brand theme variables (CSS custom properties), Twig helpers, and per-sales-channel config. If you just need "serve brand A from brand-a.tld and brand B from brand-b.tld with their own colours, fonts and logo", Lite is the whole answer.
Multi-Brand Pro (coming as tenbruggencate/multibrand-pro) will layer on the per-brand content + commerce surfaces that the Lite tier deliberately leaves out:
- Per-brand CMS pages โ distinct landing pages, About, FAQ etc. per brand without forking the sales channel
- Per-brand email templates โ order confirmations, shipping notifications, password resets all branded per host
- Per-brand checkout & shipping rules โ different payment methods, shipping costs or thresholds per brand
- Brand-specific analytics โ segment Matomo / Plausible dashboards per brand for clean per-brand reporting
- Brand A/B testing โ run experiments scoped to one brand without polluting the others
Pro is on the roadmap, not yet released. Lite alone is production-ready for the "shared catalogue, separate visual identity" use case and stays free.
Screenshots
Storefront homepage โ desktop, multibrand resolved per host |
Storefront homepage โ mobile (responsive) |
What it does
Serving two or three brand domains from a single Shopware install normally forces you to either (a) fork templates per brand or (b) duplicate the whole store as separate sales channels. Both paths are expensive to maintain. This plugin takes the middle path:
- One host โ one
brandKeyโ configure which hostnames resolve to which brand in the admin - Per-brand CSS tokens โ amethyst vs forest vs whatever you want, emitted as
var(--brand-primary)etc. so the same SCSS compiles once and renders differently per host - Twig helper โ
{{ brand() }}returns the current brand object; templates stay simple
No per-brand plugins, no duplicate theme compilation, no forked templates. Just a thin resolution layer and a token system.
Install
Multi-Brand Lite is free and distributable via Composer / Packagist or via the Shopware Store.
composer require tenbruggencate/multibrand-lite
bin/console plugin:refresh
bin/console plugin:install --activate TenBruggencateMultiBrand
bin/console cache:clear
The plugin class name stays TenBruggencateMultiBrand (grandfathered from v1.x โ only the composer package name changed in v2.0.0). If you're upgrading from v1.x see the v2.0.0 changelog entry for the one-line composer manifest update.
Configuration
Configurable per sales channel from Settings โ System โ Plugins โ Multi-Brand Layer.
| Field | Purpose |
|---|---|
brands | JSON-editable list of { key, label, hosts[], tokens{} } entries |
defaultBrand | Fallback brandKey when no host matches (e.g. on admin preview URLs) |
tokenPrefix | CSS custom-property prefix (default --brand-) |
Tokens in each brand entry are free-form โ ship whatever your theme reads. Common examples: primary, secondary, surface, text-strong, accent-1, accent-2.
Usage
In any Twig template:
{% set brand = brand() %}
<body data-brand="{{ brand.key }}">
<h1>Welcome to {{ brand.label }}</h1>
</body>
meta.html.twig automatically emits the <style> block with --brand-* tokens; your SCSS reads them with graceful fallbacks:
.button--primary {
background: var(--brand-primary, #7C5BA5); // amethyst fallback
}
Standards
- Performance โ resolution happens once per request, cached per host. Token block adds ~400 bytes to
<head>; no runtime JS. - SEO โ no impact on URL structure, canonicals, or sitemaps. Each brand's sales channel retains its own SEO settings.
- WCAG โ CSS custom properties are a progressive enhancement; colour-contrast guarantees must be satisfied per-brand by the theme consuming the tokens (this plugin doesn't enforce them). Axe audit on a storefront page with the resolver active (0 violations on the plugin's own injection; theme-owned violations out of scope):
docs/ACCESSIBILITY.md. - GDPR โ stateless. No cookies, no tracking, no data stored per visitor. Full data-flow + subject-rights documentation in
GDPR.md. - Security โ host resolution uses
Request::getHost()(trusted-proxy aware); no user-controllable input touches the brand lookup. - Uninstall โ
plugin:uninstall --keep-user-datapreserves all brand config;plugin:uninstallwithout the flag drops everyTenBruggencateMultiBrand.config.*row so the destructive path leaves no trace. No owned tables.
Production-readiness checklist
A deliberately short list of things to verify before enabling the plugin on a customer-facing storefront. Not legal cover โ the MIT license already disclaims warranty โ but practical guidance an experienced operator would want anyway.
- [ ] Configure
trusted_proxiesif you sit behind a CDN / load balancer.Request::getHost()reads theHostheader (orX-Forwarded-Hostwhen proxies are trusted). Without trusted proxies set, the wrong hostname can resolve and visitors see the default brand instead of yours. - [ ] Set
defaultBrandto a valid existing brand key. This is the fallback for admin preview URLs and unmatched hostnames; pointing it at a non-existent key means the storefront renders with empty tokens and a brokendata-brandattribute. - [ ] Test each brand domain on staging. Hit
curl -I https://brand-a.staging.tld/and grep the response fordata-brand="brand-a"and the brand-specific--brand-primarytoken; if either is missing, host resolution isn't matching. - [ ] Don't try to use
hreflangbetween brand hostnames โ see the GEO note below for why. If your "brands" are actually locale-variants, use Shopware'sSalesChannelDomainper-language config instead and uninstall this plugin. - [ ] Theme contrast is per-brand, not per-plugin. This plugin injects tokens; your theme has to satisfy WCAG colour-contrast for every brand combination. Run an axe-core audit on each brand domain before launch.
Compatibility
Core platform
| Shopware | PHP | Status |
|---|---|---|
| 6.7.x โ tested against 6.7.8, 6.7.9 | 8.1, 8.2 | Stable |
| 6.6.x | โ | Not supported |
| 6.5.x and earlier | โ | Not supported |
Database
| Engine | Version | Notes |
|---|---|---|
| MySQL | 8.0+ | Primary target; JSON functions used for config-row manipulation in migrations |
| MariaDB | 10.11+ | Tested end-to-end; earlier versions lack some JSON operator support |
Browsers (storefront)
Evergreen browsers only โ the two most recent stable releases of each:
| Browser | Desktop | Mobile |
|---|---|---|
| Chrome / Chromium | โ | โ |
| Firefox | โ | โ |
| Safari | โ (macOS) | โ (iOS 16+) |
| Edge | โ | โ |
Internet Explorer and legacy Edge are not supported. The plugin emits no runtime JS, so graceful degradation on older browsers usually still renders content, just without progressive enhancements.
Admin browsers
Same evergreen matrix โ the Shopware admin is Vue-based and has its own compatibility baseline that this plugin doesn't extend or narrow.
Development
| Tool | Version | Scope |
|---|---|---|
| PHP | โฅ 8.1 | Runtime + test suite |
| Composer | 2.x | Dependency management |
| Node.js | โฅ 18 | Only needed if you edit SCSS and re-run the theme compile |
Accessibility
WCAG 2.2 level A + AA โ see docs/ACCESSIBILITY.md for axe-core audit output and per-page violations.
What we test before each release
- Full PHPUnit unit suite against PHP 8.1 + 8.2 (source-inspection tests don't need a kernel)
- PHPStan level 8 + PHP-CS-Fixer (@PSR12 + @Symfony)
- Composer validate
- Live-DB smoke tests (plugin install โ activate โ brand resolves per host โ uninstall cycle) against Shopware 6.7.8
Uninstall note
If you also install a theme plugin or another plugin that declares a composer dependency on tenbruggencate/multibrand-lite (or, for legacy installs, the pre-v2.0.0 name tenbruggencate/multibrand), Shopware's plugin manager will refuse to uninstall MultiBrand while that dependant is still active โ you'll see PluginHasActiveDependantsException. This is correct Shopware behaviour, not a MultiBrand bug: uninstalling MultiBrand first would break the dependant plugin at runtime.
To uninstall MultiBrand cleanly:
- Uninstall the dependant plugin(s) first, or remove the
requireentry from theircomposer.jsonand re-runcomposer update. - Then
bin/console plugin:uninstall TenBruggencateMultiBrand.
For vanilla MultiBrand installs (no composer-dependant plugin on top), uninstall runs unblocked: the plugin drops all TenBruggencateMultiBrand.config.* rows from system_config and removes itself.
GEO / multi-region note โ why there is no hreflang
This plugin deliberately does NOT emit hreflang alternate links between the configured brand hostnames. That is correct, not an oversight:
hreflangis the signal for "the same canonical content is served in multiple languages or regions" โ e.g.example.com/product(en) vs.example.de/product(de) for the same product.- The domains MultiBrand is designed for are separate brands with their own catalogues, copy, and identity, not locale-variants of the same storefront. They just share a single Shopware instance for operational reasons.
- Cross-linking them via
hreflangwould tell Google "these are equivalent pages, pick one" โ which is the opposite of what multi-brand storefronts want.
If your brands really ARE locale-variants (e.g. you have shop.nl / shop.de / shop.fr serving the same products in different languages), Shopware's native SalesChannelDomain per-language config is the right tool โ leave this plugin out of that use case.
Related plugins
Free Packagist-distributed siblings from the same publisher:
- TenBruggencateAnalytics โ multi-backend analytics (Matomo + Plausible) with optional per-brand custom dimensions
- TenBruggencateNewsletterLite โ GDPR-safe newsletter signup with double opt-in; stores the resolved brand with each subscriber
- TenBruggencateMaintenance โ branded maintenance page with HTTP 503 + Retry-After
- TenBruggencateLegalPages โ drop-in legal templates (privacy / terms / shipping / returns / disclaimer) with merge fields
Support
- Email: guy@tenbruggencatedevelopment.nl
- Docs & news: tenbruggencatedevelopment.nl
- Source / issues: Bitbucket repo
- Security vulnerabilities: see
SECURITY.mdโ email first, no public issues, 72-hour acknowledgement SLA
License
MIT ยฉ Ten Bruggencate Development
More from Ten Bruggencate Development
Focused, privacy-first Shopware 6 plugins โ free to start, upgrade when you grow:
- Newsletter โ Lite: GDPR-safe signup & subscriber-list management ยท Pro: campaigns, lifecycle automations, native-data segmentation
- Legal Pages โ Lite: localized legal-page templates ยท Pro: the compliance toolkit (maintained templates, cookie policy, accessibility statement)
- Analytics โ multi-backend (Matomo / Plausible), GDPR-first, cookieless-capable
- Maintenance โ a branded, SEO-correct maintenance page
- Multi-Brand โ Lite: hostname-based brand resolution + per-brand theme tokens ยท Pro (coming): per-brand CMS pages, email templates, checkout & shipping rules, analytics and A/B testing
- Product Encyclopedia โ structured educational content pages linked to products
- Seasons โ scheduled theme-config variants