alizharb/laravel-themer
Enterprise-grade theme management for Laravel. Create, clone, activate, and safely delete themes with per-theme Vite builds, NPM workspaces, asset shortcuts, view overrides, and Livewire 4 support. Includes metadata, wizards, and fast production caching.
Installation
composer require alizharb/laravel-themer
php artisan themer:install
.gitignore files and theme.json hooks during installation.Default Theme Structure
themes/ directory in your resources/ folder.theme.json (new in v1.3.0):
resources/themes/
├── default/ # Default theme
│ ├── views/ # Blade templates
│ ├── assets/ # CSS/JS
│ ├── config.php # Theme-specific config
│ └── theme.json # New: Theme metadata & hooks (v1.3.0)
└── custom/ # Your custom themes
First Use Case: Interactive Theme Creation
php artisan themer:make
.gitignore and theme.json.First Blade Template with Vite
@vite(['resources/themes/default/assets/css/app.css'])
@vite tags without legacy workarounds.Zero-Config Modularity
resources/themes/ (custom paths configurable).theme.json (v1.3.0) for metadata and hooks:
{
"name": "custom.my-theme",
"hooks": {
"after_activate": ["php artisan db:seed --class=EcommerceSeeder"]
}
}
Theme-Specific Assets with Vite
php artisan themer:publish --theme=custom.my-theme
@vite directly in Blade (native Vite support in v1.3.0):
@vite(['resources/themes/custom/my-theme/assets/js/app.js'])
Middleware-Based (with Preview Support)
// app/Http/Middleware/SwitchTheme.php
public function handle(Request $request, Closure $next) {
$theme = $request->user()->preferred_theme ?? 'default';
if ($request->query('preview_theme')) {
Themer::previewTheme($request->query('preview_theme')); // New in v1.3.0
} else {
Themer::setTheme($theme);
}
return $next($request);
}
PreviewTheme middleware for secure theme previews via ?preview_theme=slug.Livewire Integration
public function mount() {
Themer::setTheme('dark');
$this->dispatch('theme-switched')->toOthers();
}
config/themer.php:
'themes' => [
'custom.my-theme' => [
'assets_path' => 'themes/custom/my-theme/assets',
'config' => ['primary_color' => '#3b82f6'],
'hooks' => ['after_activate' => ['php artisan optimize']] // v1.3.0
],
],
<div style="color: {{ config('themer.themes.custom.my-theme.config.primary_color') }};">
Fallback Chain
active_theme → default → vendor/themer.views/ directory.Partial Overrides with Vite
@push('themer-scripts')
@vite(['resources/themes/custom/my-theme/assets/js/partial.js'])
@endpush
Theme-Aware Components
@themerComponent('theme-aware-component', ['prop' => 'value'])
Dynamic Theme Switching
public function switchTheme(string $theme) {
Themer::setTheme($theme);
$this->dispatch('theme-switched')->toOthers();
}
Asset Path Conflicts
@vite directly (v1.3.0 removes symlink legacy). Verify paths with:
php artisan themer:publish --theme=NAME
Caching Issues
bootstrap/cache/themes.php). Clear only when themes change:
php artisan theme:cache
Livewire Hydration Mismatches
Namespace Collisions
admin). Use prefixes like custom.my-theme/.Theme Hooks (v1.3.0)
theme.json must be valid Artisan commands. Test locally first.Check Active Theme
php artisan themer:list
Log Theme Switches Enable debug mode:
'debug' => env('THEMER_DEBUG', false),
Verify View Resolution
Themer::resolveView('path.to.view');
New in v1.3.0: Linting
php artisan theme:lint custom.my-theme
laravel-pint + NPM formatters scoped to the theme.Custom Theme Resolvers
Themer::extend(function ($theme) {
return ThemeResolver::resolve($theme);
});
Theme Events (v1.3.0)
Themer::on('theme.activated', function ($theme) {
Log::info("Activated: {$theme}");
});
Asset Pipeline Hooks
Themer::macro('assetPath', function ($path) {
return str_replace('public/', 'themed/', $path);
});
Dynamic Theme Loading
Themer::addThemeSource(new S3ThemeSource());
Precompile Themes (v1.3.0)
php artisan theme:cache
bootstrap/cache/themes.php for instant boot.Lazy-Load Assets
@if(Themer::isTheme('custom.my-theme'))
@vite(['resources/themes/custom/my-theme/assets/js/app.js'])
@endif
Git Workspace Sync (v1.3.0)
.gitignore auto-generated in new themes. Exclude:
/themes/*/vendor/
/themes/*/node_modules/
ThemeServiceProvider crashes, the system silently falls back to the default theme. No more fatal errors during boot.php artisan theme:upgrade
.gitignore and initializes theme.json hooks.How can I help you explore Laravel packages today?