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

Laravel Themes Laravel Package

facuz/laravel-themes

A Laravel package for adding multi-theme support to your app. Organize theme views, assets, translations, and configuration, switch the active theme at runtime, and use theme-aware Blade helpers without changing your core application structure.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install and publish. Require facuz/laravel-themes with Composer, then publish the package config/provider assets (php artisan vendor:publish). On Laravel 5.5+ the service provider and Theme facade are usually auto-discovered; on older versions add them to config/app.php.
  2. Look at config/theme.php first. This is where the theme root and public asset path are defined. Confirm those paths match where you intend to keep themes; everything else in the package is driven from them.
  3. Create the smallest theme that proves the pipeline. A first theme only needs a view directory and an asset directory, for example:
    • themes/default/views/layouts/app.blade.php
    • themes/default/views/home.blade.php
    • themes/default/views/partials/header.blade.php
    • themes/default/assets/css/app.css
  4. Activate a theme once, globally. In AppServiceProvider::boot() or a simple middleware call Theme::set('default'). This is the package’s core switch; views, partials and asset resolution then follow that active theme.
  5. Return a themed view. In a route or controller use return Theme::view('home'); rather than view('home'). That is the first end-to-end use case: request → theme selection → layout/partial rendering → asset tags.
  6. Render assets in the layout. Use the package’s asset API, e.g. Theme::asset()->add('app', 'css/app.css'), then output {!! Theme::asset()->styles() !!} and {!! Theme::asset()->scripts() !!} in the layout. Partials are rendered with Theme::partial('header') so they resolve against the active theme.

Implementation Patterns

  • Request-scoped theme selection. Put theme resolution in middleware rather than controllers: read a user preference, cookie, domain, subdomain, or route parameter, validate it with Theme::exists(), then call Theme::set(). This keeps every controller unaware of the active theme.
  • Theme switcher route. A small controller that validates the requested theme, stores it in session or user settings, and redirects back is a common day-to-day pattern. Always whitelist against configured themes; never pass a raw request value into the theme path.
  • Layouts and partials as the theme contract. Define one shared layout per theme (layouts/app.blade.php) and standard partial names (header, footer, nav, sidebar). Controllers and routes then call Theme::view('page'), while the layout handles Theme::partial() and asset rendering. This keeps theme differences isolated to view files.
  • Asset containers and ordering. Register CSS in the default container and JavaScript in a footer container where supported, e.g. Theme::asset()->container('footer')->add('app-js', 'js/app.js', ['jquery']). Use dependency arrays for ordering and unique asset names to avoid silent overwrites. Render each container exactly once in the layout.
  • Config-driven theme mapping. For multi-site or white-label apps, keep a domain => theme or plan => theme map in your own config, then resolve it in middleware. This is more maintainable than scattering Theme::set() calls through controllers.
  • Controller base class or helper. Wrap Theme::view() in a base controller method (protected function themeView($name, $data = [])) so you can add analytics, shared view data, or fallback logic in one place.
  • Fallback and override conventions. If themes share structure, keep a base theme and copy only changed views/assets into child themes. The package resolves within a single active theme, so treat shared partials and layouts as a deliberate convention rather than assuming automatic inheritance.
  • Testing. In feature tests, set the theme in setUp() or via the middleware under test, then assert the rendered view and asset output. Use View::getName() or response assertions to confirm the correct theme view was selected.
  • Deployment. Keep theme source in version control, but ensure the public asset directory is present and writable/published at deploy time. For local development, a symlink from public/themes to the source theme assets avoids repeated copying.

Gotchas and Tips

  • Compatibility is the biggest risk. This package descends from teepluss/theme and targets older Laravel conventions. Check its Composer constraints against your Laravel version before adopting it; on modern Laravel you may need a fork or a shim for removed helpers.
  • Facade and provider registration. Auto-discovery only works on newer Laravel. If Theme:: is undefined, the provider or Theme alias is missing from config/app.php.
  • Config caching freezes paths. php artisan config:cache evaluates base_path()/public_path() once. Avoid env() inside config/theme.php; after changing theme paths run php artisan config:clear and recache.
  • View cache hides moved templates. After adding or renaming theme views, run php artisan view:clear. A stale compiled view is a common cause of “my new theme file is ignored.”
  • Path vs URL confusion. Asset registration usually expects a path relative to the theme’s asset directory; layout output converts that to a public URL. Mixing asset() URLs into Theme::asset()->add() produces duplicated or broken paths.
  • Assets are not automatically public. The package organizes assets in the theme directory; you still need the configured public asset path populated, published, or symlinked. A 404 on theme CSS usually means the public side was never synced.
  • Duplicate asset names silently replace. Use namespaced names (theme-app-css, vendor-jquery) and verify dependency order in the rendered output; a missing dependency can prevent a script from appearing.
  • Global theme state can leak. Theme::set() is effectively global for the request. In long-running workers (Octane, Swoole) reset the theme at the start or end of each request in middleware, otherwise one request’s theme can bleed into the next.
  • Sanitize theme names. Treat theme selection as user input if it comes from a route, cookie, or header. Whitelist against Theme::all()/Theme::exists() and reject path separators.
  • Set the theme before rendering. Calling Theme::set() inside a view composer or after a view has begun rendering is too late; resolve it in middleware or a service provider boot path.
  • Extension points are limited. There is no rich event system here; the practical extension points are the package config, a custom middleware/resolver, a wrapper service around the facade, and your own Blade layout conventions. If you need sophisticated theme inheritance or per-tenant assets, plan to build that layer yourself rather than expecting it from the package.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager