byrcsc / laravel-whitelabel
Manage white-label branding and settings across Laravel views, mail, notifications, and queued jobs.
Fund package maintenance!
Requires
- php: ^8.3
- illuminate/console: ^12.0||^13.0
- illuminate/contracts: ^12.0||^13.0
- illuminate/database: ^12.0||^13.0
- illuminate/filesystem: ^12.0||^13.0
- illuminate/http: ^12.0||^13.0
- illuminate/mail: ^12.0||^13.0
- illuminate/queue: ^12.0||^13.0
- illuminate/support: ^12.0||^13.0
- illuminate/view: ^12.0||^13.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.18
- nunomaduro/collision: ^8.5
- orchestra/testbench: ^10.0||^11.0
- pestphp/pest: ^3.7||^4.0
- pestphp/pest-plugin-arch: ^3.0||^4.0
- pestphp/pest-plugin-laravel: ^3.1||^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- spatie/laravel-multitenancy: ^4.0
Suggests
- phpunit/phpunit: Required by the InteractsWithBrands testing trait, and already there in any test suite.
- spatie/laravel-multitenancy: Activate a brand whenever a tenant becomes current (^4.0).
README
Give every white-label client its own branding and settings across web pages, emails, and background jobs in one Laravel application.
Laravel Whitelabel stores each client's logo, favicon, colours, mail sender, and application settings as a brand. It selects one active brand for each request or job, so every part of the application reads the same client configuration.
The package manages branding only. Your application remains responsible for tenants, users, billing, authorization, and content.
| Laravel | Tested PHP versions |
|---|---|
| 12.x | 8.3, 8.4 |
| 13.x | 8.3, 8.4 |
Tested with SQLite, MySQL, and PostgreSQL. The optional integration supports
spatie/laravel-multitenancy 4.x.
Installation
Install the package and publish its configuration:
composer require byrcsc/laravel-whitelabel php artisan whitelabel:install
The installer can also publish the migration for database-managed brands:
php artisan whitelabel:install --database --no-interaction php artisan migrate
How it works
A brand is an immutable definition with fixed fields for its name, domain, logo, favicon, colours, and mail sender, plus a settings array for values your application owns.
The default config driver reads definitions from config/whitelabel.php. The
database driver stores them in a table and supports create, update, and delete
operations. Both return the same Brand object through the
BrandRepository contract.
The active brand comes from the first resolver that finds one. The default order checks an explicit activation, the current Spatie tenant, the request domain, and finally the configured default brand. Values omitted by a brand inherit from the default brand one key at a time.
Quick start
Brands can live in configuration or the database. This shortest example uses the config driver, which fits brands managed through deployments. Use the database driver when customers create or edit their branding at runtime; the Blade code below stays the same.
Define a default brand and a domain-specific brand in
config/whitelabel.php:
'default' => 'default', 'brands' => [ 'default' => [ 'name' => 'Example', 'logo' => ['disk' => 'public', 'path' => 'brands/default/logo.svg'], 'favicon' => ['disk' => 'public', 'path' => 'brands/default/favicon.svg'], 'colors' => ['primary' => '#111827'], ], 'acme' => [ 'name' => 'Acme', 'domain' => 'acme.test', 'logo' => ['disk' => 'public', 'path' => 'brands/acme/logo.svg'], 'colors' => ['primary' => '#7c3aed'], 'settings' => ['support_url' => 'https://support.acme.test'], ], ],
Render the active brand in a shared Blade layout:
<head> <title>{{ brand('name') }}</title> <x-whitelabel::favicon /> <x-whitelabel::styles /> </head> <body> <x-whitelabel::logo class="h-8" /> <a href="{{ brand('settings.support_url') }}">Support</a> </body>
A request for acme.test uses Acme's name, logo, colour, and support URL. Its
missing favicon falls back to the default brand's favicon.
What is included
- Config and database repositories behind one public contract.
- An ordered resolver chain for explicit, tenant, domain, and default brands.
- Per-key fallback with deliberate clearing for empty values.
- Storage-backed logo, favicon, and custom asset URLs.
- Blade components for logos, favicons, and CSS custom properties.
- Branded Markdown mail and an opt-in sender override.
- Brand context restoration for jobs, mailables, notifications, and listeners.
- Optional Spatie Multitenancy integration.
- Runtime definitions, testing helpers, lifecycle events, and cache management.
Documentation
The versioned documentation contains the full setup, guides, behavior details, and API reference:
- Installation and setup
- Quick start
- Brand definitions and fallback
- Brand resolution
- Blade components
- Mail and notifications
- Queues
- Spatie Multitenancy
- Database brands
- Configuration reference
- Public API reference
- Testing
- Troubleshooting
Development
The local checks mirror CI:
composer install
composer test
composer analyse
vendor/bin/pint --test
PHPStan runs at max with no baseline. Tests run against SQLite locally and
against MySQL and PostgreSQL in CI. The public API test pins the supported
classes and methods. See CONTRIBUTING.md for the full
development workflow.
workbench/ is a bootable demo application that exercises both repositories,
the resolver chain, Blade components, branded mail, queued work, Spatie
Multitenancy, and the testing helpers. Run composer build, then follow the
workbench demo loop.
Out of scope
The package will not include:
- Any admin or management UI.
- Asset uploads, image manipulation, or favicon generation.
- Theme or CSS compilation, including per-brand Tailwind builds.
- Per-brand routes, feature flags, content localization, or Blade directories.
- Tenancy, user management, billing, authorization, or database isolation.
Versioning
The package follows semantic versioning.
- Upgrading within
1.xis safe. Nothing you use will break. - Only a new major version, like
2.0.0, can break your code. - If the README or the documentation describes it, it is safe to build on. If they don't, treat it as internal and expect it to change.
Bug fixes go into the newest version only. To get a fix, upgrade to it.
Questions and issues
- Stuck, or have an idea? Start a discussion. Usage questions and feature ideas both live there.
- Found a bug you can reproduce? Open an issue. A failing test is the fastest way to a fix, and a short reproduction is the next best thing.
- Found a security problem? Please don't open a public issue. See SECURITY.md for how to report it privately.
- Planning a pull request? CONTRIBUTING.md covers the setup and the three checks it needs to pass.
This package is maintained by one person, so replies can take a while. Everything gets read.
Credits
License
MIT. See LICENSE.md. Changelog in CHANGELOG.md.