Weave Code
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

Laratheme Laravel Package

jcmccoders/laratheme

Laratheme adds multi-theme support to Laravel 11/12: switch active theme via config/env, auto-register view namespaces, generate new themes with make:theme, and resolve theme views and public assets (CSS/JS/images) from dedicated theme folders.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to Begin

  1. Installation:

    composer require jcmccoders/laratheme
    php artisan vendor:publish --tag=theme-config --tag=theme-stubs
    
    • Verify config/theme.php and resources/themes/stubs are published.
  2. Create Your First Theme:

    php artisan make:theme mytheme
    
    • This generates a folder structure under resources/themes/mytheme/ with:
      • views/ (for Blade templates)
      • assets/ (for CSS/JS/images)
      • stubs/ (optional custom stubs)
  3. Activate a Theme:

    • Set THEME_ACTIVE=mytheme in .env or update config/theme.php:
      'active' => 'mytheme',
      
  4. Use the Active Theme in Views:

    • Laravel automatically resolves views from resources/themes/{active}/views/ (e.g., @extends('mytheme.layouts.app')).

Implementation Patterns

1. Dynamic Theme Switching

  • Workflow:

    • Store user/theme preferences in a database (e.g., users table with theme column).
    • Switch themes dynamically in middleware or controllers:
      // Middleware: Set theme based on user preference
      public function handle(Request $request, Closure $next) {
          config(['theme.active' => auth()->user()->theme ?? 'default']);
          return $next($request);
      }
      
    • Cache the active theme in a session or cache layer for performance.
  • Integration with Blade:

    • Access the active theme name in views:
      @php $activeTheme = config('theme.active'); @endphp
      <div class="theme-badge">{{ $activeTheme }}</div>
      

2. Asset Management

  • Organize Assets:

    • Place theme-specific assets in public/themes/{theme}/assets/.
    • Use Laravel Mix/Vite to compile assets per theme or use the theme() helper:
      <link rel="stylesheet" href="{{ theme('assets/css/style.css') }}">
      
    • Tip: Use mix-manifest to version assets dynamically:
      // In a service provider
      $mix = app()->make('mix');
      $mix->setPublicPath(public_path("themes/{$theme}/assets"));
      
  • Fallback Assets:

    • Configure a fallback theme in config/theme.php:
      'fallback' => 'default',
      
    • Assets/views from the fallback theme are used if the active theme is missing a file.

3. View Overrides

  • Namespace Views:

    • Extend a base view with theme-specific overrides:
      @extends('themes.' . config('theme.active') . '.layouts.app')
      
    • Partial Overrides: Override specific sections (e.g., @section('sidebar')) in child views.
  • Stub Customization:

    • Extend the make:theme stubs by publishing and modifying:
      php artisan vendor:publish --tag=theme-stubs --force
      
    • Example: Add a webpack.mix.js stub for theme-specific asset compilation.

4. Theming in Controllers

  • Conditional Logic:
    public function show() {
        $theme = config('theme.active');
        if ($theme === 'dark') {
            return view('themes.dark.pages.home');
        }
        return view('themes.light.pages.home');
    }
    
  • Dynamic Data: Pass theme-specific data to views:
    return view('themes.' . $theme . '.pages.home', [
        'theme_vars' => $theme === 'dark' ? ['bg_color' => '#121212'] : [],
    ]);
    

5. APIs and Themes

  • Theme-Aware APIs:
    • Use middleware to set the theme for API requests (e.g., based on Accept-Language header):
      public function handle($request, Closure $next) {
          $theme = $request->header('X-Theme') ?? 'default';
          config(['theme.active' => $theme]);
          return $next($request);
      }
      
    • Return theme-specific JSON responses:
      return response()->json([
          'data' => $data,
          'theme' => config('theme.active'),
      ]);
      

Gotchas and Tips

Pitfalls

  1. View Resolution Order:

    • Laravel resolves views in this order:
      1. resources/views/{theme}/{view}.blade.php
      2. resources/views/{view}.blade.php (fallback).
    • Gotcha: Forgetting to prefix views with the theme namespace (e.g., @extends('layouts.app') instead of @extends('themes.dark.layouts.app')) will fail silently.
  2. Asset Paths:

    • Hardcoding asset paths (e.g., <link href="/css/style.css">) breaks when switching themes.
    • Fix: Always use the theme() helper:
      <link href="{{ theme('assets/css/style.css') }}" rel="stylesheet">
      
  3. Caching Issues:

    • Theme changes may not reflect immediately due to Blade caching.
    • Solution: Clear views and config caches:
      php artisan view:clear
      php artisan config:clear
      
  4. Middleware Conflicts:

    • If multiple middleware set the theme, the last one wins.
    • Tip: Use a single middleware or prioritize them in app/Http/Kernel.php.
  5. Database Migrations:

    • If storing theme preferences in the database, ensure migrations are idempotent:
      Schema::table('users', function (Blueprint $table) {
          $table->string('theme')->default('default');
      });
      

Debugging

  1. Verify Active Theme:

    • Add a debug line in a Blade view:
      @dump(config('theme.active'))
      
    • Check if the correct theme is loaded.
  2. Check File Existence:

    • Ensure theme files exist in the expected paths:
      ls resources/themes/{theme}/views/
      ls public/themes/{theme}/assets/
      
  3. Artisan Commands:

    • List available themes:
      php artisan theme:list
      
    • Clear cached theme data:
      php artisan theme:clear-cache
      

Extension Points

  1. Custom Theme Providers:

    • Extend the theme system by creating a custom service provider:
      class ThemeServiceProvider extends ServiceProvider {
          public function register() {
              $this->app->singleton('theme', function () {
                  return new CustomThemeManager();
              });
          }
      }
      
    • Override the ThemeManager class to add logic (e.g., theme validation, dynamic loading).
  2. Dynamic Theme Loading:

    • Load themes from a remote source (e.g., S3) by extending the ThemeRepository:
      class RemoteThemeRepository implements ThemeRepository {
          public function getViewsPath(string $theme): string {
              return storage_path("app/themes/{$theme}/views");
          }
      }
      
  3. Theme Events:

    • Dispatch events when the theme changes (e.g., ThemeSwitched):
      // In the ThemeManager
      event(new ThemeSwitched($oldTheme, $newTheme));
      
    • Listen for events in a service provider:
      ThemeSwitched::listen(function ($event) {
          Log::info("Switched from {$event->oldTheme} to {$event->newTheme}");
      });
      
  4. Theme Validation:

    • Validate themes before activation (e.g., check for required files):
      public function isValidTheme(string $theme): bool {
          return File::exists(resource_path("themes/{$theme}/views/app.blade.php"));
      }
      

Performance Tips

  1. Cache Theme Configuration:

    • Cache the active theme in the session or Redis to avoid repeated config reads:
      $theme = session('theme') ?? config('theme.active');
      
  2. Lazy-Load Assets:

    • Use dynamic asset loading to reduce initial load time:
      @if(config('theme.active') === 'dark')
          <link rel="stylesheet" href="{{ theme('assets/css/dark.css') }}" media="print" onload="this.media='all'">
      @endif
      
  3. Theme-Specific Routes:

    • Cache routes per theme using route caching:
      php artisan route:cache
      
    • Note: This requires rebuilding the cache when themes change.
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.
daikazu/eloquent-salesforce-objects
unseen-codes/chat
romalytar/yammi-jobs-monitoring-laravel
kisame76/filament-db-table-state
nqxcode/laravel-lucene-search
dpfx/laravel-livewire-wizards
workos/workos-php-laravel
sofa/laravel-global-scope
nawasara/auth-primitives
adhocrat-io/arkhe-main
make-dev/orca-harpoon
itsemon245/lamet
baks-dev/dashboard
amoifr/pickle-panther-bundle
make-dev/orca
dmstr/symfony-system-resources-bundle
dmstr/symfony-job-queue-bundle
dmstr/openapi-json-schema-bundle
dmstr/keycloak-security-bundle
dmstr/doctrine-audit-log-bundle