Build a Simple - Yet Extendable CMS with Laravel & Backpack
In this tutorial (or series) depending on how much I cover, we will install Laravel, Backpack & setup a simple CMS system to manage your content.
I am not one to drabble on so lets get to the meat of it:
Laravel has a few ways of being deployed on your development machine: and we will leave it to you to pick your method: - see here for documentation on this
Under the assumption that you are using Sail
curl -s "https://laravel.build/lcms" | bash
cd example-app
./vendor/bin/sail up
Now once it is up let us install some of the tools we want to use
sail composer require spatie/laravel-permission laravel/jetstream backpack/crud
sail composer require --dev barryvdh/laravel-ide-helper nunomaduro/phpinsights backpack/generators laracasts/generators jeroen-g/laravel-packager
sail artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
sail artisan jetstream:install livewire
sail artisan vendor:publish --tag=jetstream-views
sail artisan backpack:install
npm install && npm run dev
This will install permission, authentication and backpack for the admin panel.
next add to your composer.json file the following in scripts
"scripts": {
"post-update-cmd": [
"Illuminate\\Foundation\\ComposerScripts::postUpdate",
"@php artisan ide-helper:generate",
"@php artisan ide-helper:meta"
]
},
Next let us create a seeder for our roles:
first edit app/Models/User and add
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Jetstream\HasProfilePhoto;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles; //--> this line
class User extends Authenticatable
{
use HasApiTokens;
use HasFactory;
use HasProfilePhoto;
use Notifiable;
use TwoFactorAuthenticatable;
use HasRoles; //-> and this line
then add a new file at database/seeders/RolesSeeder.php with the following content:
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\PermissionRegistrar;
class RolesPermissionsSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
app()[PermissionRegistrar::class]->forgetCachedPermissions();
Permission::create(['name' => 'users']);
Role::create(['name' => 'Developer']);
Role::create(['name' => 'Admin'])->givePermissionTo(['users']);
Role::create(['name' => 'User']);
}
}
Next lets override the artisan command for backpack to create our user.
add a new file at app/Console/Commands/CreateBackpackUser.php
<?php
namespace App\Console\Commands;
use Backpack\CRUD\app\Console\Commands\CreateUser;
class CreateBackpackUser extends CreateUser
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'backpack:user
{--N|name= : The name of the new user}
{--E|email= : The user\'s email address}
{--P|password= : User\'s password}
{--encrypt=true : Encrypt user\'s password if it\'s plain text ( true by default )}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new user';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->info('Creating a new user');
if (! $name = $this->option('name')) {
$name = $this->ask('Name');
}
if (! $email = $this->option('email')) {
$email = $this->ask('Email');
}
if (! $password = $this->option('password')) {
$password = $this->secret('Password');
}
if ($this->option('encrypt')) {
$password = bcrypt($password);
}
$auth = config('backpack.base.user_model_fqn', 'App\User');
$user = new $auth();
$user->name = $name;
$user->email = $email;
$user->password = $password;
$user->assignRole("Admin");
if ($user->save()) {
$this->info('Successfully created new user');
} else {
$this->error('Something went wrong trying to save your user');
}
}
}
and lets configure backpack to use our admin user:
edit app/Http/Middleware/CheckIfAdmin.php and adjust the function checkIfUserIsAdmin as follows
private function checkIfUserIsAdmin($user)
{
return $user->hasAnyRole('Admin', 'Developer');
}
You should now be able to get started and create a user by running
sail artisan migrate:fresh --seed
sail artisan backpack:user
and now you should be able to view the site at http://localhost and http://localhost/admin to login to the admin panel.
Backpack has an addons that we can use to manage users & roles - add it by doing the following:
sail composer require backpack/permissionmanager
edit your User model:
<?php
namespace App\Models;
use Backpack\CRUD\app\Models\Traits\CrudTrait; //-->add this
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Jetstream\HasProfilePhoto;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasApiTokens;
use HasFactory;
use HasProfilePhoto;
use Notifiable;
use TwoFactorAuthenticatable;
use HasRoles;
use CrudTrait;//-->add this
then edit resources/views/vendor/backpack/base/inc/sidebar_content.blade.php and add the following
<!-- Users, Roles, Permissions -->
@if(backpack_user()->hasanyrole('Admin|Developer'))
<li class="nav-item nav-dropdown">
<a class="nav-link nav-dropdown-toggle" href="#"><i class="nav-icon la la-users"></i> Authentication</a>
<ul class="nav-dropdown-items">
<li class="nav-item"><a class="nav-link" href="{{ backpack_url('user') }}"><i class="nav-icon la la-user"></i>
<span>Users</span></a></li>
<li class="nav-item"><a class="nav-link" href="{{ backpack_url('role') }}"><i
class="nav-icon la la-id-badge"></i> <span>Roles</span></a></li>
<li class="nav-item"><a class="nav-link" href="{{ backpack_url('permission') }}"><i
class="nav-icon la la-key"></i> <span>Permissions</span></a></li>
</ul>
</li>
@endif
we will most likely re-address this later to use the @can permission instead.
Now with the system running lets start with our Addon - See Part 2