This package is a fork of yaap/theme, which in turn was inspired by bigecko/laravel-theme, a theme manager for Laravel 4.
Themes are stored in the themes folder of your project by default (see path in the package config).
This package provides a simple way to manage themes in Laravel applications.
For example, you can develop multiple themes for your application and easily switch between themes for different purposes.
This version requires PHP 8.1 and supports Laravel 10.39 and newer, up to Laravel 13.
This package also provides support for Laravel Mix and Vite configurations.
| Package Version | Laravel 10 | Laravel 11 | Laravel 12 | Laravel 13 |
|---|---|---|---|---|
| 1 | ✅ (10.39+) | ✅ | ✅ | ✅ |
To get the latest version, simply require the project using Composer:
composer require "felixfrey/laravel-theme:^1.0.0"or manually add line to composer.json
{
"require": {
"felixfrey/laravel-theme": "^1.0.0"
}
}Optionally, publish config using artisan CLI (if you want to overwrite default config).
php artisan vendor:publish --provider="FelixFrey\LaravelTheme\ThemeServiceProvider"Config in config/theme.php file.
return [
/*
|--------------------------------------------------------------------------
| Path to directory with themes
|--------------------------------------------------------------------------
|
| The directory with your themes.
|
*/
'path' => base_path('themes'),
/*
|--------------------------------------------------------------------------
| Path to directory with assets build
|--------------------------------------------------------------------------
|
| The directory with assets build in public directory.
|
*/
'assets_path' => 'themes',
/*
|--------------------------------------------------------------------------
| A pieces of theme collections
|--------------------------------------------------------------------------
|
| Inside a theme path we need to set up directories to
| keep "layouts", "assets" and "partials".
|
*/
'containerDir' => [
'assets' => 'assets',
'lang' => 'lang',
'layout' => 'views/layouts',
'partial' => 'views/partials',
'view' => 'views',
],
];Config in theme folder. Placeholder %theme_name% will be replaced with theme name on creation.
return [
/*
|--------------------------------------------------------------------------
| Theme name
|--------------------------------------------------------------------------
|
| Use in assets publishing etc.
|
*/
'name' => '%theme_name%',
/*
|--------------------------------------------------------------------------
| Inherit from another theme
|--------------------------------------------------------------------------
|
| Set up inherit from another if the file is not exists.
|
*/
'inherit' => null,
];The first time you have to create theme default structure, using the artisan command:
php artisan theme:create defaultBy default, it will use vite as assets builder. If you want to use laravel mix instead, pass mix as the second argument:
php artisan theme:create default mixThe assets builder must be vite or mix.
Theme names may contain letters, numbers, dashes, underscores and spaces. They are converted to snake case, so My Theme creates the folder themes/my_theme. If you run the command without a name, it asks for one.
If the theme already exists, the command asks whether to overwrite it. The files the command generates are then written again, and other files in the theme folder stay as they are. To overwrite without the question, add --force:
php artisan theme:create default --forceTo delete an existing theme, use the command:
php artisan theme:destroy defaultThe command asks for confirmation and exits with an error if you decline. To delete the theme without the question, for example in a script, add --force:
php artisan theme:destroy default --forceHere is an example of the folder structure of project with theme
project-root
├── app/
<...>
├── public/
| ├── index.php
| └── themes/
| └── default/
| ├── js/
| | └── app.js
| ├── css/
| | └── styles.css
| └── images/
| └── icon.png
├── resources/
<...>
├── themes/
| ├── default/
| | ├── assets/
| | ├── lang/
| | ├── views/
| | | ├── layouts/
| | | ├── partials/
| | | └── hello.blade.php
| | └── config.php
| └── admin/
| ├── views/
| | ├── emails/
| | | └── notify.blade.php
| | └── hello.blade.php
| └── config.php
To init and use theme in your application, add the following code to any boot method in application service provider (e.g. AppServiceProvider):
use FelixFrey\LaravelTheme\Facades\ThemeLoader;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
ThemeLoader::init('default');
}
}This will add to views find path:
themes/{$name}(for layouts such aslayouts.master)themes/{$name}/views
Views in your application's own view paths, such as resources/views, take precedence over theme views with the same name.
Lang files will be added as well:
themes/{$name}/lang
They are registered under the theme name, so you use them with the theme name as namespace:
__('default::labels.intro');Set inherit in the config.php of a theme to the name of another theme. Views that are missing in the child theme are then loaded from the parent theme, and the parent theme can inherit from another theme in turn.
Translations are not inherited. Only the lang folder of the theme passed to init() is registered.
ThemeLoader::init() throws a FelixFrey\LaravelTheme\Exceptions\ThemeException when:
- the theme name is empty
- the folder of the theme or of a parent theme does not exist
- the name of the theme or of a parent theme is not a single folder inside the themes path, for example
../sharedorclients/acme - the inheritance is circular, for example two themes that inherit from each other
If init() throws, no view paths of the failed theme are registered.
View::make('hello');
View::make('emails.notify');
// or
view('hello');
view('emails.notify');If you use Vite, ensure vite.config.js have specified the input path for theme
import {defineConfig} from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
plugins: [
laravel({
input: [
'themes/default/assets/js/app.js', // for default theme
// ...
],
refresh: true,
}),
],
});Because app.js includes app.scss you can use the following code to include assets in your views:
<head>
<!--...-->
@vite([
'themes/default/assets/js/app.js',
])
</head>If you use Laravel Mix, ensure webpack.mix.js have specified mix configuration for theme
const mix = require('laravel-mix');
mix.disableNotifications();
mix.browserSync({
open: true,
proxy: 'localhost:8000',
files: [
'app/**/*',
'routes/**/*',
'themes/**/*', // manually add this line
]
});
// other configurations...
// mix for default theme
mix.copyDirectory('themes/default/assets/img', 'public/themes/default/img');
mix.copyDirectory('themes/default/assets/fonts', 'public/themes/default/fonts');
// js
mix.js(['themes/default/assets/js/app.js'], 'public/themes/default/js/app.min.js')
// sass
mix.sass('themes/default/assets/sass/app.scss', 'public/themes/default/css/app.min.css')Then you can use the following code to include assets in your views:
in the <head> tag
<head>
<!--...-->
<link rel="stylesheet" href="{{ mix('/themes/default/css/app.min.css') }}"/>
</head>and before </body> tag
<body>
<!--...-->
<script type="text/javascript" src="{{ mix('/themes/default/js/app.min.js') }}"></script>
</body>To use images, you can use the following code:
<img src="{{ mix('themes/default/img/icon.png') }}" alt="icon">To build layouts we use template inheritance.
You can use @extends directive to specify a parent layout.
@extends('layouts.master')
@include('partials.header')
@section('content')
<section id="main">
<h1>HOME</h1>
</section>
@stop
@include('partials.footer')You still able to use default View::make('emails.notify') which is stored outside the themes directory.
composer testMIT license.