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

Themes Laravel Package

devdojo/themes

DevDojo Themes is a lightweight Laravel package for adding switchable themes to your application. Organize theme views, assets, and settings, then activate a theme to change your app’s look without modifying core code.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a Voyager-era theming addon: it gives you a Theme concept backed by database records, lets you register theme directories, and swaps the active theme's views/assets at runtime. Because it is Voyager-first (and small — ~21 stars, last release Aug 2024), treat the source as the source of truth over any blog post.

  1. Install into a Laravel app that already has Voyager installed and configured (the package assumes Voyager's admin routes, BREAD, and auth):
    composer require devdojo/themes
    
  2. Publish the package assets/config and run migrations:
    php artisan vendor:publish --provider="DevDojo\Themes\ThemesServiceProvider"
    php artisan migrate
    
  3. Log into /admin and look for the new "Themes" menu item Voyager registers. That admin screen is where you create a theme record, point it at a directory, and mark one active. This is the first place to look — it tells you exactly which fields are expected (name, folder/path, active flag, etc.).
  4. Drop a theme folder with your Blade views (e.g. resources/views/themes/my-theme/), register it via the admin screen, activate it, and hit a route that resolves a view the theme overrides.

First practical use case: create a second theme, put a single welcome.blade.php override in it, and confirm switching the active theme in Voyager changes the rendered page. That proves the view resolution path end-to-end before you commit to a structure.

Implementation Patterns

Directory-per-theme with view overrides. The day-to-day value is letting a theme shadow app views without rewriting controllers. Keep each theme self-contained under a single root (views, assets, optional partials). Controllers keep returning view('welcome'); the theme layer decides which file actually renders. Verify the resolution order in the service provider — most themes packages prepend a theme view path so theme views win, then fall back to resources/views.

Activating a theme at runtime. Rather than only using the Voyager toggle, wire the active theme into a middleware or a service that reads it once per request and calls the package's setter. Pattern:

  • Store the active theme per-tenant or per-user (add a column, resolve in middleware).
  • Call the theme-switch API in middleware after StartSession and before your view-rendering routes.
  • Cache the resolved theme in the request container to avoid repeated DB hits.

This is where the package earns its keep versus hand-rolled view()->prependLocation(): you get the admin CRUD for free, but you still own the "which theme for this request" logic.

Asset handling. Theme assets usually live under public/themes/{slug}/ (or are symlinked from the package). Reference them through a helper or asset('themes/'.theme_slug().'/css/app.css') rather than hardcoded paths so switching themes doesn't 404. If the package ships a publish/symlink command, run it as part of deploy.

Voyager integration points. Extend the theme BREAD with custom fields (preview image, author, version) via Voyager's BREAD editor — no code required. If you need theme-scoped settings (colors, logos), add fields to the themes table and read them through the theme model; that keeps config next to the theme instead of in config/.

Compose with layouts. Have each theme supply a layouts/app.blade.php and require app views to @extends('layouts.app') (unqualified). Then a theme only needs to provide the layout plus whatever it wants to override — you don't have to duplicate every view.

Multi-theme testing. In feature tests, set the active theme explicitly (via the model or the package's setter) in setUp() and assert on rendered content, not view paths. Add a thin helper like withTheme('dark') to make tests readable.

Gotchas and Tips

  • Hard Voyager dependency. The description is literal — "currently for Voyager." If you're on a newer Laravel (10/11/12) with Voyager unmaintained, expect friction on service provider discovery, config publishing, and the admin menu registration. Check composer.json constraints before committing; this is a package to evaluate, not assume.
  • View cache will bite you. When a theme's views don't seem to update, it's almost always php artisan view:clear (and config:clear after config edits). Add both to your deploy script alongside optimize:clear.
  • Resolution order is the whole game. If a theme view "isn't winning," dump View::getFinder()->getPaths() to see the ordering. If the theme path isn't near the front, your app's resources/views wins and the theme looks broken when it's just misordered.
  • Blade @extends/@include names are relative to the finder, not the active theme. Once a theme prepends the finder, an unqualified @extends('layouts.app') resolves in-theme, but an explicit @extends('themes.dark.layouts.app') pins you. Prefer unqualified names so themes stay swappable.
  • Asset 404s after switching are typically stale published files or a missing symlink. Re-run the publish/symlink step rather than debugging routes.
  • Migration ordering with Voyager. Run Voyager's own migrations first; the themes migration assumes Voyager's admin tables/roles exist. On a fresh DB, install Voyager, then themes, then migrate.
  • Extension points are thin. With low activity and no dependents, don't expect plugin hooks. The practical extension approach is: bind your own ThemeResolver interface in a service provider and wrap the package's setter, so you can swap the package out later with a one-class change.
  • Pin the version and note the date. Last release 2024-08-04 with ~21 stars means you're on the maintenance hook for anything Laravel-version-specific. Record the exact tag in composer.json and add a short README note on why it's there.
  • Don't use it for tenant asset isolation. It manages view/asset resolution, not storage or per-tenant uploads — pair it with your own upload/tenant logic instead of shoehorning that into theme records.
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.
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
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console