caffeinated/themes
Caffeinated Themes brings flexible, configurable theme support to Laravel apps. Organize views, assets, and settings into switchable themes, then render them cleanly through Blade with a simple, expressive API. It supports multiple themes and clean separation of layout and assets for multi-theme pro...
composer require caffeinated/themes. On Laravel 5.5+ the ThemesServiceProvider and Theme facade are auto-discovered; on older versions add Caffeinated\Themes\ThemesServiceProvider::class and 'Theme' => Caffeinated\Themes\Facades\Theme::class to config/app.php.php artisan vendor:publish --provider="Caffeinated\Themes\ThemesServiceProvider" --tag=config. Open config/themes.php and note the two values that matter: path (defaults to base_path('themes')) and default (the theme name used when nothing else is set).themes/default/, with the conventional subfolders: views/, assets/, lang/, and config/. Drop a views/welcome.blade.php in it.Theme::set('default'); return Theme::render('welcome'); — or reference the theme namespace directly with view('default::welcome'). In tinker, run Theme::all() and Theme::current() to confirm the package sees your folder.Look first at the facade (Caffeinated\Themes\Facades\Theme), the manager class it resolves to, and the published config. Those three files explain 90% of the package.
Theme::set($name). Keep the selection logic out of controllers so it applies globally.Theme::render('home', $data) so the current theme is honored without hardcoding a namespace. Use view('mytheme::home') only when you intentionally want a specific theme.Theme::has('partials.hero') (or Theme::find($name)->getViewPath(...)) and fall back to a base theme. This is the cleanest way to ship a minimal theme and let a richer one override selectively.config/ files, read through Theme::config('key') or the theme's getConfig(). Good place for per-theme branding, colors, and feature flags so code doesn't branch on theme name.Theme::all() gives you the collection of discovered themes — iterate it to build a back-office picker, store the chosen name in user/settings, and apply it with Theme::set() on the next request.Theme::asset('css/app.css') so links follow the active theme. For cache-busting, append your own version query string (the package doesn't do manifest/mix-style resolution per theme for you).caffeinated/modules, mirror a module's view namespace inside a theme's views/ directory to override module views per theme. This is the main reason to pick this package over rolling your own view-path swapping: it understands module namespaces.views/layout.blade.php per theme and have all pages @extends('layout'). Because the theme's view path is prepended, the same template name resolves per theme without conditionals in Blade.public/. The default path is base_path('themes'), so Theme::asset() produces a URL your web server likely can't serve. Either symlink themes/*/assets into public/themes, publish assets on deploy, or point the config at a directory inside public/. This is the #1 source of "styles are 404ing" reports.composer.json override for Laravel 10/11 (signature changes in ServiceProvider, container bindings, etc.). Budget an afternoon to smoke-test, not a sprint.php artisan view:clear. Namespaced views are cached by resolved path, and stale compiled files will silently serve the old theme's markup.Theme::set() must run before the response is built. Calling it from a view composer or a controller that has already returned a view has no effect. Put it in middleware.errors, pagination, etc.) — the prepended theme path will shadow the framework's views in confusing ways.config:cache is safe, but keep logic out of it. The default theme value is cached; runtime Theme::set() still works. Don't try to compute the default dynamically inside the config file.Theme::exists($name), Theme::current(), Theme::all()->keys(), and confirm config('themes.path').'/'.$name.'/views' actually exists. Most "view not found" issues are a misnamed folder or a missing .blade.php extension.How can I help you explore Laravel packages today?