Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Theme Laravel Package

karlomikus/theme

A Laravel package for adding multi-theme support to your application. Manage theme views, assets, translations, and configuration with fallback handling, switch themes via middleware or helpers, and build customizable, white-label interfaces with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install (package targets Laravel 5.x — verify constraints before adding to newer apps):

    composer require karlomikus/theme
    
  2. Register the provider — auto-discovered on 5.5+, otherwise add to config/app.php:

    Karlomikus\Theme\ThemeServiceProvider::class,
    'Theme' => Karlomikus\Theme\Facades\Theme::class,
    
  3. Publish the config so you control the themes path:

    php artisan vendor:publish --provider="Karlomikus\Theme\ThemeServiceProvider"
    

    You get config/theme.php with themes_path, default_theme, and asset settings. Look here first — almost every quirk in this package is a path or a config-cache issue.

  4. Create your first theme at the configured path:

    themes/
      Default/
        theme.json          # name, description, author, version
        views/              # Blade templates
        assets/             # css, js, images
    

    theme.json is what the loader reads to discover the theme; without it the theme is invisible.

  5. First use case — set the active theme and render a view:

    Theme::set('Default');
    return Theme::view('welcome', ['user' => $user]);
    

    Theme::view() resolves against the active theme's views/ directory, so you stop hardcoding paths in controllers.

Implementation Patterns

Per-request theme switching via middleware. This is the pattern most teams settle on — resolve the theme from a user preference, subdomain, or session, then set it before the controller runs:

public function handle($request, Closure $next)
{
    Theme::set($request->user()->theme ?? config('theme.default_theme'));
    return $next($request);
}

Keep it early in the web stack so every view render downstream inherits it.

Admin preview / multi-tenant layouts. Render any theme by name without changing the request-global default by setting, rendering, and resetting:

$previous = Theme::get();
Theme::set($request->input('theme'));
$html = Theme::view('home', $data)->render();
Theme::set($previous);

Useful for admin "preview theme" screens and for tenant-specific rendering inside a single queue job.

Asset URL helper in Blade. Do not hardcode asset('css/app.css') inside themes — use the package's asset helper so the URL follows the active theme:

<link rel="stylesheet" href="{{ theme_asset('css/app.css') }}">

Back it with a published/symlinked public/themes directory (or a route fallback) so the files resolve.

Layout inheritance across themes. Define a shared layouts/app.blade.php inside each theme at the same relative path. Controllers call Theme::view('pages.dashboard'); each theme owns its own layout, and swapping themes never touches controllers.

Theme list for pickers. Populate a settings dropdown from the package's theme enumeration (Theme::all() / the loader), not from File::directories() — the package already filters out folders without a valid theme.json.

Scaffold a new theme as a composer package. The cleanest integration in a larger codebase: put each theme in packages/themes/Acme with a small service provider that publishes views/ and assets/, then point themes_path at the published location. You get versioning and CI for free.

Testing. Set the theme in setUp() on the test case, not in the test body, so every Theme::view() assertion resolves deterministically. Use View::getFinder()->getPaths() in assertions if you need to prove the right theme was bound.

Gotchas and Tips

  • Laravel version ceiling. Last release was April 2019; the package targets Laravel 5.x. On Laravel 6+ expect to fork or pin with composer require karlomikus/theme --ignore-platform-reqs and then verify the service provider still binds correctly. Treat it as a vendored fork rather than an actively maintained dependency.

  • Config cache breaks theme discovery. php artisan config:cache freezes themes_path; if you deploy themes to a different directory per environment, clear the cache after deploy or the loader reads the stale path.

  • theme.json is mandatory and case-sensitive. A theme folder with no manifest (or a manifest with a parse error) silently drops out of Theme::all() and Theme::set() will fall back to the default. If a theme "doesn't exist," check the JSON first.

  • View cache persists across theme switches. Blade caches compiled views by name; if two themes have a welcome.blade.php at the same relative path, you can get the wrong compiled output after switching. The package namespaces views, but during development run php artisan view:clear whenever you swap a theme. In production this is a real bug class — test theme switching with the view cache warm.

  • Assets are not symlinked for you. theme_asset() builds a URL; it does not publish files. Add a deploy step (ln -s or php artisan vendor:publish) or your themes 404 on CSS.

  • Path traversal on user-supplied theme names. Theme::set($request->input('theme')) without validation is an arbitrary directory read. Always whitelist against Theme::all() before setting.

  • Default theme fallback is silent. When the active theme is missing, the package quietly uses default_theme instead of throwing. Wrap critical renders in a check (in_array($name, Theme::all())) if you need loud failures.

  • Extension point is thin. There is no driver/repository abstraction to swap — the loader reads from disk. If you need themes stored in a database or S3, you are writing a parallel implementation, not extending this package. Factor that into the build-vs-fork decision early.

  • Debug tip. Dump config('theme.themes_path'), Theme::all(), and Theme::get() together at the top of a failing view — 90% of "theme not found" issues are a wrong themes_path (often a missing base_path() in a queued job or console command) combined with a stale config cache.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core