Come creare un semplice CMS Headless con Laravel

creare-un-cms-headless-con-laravel-blog-ComodoLab-web-agency

Questo tutorial parte dal presupposto che si conoscano almeno le basi di Laravel, ciò nonostante cercheremo di riportare tutti gli step necessari ad implementare un semplicissimo CMS Headless con Laravel.

Se non sapete cosa sia un CMS Headless, partiamo dalle basi. CMS è l’acronimo di Content Management System (sistema di gestione dei contenuti) e forse il membro più conosciuto di questa famiglia di applicazioni è WordPress.

Headless (tradotto: senza testa) si riferisce invece alla possibilità di rendere indipendenti front-end e back-end dei nostri siti internet.

Se nei CMS ordinari le pagine del sito web vengono “costruite” ed inviate al browser dal CMS stesso tramite il supporto di un web server, nel caso di un CMS Headless (semplificando al massimo) il sito web è un semplice client che attinge informazioni da un server remoto, solitamente tramite API REST o GraphQL, pur rimanendone indipendente.

In questo tutorial ci concentreremo sugli aspetti legati al CMS stesso, senza addentrarci nelle tecnologie adottate lato client ma per illustrare uno scenario reale possiamo immaginare di avere un’applicazione Nuxt.js ospitata su Netlify che attinga ai contenuti tramite chiamate http al nostro CMS Headless ospitato su Digital Ocean.

Fatta questa premessa è doveroso ricordare che esistono tante soluzioni pronte all’uso, sia open-source che commerciali, che sopperiscono alla necessità di implementare un CMS Headless. Tra le più conosciute possiamo menzionare strapi, Netlify CMS e Directus. Senza dimenticare che anche diversi CMS comuni possono essere utilizzati in maniera Headless come ad esempio Sulu, CMS basato su Symfony, o il celebre WordPress.

Tornando in tema però oggi parliamo di come creare un nostro CMS Headless con Laravel e l’ausilio di alcuni fondamentali pacchetti open-source scaricabili da Packagist.

Prerequisiti – Iniziamo a creare il nostro CMS Headless con Laravel

Al momento in cui scrivo Laravel è alla versione 9.5.1, mentre i tool che utilizzo per lo sviluppo:

  • Laravel Valet con PHP 8.0.16
  • DBngin con Mysql 5.7.23

Installiamo Laravel

Come prima cosa installiamo Laravel dentro la nostra cartella di Laravel Valet (qui propongo l’installazione tramite composer ma chiaramente come vi risulta più comodo in base al vostro ambiente di sviluppo):

composer create-project laravel/laravel headless-cms

E già che ci siamo inizializziamo la nostra repository e facciamo il primo commit:

cd headless-cms
git init
git add .
git commit -am "Primo commit"

Apriamo quindi il file .env e configuriamo la connessione al nostro database e l’url dell’applicazione locale:

APP_URL=http://headless-cms.test

DB_DATABASE=headless-cms

Procediamo quindi ad effettuare la migrazione del database e a pubblicare la cartella storage:

php artisan migrate
php artisan storage:link

Installiamo Filament

Ora procediamo all’installazione del pacchetto principale che gestirà tutta la UI del nostro pannello amministrativo:

composer require filament/filament:"^2.0"

E creiamo il nostro primo utente amministrativo con il comando:

php artisan make:filament-user

Ora accedendo nel browser al link http://headless-cms.test/admin/login ci troveremo di fronte una pagina di login, inseriamo le nostre credenziali per accedere all’interfaccia amministrativa.

creare-un-cms-headless-con-laravel-blog-ComodoLab-web-agency

É già qualcosa ma chiaramente dobbiamo cominciare a popolare il nostro menu applicativo con le varie voci che ci interessano.

Creiamo modello, migrazioni e risorse per le nostre pagine

Per creare il modello eseguiamo il seguente comando da terminale:

php artisan make:model Page -m

Modifichiamo quindi la migrazione appena creata in database/migrations come segue:

<?php

[...]

return new class extends Migration
{
    public function up()
    {
        Schema::create('pages', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->json('content');
            $table->timestamps();
        });
    }

    [...]
};

Effettuiamo la migrazione con:

php artisan migrate

Modifichiamo quindi il modello app/Models/Page.php:

<?php

namespace App\Models;

[...]

/**
 * @property string $title
 * @property string $content
 */
class Page extends Model
{
    protected $fillable = [
        'title',
        'content',
    ];

    protected $casts = [
        'content' => 'array'
    ];
}

Ora possiamo procedere a configurare la nostra risorsa in modo che venga automaticamente creata la relativa interfaccia grafica all’interno del pannello di amministrazione di Filament.

Eseguiamo quindi il comando:

php artisan make:filament-resource Page

Questo comando creerà tutta una serie di file all’interno della cartella app/Filament/Resources:

Se torniamo all’indirizzo http://headless-cms.test/admin/login troveremo ora che la risorsa è effettivamente tra quelle gestibili dal pannello:

Se proviamo però a creare una nuova pagina, cliccando su “New page” ci troveremo davanti ad un primo problema: nessun campo è ancora disponibile. Nel prossimo step andremo quindi a configurare il modulo che ci permetta di andare a creare e modificare i contenuti.

Creiamo il modulo per modificare le pagine

Andiamo a modificare il metodo form all’interno del file app/Filament/Resources/PageResource.php

<?php

[...]
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Builder\Block;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\TextInput;
[...]

public static function form(Form $form): Form
{
    return $form
        ->columns(1)
        ->schema([
            TextInput::make('title')
                ->required()
                ->label('Nome della pagina'),
            Builder::make('content')
                ->label('Contenuto')
                ->blocks([
                    Block::make('heading')
                        ->label('Intestazione')
                        ->schema([
                            TextInput::make('title')
                                ->label('Titolo')
                                ->required(),
                        ]),
                    Block::make('paragraph')
                        ->label('Contenuto')
                        ->schema([
                            RichEditor::make('content')
                                ->label('Paragraph')
                                ->required(),
                        ]),
                    Block::make('image')
                        ->label('Immagine')
                        ->schema([
                            FileUpload::make('url')
                                ->label('Image')
                                ->image()
                                ->required(),
                        ]),
                ])
        ]);
}

Ora torniamo sul pannello di amministrazione e quando andremo a creare una nuova pagina dovremmo trovare il modulo pronto all’uso. Provate ad inserire dei contenuti, partendo dal titolo, e dovreste riuscire ad ottenere qualcosa del genere:

Dopo averla creata, tornando alla pagina padre troverete però che la lista delle pagina non risulta formattata correttamente in quando il sistema ancora non sa quale campo vogliamo utilizzare per identificare la nostra pagina.

Torniamo a modificare app/Filament/Resources/PageResource.php e questa volta ci concentriamo sul metodo table:

<?php

[...]
use Filament\Tables\Columns\TextColumn;

public static function table(Table $table): Table
{
    return $table
        ->columns([
            TextColumn::make('title')
                ->label('Nome della pagina')
                ->searchable()
        ]);
}

Ora ricaricando il pannello di amministrazione dovremmo vedere correttamente anche la lista delle pagine, con tanto di possibilità di poterle cercare per titolo:

creare-un-cms-headless-con-laravel-blog-ComodoLab-web-agency

Arrivati a questi punto abbiamo concluso l’aspetto di configurazione della nostra risorsa. Chiaramente se stessimo implementando una soluzione reale dovremmo preoccuparci di tanti altri aspetti come le traduzioni, il ridimensionamento delle immagini, i permessi utente e molto altro ma nel nostro caso possiamo ritenerci soddisfatti. Nel prossimo passaggio vediamo assieme come restituire una rappresentazione JSON della nostra pagina usufruibile tramite API dal nostro applicativo client.

Sviluppiamo una semplice API per accedere alle pagine

Come prima cosa creiamo un Controller tramite il comando:

php artisan make:controller PageController

Andiamo quindi a modificare il file creato app/Http/Controllers/PageController.php:

<?php

namespace App\Http\Controllers;

use App\Models\Page;

class PageController extends Controller
{
    public function show(Page $page): array
    {
        return ['data' => $page];
    }
}

Aggiungiamo quindi una rotta in routes/api.php:

<?php

use App\Http\Controllers\PageController;
use Illuminate\Support\Facades\Route;

Route::get('pages/{page}', [PageController::class, 'show']);

Ora apriamo il seguente link nel browser http://headless-cms.test/api/pages/1 e se tutto è andato bene dovremmo ottenere qualcosa del genere:

creare-un-cms-headless-con-laravel-blog-ComodoLab-web-agency

Vuoi continuare a leggere gli articoli di ComodoLab?

Allora ISCRIVITI gratuitamente alla Newsletter adesso! 👇