🔥 Concept

This dynamic theme manager brings theme support to Laravel projects. Theme Manager manages multiple theme at same time and you won't lose build-in Laravel features. This package uses custom middleware for overwriting view path with selected theme.

Add theme-manager middleware alias to your web or custom route chain. Then Theme Manager can manipulate the views.


Installation

⚠️ This package compatible only Laravel 8 and above.

To get the latest version of Laravel Theme Manager, simply require the project using Composer :

                            
$ composer require laravel-ready/theme-manager
                            
                        

Publish configs

Run artisan command:

                            
$ php artisan vendor:publish --tag=theme-manager-config
                            
                        

and you can find theme-manager.php file in config folder.

Middleware

Add theme-manager middleware alias to your base route in {route}.php or app/Providers/RouteServiceProvider.php

Method 1: routes/{web}.php

We can use it in web.php or any-custom.php file but these route files should work with web middleware web.

                            
Route::prefix('/')->middleware(['theme-manager', 'another-mw'])->group(function (){
    Route::get('', [LandingController::class, 'index'])->name('home');

    Route::get('my-page', [LandingController::class, 'anyPage'])->name('my-page');
});
                            
                        
Method 2: RouteServiceProvider.php

You can find RouteServiceProvider.php in app/Providers folder. Also, this method affects sub-routes. If you want to use a specific route or group use the method 1.

                            
public function boot()
{
    $this->configureRateLimiting();

    $this->routes(function () {
        ...

        Route::middleware(['web', 'theme-manager'])
            ->namespace("{$this->namespace}\\Web")
            ->group(base_path('routes/web.php'));

        Route::middleware(['web', 'theme-manager'])
            ->namespace("{$this->namespace}\\Admin")
            ->group(base_path('routes/admin.php'));

    });
}
                            
                        

🚀 Usage


Middleware

Theme Manager works with vendor/theme pair. We can define default themes in routes and also you can restrict with the route specific theme group.

⚠️ Parameter ordering does not matter.

Parameter Description Usage
theme Specify theme alias theme-manager: theme=vendor-x/theme-y
vendor Restrict with specific vendor theme-manager: group=admin

Combined usage examples:

  • theme-manager: theme=admin/my-theme, vendor=admin
    • theme: default theme
    • vendor: default vendor
  • theme-manager: vendor=admin
    • In this way, the theme is not defined because the theme will be set with service class but the vendor field is required for using the default theme option.

Todo: connect to own title If you want to add a theme you must add group alias because all themes depends to own group. Also to use multiple default theme you first must define group. See multiple and default theme sections for more example.


Service

Theme loading and other options are depends to your logic. You can use ThemeManager service in controller, custom middleware etc.

                            
use LaravelReady\ThemeManager\Services\Theme;
use LaravelReady\ThemeManager\Services\ThemeManager;
                            
                        

⚠️ Remember: framework and packages work with order and follow priorities. Service class depends on ThemeManagerMiddleware and won't work in controller methods. Because we are overwriting blade paths in middleware. This depends on the case, if you want to change to active theme or real-time actions will not work. And still, you can use static methods like update, delete, etc. So we need to use service methods before the controller method fires or in the controller constructor.

Scan installed themes

Returns theme collection. After themes are scanned, adds to cache.

                            
ThemeManager::scanThemes()
                            
                        
Get current theme

Returns current Theme details.

                            
ThemeManager::getCurrentTheme()
                            
                        
Get target theme

Returns requested Theme details.

                            
ThemeManager::getTheme()
                            
                        
Set current theme

setTheme is required vendor/theme pair.

                            
ThemeManager::setTheme('vendor-x/theme-y')
                            
                        
Set theme status

setThemeStatus is required vendor/theme pair.

                            
ThemeManager::setThemeStatus('vendor-x/theme-y', true|false)
                            
                        

or update all themes

                            
ThemeManager::setThemeStatusAll(true|false)
                            
                        
// TODO: Add 'Theme' methods

Views

We can call regular views with return view('welcome'). If you want to call the theme view use theme:: alias like return view('theme::welcome') in the controller. theme:: alias is auniversal gateway for Theme Manager. When you use the setTheme method Theme Manager finds theme views and applies them, then Laravel renders.

⚠️ #1 You can't use theme:: alias like theme::theme-name.... You can only define themes with ThemeManager service class and middleware. This package focused to dynamic theming.

⚠️ #2 View paths are must be the same for each theme. If you want to change the view path for the specific theme you have to change all themes for the target group. Otherwise, the target view is going to be broken on runtime because the path changed for other themes. Laravel throws view path not found exception.

                            
class AnyController extends Controller
{
    public function __construct() {
        ThemeManager::addDefaultTheme(['vendor-x/red-swan']);

        $theme = request()->query('theme', 'vendor-x/green-energy');

        ThemeManager::setTheme($theme, 'web');
    }

    public function index(){
        // laravel native
        return View('web.welcome');
    }

    public function anyPage(){
        ...

        // our view path of templates
        return View('theme::pages.home.index');
    }
}
                            
                        

Directives

Directive Description Parameters
@asset Get theme asset URL 0: Asset path, 1: Print theme version number (default true)
@assetLoad Get theme asset content as string 0: Asset path, 1: Fallback asset (default null)
@svg Get SVG content as string 0: SVG file name, 1: Class name (default null), 2: CSS style (default null)
  • @asset
    • @asset('css/base.css')
    • @asset('css/base.css', true|false)
    • @asset('js/app.js')
    • @asset('images/user/avatar-01.jpg')
    • @asset('favicons/favion.ico')
  • @assetLoad
    • @assetLoad('css/base.css')
    • @assetLoad('html/any-template.html')
    • @assetLoad('images/svg/sunshine.svg', 'images/svg/moonshine.svg')
  • @svg
    • @svg('chevron-left')
    • @svg('chevron-right', 'mx-auto')
    • @svg('chevron-down', 'mx-auto', 'fill: green; top: 20px; position: relative;')

The above asset paths css, js, html are not reserved or any custom paths are depends to your theme webpack.mix.js configs and design approach.

⚠️ Published theme specific assets must be in project-folder/src/public/themes/{group-alias}/{theme-alias}/ folder because Theme Manager uses this path for directives.


Default Theme

We can show default theme when target theme is not found. Can define default themes with config file and service class.

Config file

Open theme-manager.php ( see installation part ) file then set default_theme value. default_theme supports single and multiple themes.

                            
<?php

return [
    ...

    'default_theme' => 'vendor-x/red-swan',

    ...
];
                            
                        

or in array

                            
<?php

return [
    ...

    'default_theme' => [
        'vendor-x/red-swan',
        'egoistdev:admin-who'
    ],

    ...
];
                            
                        

Service class

Also we can pass default themes pass through with service class.

                            
// add default theme/s
ThemeManager::addDefaultTheme(['vendor-x/red-swan', 'egoistdev:admin-who']);

// remove default theme/s
ThemeManager::removeDefaultTheme(['vendor-x/red-swan', 'egoistdev:admin-who']);
                            
                        

Both of two usage requires default vendor definition on middleware. Just assign default vendor field to middleware. If theme already defined in middleware this option does not working beacuse middleware theme definiton has high priority.

⚠️ addDefaultTheme and removeDefaultTheme methods does not effects config file.


Priority

At this moment we see multiple ways to setting theme and default theme but all of them working in order.

  1. Middleware defined theme comes first ( if the theme is not found, goes to second check point )
  2. Service class defined theme ( if the theme is not found, goes to third check point )
  3. Default theme ( will define in config or service class )
  4. If default theme is not exists throws error and application breaks

✳️ Theme

Views folder and subfolder structure depends to your strategy. In this point just follow classical blade theming approach.

After new theme created you can change configs details in {themes}/group/theme/theme-configs.json file and you can add preview image preview.jpg and preview.png formats. Then you can manage with own custom visual manager.


Commands

You can manage themes with commands.

Create new theme
                            
$ php artisan theme-manager:make
                            
                        

Result:

                            
Theme Group: (as slug. web, admin etc):
> web

Theme Vendor: (as slug):
> theme-factory

Theme Name:
> awesome-blog

Theme Description: /optional/:
> Enim laboris minim occaecat incididunt eiusmod sit excepteur reprehenderit enim consectetur Lorem.

Author Name:
> EgoistDeveloper

Author Contact Address or Email /optional/:
> https://github.com/EgoistDeveloper/

Theme "theme-factory/awesome-blog" created successfully for "web" group. Please check your "themes/theme-factory/awesome-blog" folder
                            
                        
List installed themes

scanThemes methods scans folders recursively and theme listing order depends to your file system.

                            
$ php artisan theme-manager:list
                            
                        

Result:

                            
⚠️  Check the "theme-config.json" file in the own theme folder for more information.

+-------+---------+--------------+----------------------------+--------+-------+-----------------------------------+-----------------+---------+
| Index | Default | Name         | Alias                      | Status | Group | Description                       | Authors         | Version |
+-------+---------+--------------+----------------------------+--------+-------+-----------------------------------+-----------------+---------+
|  [1]  | -       | Admin Who?   | egoistdev/admin-who        | Active | admin | Dolore officia adipisicing ven... | EgoistDeveloper | 1.0.0   |
|  [2]  | -       | Dark Night   | egoistdev/dark-night       | Active | web   | Find the perfect lights in dar... | EgoistDeveloper | 1.1.3   |
|  [3]  | -       | Gentelella   | egoistme/gentelella        | Active | admin | Gentelella Admin is a free to...  | EgoistDeveloper | 3.1.3   |
|  [4]  | -       | awesome-blog | theme-factory/awesome-blog | Active | web   | Enim laboris minim occaecat in... | EgoistDeveloper | 1.0.0   |
|  [5]  | -       | Green Energy | vendor-x/green-energy      | Active | web   | Green energy is any energy typ... | EgoistDeveloper | 4.1.3   |
|  [6]  | Yes     | Red Swan     | vendor-x/red-swan          | Active | web   | The awesome red swan web site...  | EgoistDeveloper | 1.0.1   |
+-------+---------+--------------+----------------------------+--------+-------+-----------------------------------+-----------------+---------+
                            
                        
Delete selected theme
                            
$ php artisan theme-manager:destroy theme-factory/awesome-blog
                            
                        

Result:

                            
This theme will be delete. Are you sure? (yes/no):
> yes

Theme "theme-factory/awesome-blog" deleted.
                            
                        
Set theme status

Update specific theme status.

                            
$ php artisan theme-manager:status theme-factory/awesome-blog true|false
                            
                        

Update all themes statuses.

                            
$ php artisan theme-manager:status all true|false
                            
                        

Folder Structure

vendor-x, vendor-y, and vendor-z are theme vendors. All themes will be in their own vendor folder. Each vendor folder contains can multiple themes. Theme folder structure must be like this:

⚠️ Also, this folder structure required for remote theme managment. (In the future we will add support for store, update, licensing features).

                            
.
└── src
    ├── app
    ├── bootstrap
    ├── config
    ├── database
    ├── ...
    ├── {themes}
        ├── vendor-x
        │    ├── my-awesome-theme
        │    ├── your-awesome-theme
        │    ├── ...
        ├── vendor-y
        │    ├── banana
        │    ├── cerry
        │    ├── apple
        │    ├── orange
        │    ├── ...
        ├── vendor-z
        │    ├── other-theme
        │    ├── other-other-theme
        │    ├── ...
        ├── ...