Cara Membuat CMS Sederhana Menggunakan Laravel

Membangun Content Management System (CMS) adalah salah satu proyek fundamental yang sering dilakukan oleh developer web. CMS memungkinkan non-teknis untuk mengelola konten website dengan mudah, tanpa perlu menyentuh baris kode. Lalu, bagaimana jika kita ingin membangun CMS sendiri? Laravel, sebagai salah satu framework PHP paling populer, menawarkan ekosistem yang powerful dan intuitif untuk mewujudkannya.

Dalam artikel ini, kita akan membahas langkah demi langkah bagaimana cara membuat CMS sederhana menggunakan Laravel. Kita akan fokus pada fitur inti seperti manajemen artikel (CRUD: Create, Read, Update, Delete) dan sistem autentikasi dasar. Anggap saja ini adalah fondasi untuk CMS yang bisa Anda kembangkan lebih jauh sesuai kebutuhan.

Mengapa Laravel Cocok untuk Membuat CMS?

Laravel dikenal dengan sintaksisnya yang ekspresif, fitur-fitur yang lengkap, dan ekosistem yang luas. Beberapa alasan mengapa Laravel menjadi pilihan tepat untuk membangun CMS adalah:

  • Sistem Autentikasi yang Kuat: Laravel menyediakan fitur autentikasi siap pakai dengan starter kit seperti Breeze atau Jetstream, menghemat banyak waktu.
  • Eloquent ORM: Interaksi dengan database menjadi sangat mudah dan intuitif.
  • Routing yang Fleksibel: Mengelola URL dan logika aplikasi menjadi terstruktur.
  • Blade Templating Engine: Membangun tampilan antarmuka yang dinamis dan mudah dibaca.
  • Ekosistem Paket yang Luas: Banyak package pihak ketiga yang bisa digunakan untuk menambah fungsionalitas seperti editor teks kaya, manajemen file, dan lainnya.
  • Komunitas Aktif: Sumber daya dan dukungan yang melimpah jika Anda mengalami kesulitan.

Pengalaman saya menggunakan Laravel untuk berbagai proyek, dari website sederhana hingga aplikasi enterprise, selalu menunjukkan efisiensi dan kemudahan pengembangannya. Untuk CMS sederhana, Laravel Breeze sudah lebih dari cukup untuk memulai.

Persiapan Awal: Lingkungan Pengembangan

Sebelum memulai, pastikan Anda memiliki lingkungan pengembangan yang sesuai:

  • PHP: Versi 8.1 atau yang lebih baru.
  • Composer: Untuk manajemen dependensi PHP.
  • MySQL/PostgreSQL/SQLite: Sebagai database pilihan Anda.
  • Node.js & npm/Yarn: Untuk mengelola aset frontend (CSS/JS).
  • Text Editor: VS Code, Sublime Text, atau PHPStorm.

Langkah 1: Membuat Proyek Laravel Baru

Buka terminal Anda dan jalankan perintah berikut untuk membuat proyek Laravel baru. Kita akan beri nama proyeknya simple-cms-laravel.

composer create-project laravel/laravel simple-cms-laravel

Setelah selesai, masuk ke direktori proyek:

cd simple-cms-laravel

Langkah 2: Konfigurasi Database

Buka file .env di root proyek Anda. Sesuaikan konfigurasi database Anda:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=simple_cms_db
DB_USERNAME=root
DB_PASSWORD=

Pastikan Anda sudah membuat database dengan nama simple_cms_db (atau nama lain pilihan Anda) di server database Anda.

Langkah 3: Mengimplementasikan Sistem Autentikasi dengan Laravel Breeze

Sistem autentikasi adalah fondasi penting untuk CMS agar hanya pengguna terdaftar yang bisa mengelola konten. Laravel Breeze menyediakan scaffolding autentikasi yang ringan dan mudah diintegrasikan.

  1. Instal Laravel Breeze:

    composer require laravel/breeze --dev

  2. Install Breeze Scaffolding:
    Untuk proyek baru, kita bisa pilih tumpukan Livewire atau React/Vue. Untuk kesederhanaan, kita akan menggunakan tumpukan Blade (tanpa Livewire/Vue/React).

    php artisan breeze:install

    Pilih blade ketika diminta. Ini akan menghasilkan file-file views, controller, dan routes yang diperlukan untuk autentikasi.

  3. Jalankan Migration:
    Breeze akan membuat migration untuk tabel users. Kita perlu menjalankannya agar tabel ini terbuat di database.

    php artisan migrate

  4. Install NPM Dependencies dan Compile Assets:
    Frontend assets (CSS, JavaScript) untuk Breeze perlu diinstal dan dikompilasi.

    npm install
    npm run dev

  5. Mulai Server Pengembangan:

    php artisan serve

Sekarang, Anda bisa mengunjungi http://127.0.0.1:8000/register untuk membuat akun pengguna baru dan http://127.0.0.1:8000/login untuk masuk.

Langkah 4: Membuat Struktur Database dan Model untuk Post

CMS membutuhkan tempat untuk menyimpan konten kita. Kita akan membuat tabel posts.

1. Membuat Migration untuk Tabel Posts

Jalankan perintah Artisan untuk membuat migration:

php artisan make:migration create_posts_table

Buka file migration yang baru dibuat di direktori database/migrations/. Edit metode up() seperti berikut:

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('title');
$table->string('slug')->unique();
$table->longText('content');
$table->timestamp('published_at')->nullable();
$table->timestamps();
});
}

public function down(): void
{
Schema::dropIfExists('posts');
}
};

Beberapa poin penting:

  • user_id: Foreign key yang mengacu pada tabel users, menandakan siapa yang membuat post.
  • slug: URL-friendly version dari judul, harus unik.
  • content: Teks panjang untuk isi artikel.
  • published_at: Opsional, untuk menjadwalkan publikasi atau menandai post sebagai draft.

Setelah itu, jalankan migration:

php artisan migrate

2. Membuat Model Post

Model akan bertindak sebagai antarmuka untuk berinteraksi dengan tabel posts. Jalankan perintah:

php artisan make:model Post

Buka file app/Models/Post.php dan tambahkan properti $fillable untuk memungkinkan mass assignment. Juga tambahkan relasi ke model User.

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Post extends Model
{
use HasFactory;

protected $fillable = [
'user_id',
'title',
'slug',
'content',
'published_at',
];

protected $casts = [
'published_at' => 'datetime',
];

public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}

Jangan lupa tambahkan relasi juga di model User (app/Models/User.php):

<?php
namespace App\Models;

// ... other uses
use Illuminate\Database\Eloquent\Relations\HasMany;

class User extends Authenticatable
{
// ... existing code

public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
}

Langkah 5: Membuat CRUD untuk Post

Ini adalah inti dari CMS kita: kemampuan untuk membuat, melihat, mengedit, dan menghapus postingan.

1. Membuat Controller Post

Kita akan menggunakan resource controller yang menyediakan semua metode CRUD standar. Jalankan perintah:

php artisan make:controller PostController --resource

2. Mendefinisikan Routes

Buka file routes/web.php dan tambahkan resource route untuk PostController. Kita juga akan melindungi route ini agar hanya bisa diakses oleh pengguna yang sudah login.

<?php
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\PostController;
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
return view('welcome');
});

Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');

Route::middleware('auth')->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');

// Routes untuk CMS Posts
Route::resource('posts', PostController::class);
});

require __DIR__.'/auth.php';

Perintah Route::resource('posts', PostController::class); secara otomatis membuat route untuk index, create, store, show, edit, update, dan destroy.

3. Mengimplementasikan Logika di PostController

Buka app/Http/Controllers/PostController.php dan isi metode-metodenya:

<?php
namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;

class PostController extends Controller
{
public function index()
{
$posts = Post::latest()->paginate(10);
return view('posts.index', compact('posts'));
}

public function create()
{
return view('posts.create');
}

public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string',
'published_at' => 'nullable|date',
]);

$validated['user_id'] = auth()->id();
$validated['slug'] = Str::slug($request->title) . '-' . time();

Post::create($validated);

return redirect()->route('posts.index')->with('success', 'Post berhasil dibuat!');
}

public function show(Post $post)
{
return view('posts.show', compact('post'));
}

public function edit(Post $post)
{
$this->authorize('update', $post); // Pastikan hanya pemilik yang bisa mengedit
return view('posts.edit', compact('post'));
}

public function update(Request $request, Post $post)
{
$this->authorize('update', $post);

$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string',
'published_at' => 'nullable|date',
]);

// Update slug hanya jika judul berubah
if ($request->title !== $post->title) {
$validated['slug'] = Str::slug($request->title) . '-' . time();
}

$post->update($validated);

return redirect()->route('posts.index')->with('success', 'Post berhasil diperbarui!');
}

public function destroy(Post $post) {
$this->authorize('delete', $post);

$post->delete();

return redirect()->route('posts.index')->with('success', 'Post berhasil dihapus!');
}
}

Catatan Penting: Di sini saya menambahkan $this->authorize('update', $post); dan $this->authorize('delete', $post);. Ini memerlukan implementasi Policy. Untuk CMS sederhana, Anda bisa menghapus baris ini untuk sementara jika tidak ingin terlalu dalam dengan authorization, namun sangat disarankan untuk keamanan. Untuk implementasinya, Anda bisa membuat php artisan make:policy PostPolicy --model=Post dan definisikan metode update dan delete di sana.

4. Membuat Views untuk Post

Buat folder posts di dalam resources/views/. Kita akan membuat empat file Blade:

a. resources/views/posts/index.blade.php (Daftar Post)

Ini akan menampilkan daftar semua postingan, dengan link untuk membuat, melihat, mengedit, dan menghapus.

<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Manajemen Post') }}
</h2>
</x-slot>

<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 text-gray-900">
<div class="flex justify-end mb-4">
<a href="{{ route('posts.create') }}" class="inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150">Buat Post Baru</a>
</div>

<@if (session('success'))
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4" role="alert">
<span class="block sm:inline">{{ session('success') }}</span>
</div>
<@endif

<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Judul</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Penulis</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tanggal Publikasi</th>
<th scope="col" class="relative px-6 py-3"><span class="sr-only">Aksi</span></th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<@forelse ($posts as $post)
<tr>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">{{ $post->title }}</div>
<div class="text-sm text-gray-500">/{{ $post->slug }}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $post->user->name }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $post->published_at ? 'Published' : 'Draft' }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $post->published_at ? $post->published_at->format('d M Y') : '-' }}</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<a href="{{ route('posts.show', $post) }}" class="text-indigo-600 hover:text-indigo-900 mr-2">Lihat</a>
<a href="{{ route('posts.edit', $post) }}" class="text-green-600 hover:text-green-900 mr-2">Edit</a>
<form action="{{ route('posts.destroy', $post) }}" method="POST" class="inline" onsubmit="return confirm('Apakah Anda yakin ingin menghapus post ini?');">


<button type="submit" class="text-red-600 hover:text-red-900">Hapus</button>
</form>
</td>
</tr>
<@empty
<tr>
<td colspan="5" class="px-6 py-4 whitespace-nowrap text-center text-sm text-gray-500">Belum ada post yang dibuat.</td>
</tr>
<@endforelse
</tbody>
</table>
</div>
<div class="mt-4">
{{ $posts->links() }}
</div>
</div>
</div>
</div>
</div>
</x-app-layout>

b. resources/views/posts/create.blade.php (Form Buat Post Baru)

<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Buat Post Baru') }}
</h2>
</x-slot>

<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 text-gray-900">
<form method="POST" action="{{ route('posts.store') }}">

<div>
<x-input-label for="title" :value="__('Judul')" />
<x-text-input id="title" class="block mt-1 w-full" type="text" name="title" :value="old('title')" required autofocus />
<x-input-error :messages="$errors->get('title')" class="mt-2" />
</div>

<div class="mt-4">
<x-input-label for="content" :value="__('Konten')" />
<textarea id="content" name="content" rows="10" class="border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm block mt-1 w-full" required>{{ old('content') }}</textarea>
<x-input-error :messages="$errors->get('content')" class="mt-2" />
</div>

<div class="mt-4">
<x-input-label for="published_at" :value="__('Tanggal Publikasi (Opsional)')" />
<x-text-input id="published_at" class="block mt-1 w-full" type="date" name="published_at" :value="old('published_at')" />
<x-input-error :messages="$errors->get('published_at')" class="mt-2" />
</div>

<div class="flex items-center justify-end mt-4">
<x-primary-button class="ml-4">
{{ __('Simpan Post') }}
</x-primary-button>
</div>
</form>
</div>
</div>
</div>
</div>
</x-app-layout>

c. resources/views/posts/edit.blade.php (Form Edit Post)

Mirip dengan form create, tapi dengan data yang sudah terisi dan metode PUT/PATCH.

<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Edit Post') }}
</h2>
</x-slot>

<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 text-gray-900">
<form method="POST" action="{{ route('posts.update', $post) }}">

<div>
<x-input-label for="title" :value="__('Judul')" />
<x-text-input id="title" class="block mt-1 w-full" type="text" name="title" :value="old('title', $post->title)" required autofocus />
<x-input-error :messages="$errors->get('title')" class="mt-2" />
</div>

<div class="mt-4">
<x-input-label for="content" :value="__('Konten')" />
<textarea id="content" name="content" rows="10" class="border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm block mt-1 w-full" required>{{ old('content', $post->content) }}</textarea>
<x-input-error :messages="$errors->get('content')" class="mt-2" />
</div>

<div class="mt-4">
<x-input-label for="published_at" :value="__('Tanggal Publikasi (Opsional)')" />
<x-text-input id="published_at" class="block mt-1 w-full" type="date" name="published_at" :value="old('published_at', $post->published_at ? $post->published_at->format('Y-m-d') : '')" />
<x-input-error :messages="$errors->get('published_at')" class="mt-2" />
</div>

<div class="flex items-center justify-end mt-4">
<x-primary-button class="ml-4">
{{ __('Perbarui Post') }}
</x-primary-button>
</div>
</form>
</div>
</div>
</div>
</div>
</x-app-layout>

d. resources/views/posts/show.blade.php (Detail Post)

Ini adalah tampilan sederhana untuk melihat detail satu post.

<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ $post->title }}
</h2>
</x-slot>

<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 text-gray-900">
<p class="text-sm text-gray-600 mb-4">
Oleh: {{ $post->user->name }} | {{ $post->published_at ? 'Dipublikasikan pada: ' . $post->published_at->format('d M Y') : 'Status: Draft' }}
</p>
<div class="prose max-w-none">
{!! $post->content !!} <!-- Hati-hati dengan output raw HTML, pastikan sudah di-sanitized -->
</div>
<div class="mt-6">
<a href="{{ route('posts.index') }}" class="inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150">Kembali ke Daftar Post</a>
</div>
</div>
</div>
</div>
</div>
</x-app-layout>

5. Memodifikasi Navigasi Dashboard

Agar lebih mudah mengakses manajemen post, kita bisa menambahkan link di navigasi dashboard. Buka resources/views/layouts/navigation.blade.php dan tambahkan di bagian “Dashboard” link ke manajemen post:

<x-nav-link :href="route('posts.index')" :active="request()->routeIs('posts.*')">
{{ __('Manajemen Post') }}
</x-nav-link>

Anda bisa meletakkannya setelah link Dashboard yang ada.

Langkah 6: Menambahkan Rich Text Editor (Opsional, tapi Sangat Dianjurkan)

Untuk CMS, memiliki rich text editor (RTE) seperti TinyMCE atau CKEditor akan sangat membantu pengguna dalam membuat dan memformat konten tanpa perlu menulis HTML. Integrasi RTE biasanya melibatkan:

  1. Menambahkan library RTE via CDN atau NPM.
  2. Menginisialisasi RTE pada textarea di form create.blade.php dan edit.blade.php.

Contoh singkat dengan TinyMCE (menggunakan CDN untuk kemudahan):

Tambahkan script CDN TinyMCE di file resources/views/layouts/app.blade.php di bagian <head> atau sebelum tag penutup </body>:

<script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/6/tinymce.min.js" referrerpolicy="origin"></script>
<script>
tinymce.init({
selector: 'textarea#content',
plugins: 'advlist autolink lists link image charmap print preview anchor searchreplace visualblocks code fullscreen insertdatetime media table paste code help wordcount',
toolbar: 'undo redo | formatselect | bold italic backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | help'
});
</script>

Kemudian, pastikan textarea di create.blade.php dan edit.blade.php memiliki id="content" agar TinyMCE bisa menginisialisasi dengan benar. Ini akan mengubah textarea biasa menjadi editor teks yang powerful.

Pengalaman dan Pertimbangan Praktis

Membangun CMS sederhana dengan Laravel adalah titik awal yang fantastis. Dalam praktiknya, ada beberapa pertimbangan yang sering muncul:

  • Skalabilitas Fitur: CMS sederhana ini bagus untuk blog pribadi atau situs berita kecil. Untuk fitur yang lebih kompleks seperti manajemen media, taksonomi kustom, atau roles/permissions yang lebih granular, Anda mungkin perlu mengintegrasikan package seperti Spatie Laravel Permission atau mempertimbangkan solusi admin panel seperti Laravel Nova, Filament, atau AdminLTE. Saya pribadi sering menggunakan Filament karena fleksibilitas dan kecepatan pengembangannya yang luar biasa untuk dashboard admin.
  • Keamanan: Selalu ingat tentang validasi input, sanitasi output (terutama saat menampilkan konten dari RTE), dan otorisasi. Laravel Breeze sudah mencakup beberapa dasar keamanan, tetapi pastikan Anda mengimplementasikan Policy untuk kontrol akses yang lebih baik (misal, hanya penulis yang bisa mengedit atau menghapus post mereka sendiri).
  • Performa: Untuk CMS yang mungkin memiliki ribuan post, pertimbangkan caching (Laravel memiliki fitur caching yang powerful), optimasi query (hindari N+1 problem dengan with()), dan indexing database.
  • Deployment: Saat siap untuk produksi, pastikan konfigurasi server Anda aman dan dioptimalkan. Gunakan Nginx atau Apache, PHP-FPM, dan pastikan file .env tidak diakses publik.
  • SEO: Untuk setiap post, tambahkan kolom untuk meta title, meta description, dan gambar thumbnail (featured image) agar CMS Anda bisa menghasilkan konten yang SEO friendly.

Masalah yang Sering Terjadi

Saat mengikuti tutorial ini, beberapa masalah umum yang mungkin Anda temui dan solusinya:

1. Migration Error: Table Already Exists

Gejala: Saat menjalankan php artisan migrate, Anda mendapatkan pesan error bahwa tabel seperti users atau personal_access_tokens sudah ada.

Penyebab: Anda mungkin pernah menjalankan migration sebelumnya atau database yang Anda gunakan sudah memiliki tabel-tabel tersebut.

Solusi: Jika Anda memulai proyek baru dan tidak keberatan kehilangan data, gunakan php artisan migrate:fresh. Ini akan menghapus semua tabel dan menjalankan ulang semua migration. Jika Anda ingin mempertahankan data, pastikan nama database di .env adalah database kosong yang baru.

2. Route Not Found (404 Not Found)

Gejala: Anda mencoba mengakses URL seperti /posts atau /posts/create tetapi mendapatkan error 404.

Penyebab: Route belum didefinisikan dengan benar di routes/web.php, atau Anda lupa memulai server dengan php artisan serve, atau web server Anda (Apache/Nginx) belum dikonfigurasi untuk URL rewrite.

Solusi: Pastikan Anda telah menambahkan Route::resource('posts', PostController::class); di dalam middleware auth. Cek juga bahwa server Laravel berjalan. Untuk masalah web server, pastikan .htaccess ada di public folder (untuk Apache) atau konfigurasi Nginx sudah benar.

3. View Not Found Exception

Gejala: Error View [posts.index] not found atau serupa.

Penyebab: File Blade view (misalnya, index.blade.php) tidak ada di lokasi yang diharapkan (resources/views/posts/) atau ada kesalahan ketik pada nama file atau path.

Solusi: Periksa kembali nama folder dan file di resources/views/. Pastikan nama filenya index.blade.php, create.blade.php, dll., dan berada di dalam folder posts.

4. CSRF Token Mismatch on Form Submission

Gejala: Saat submit form (misalnya, membuat atau mengedit post), Anda mendapatkan error 419 Page Expired.

Penyebab: Anda lupa menyertakan directive di dalam form HTML Anda.

Solusi: Pastikan setiap form <form method="POST" ...> memiliki baris setelah tag pembuka <form>.

5. Authorization Exception (This action is unauthorized.)

Gejala: Saat mencoba mengedit atau menghapus post, Anda mendapatkan error This action is unauthorized.

Penyebab: Ini karena kita menambahkan baris $this->authorize('update', $post); atau $this->authorize('delete', $post); di PostController, tetapi belum mengimplementasikan Policy yang sesuai.

Solusi: Untuk sementara, Anda bisa menghapus baris $this->authorize(...) dari PostController. Untuk solusi yang tepat, buat PostPolicy (php artisan make:policy PostPolicy --model=Post) dan daftarkan di AuthServiceProvider. Kemudian implementasikan metode update dan delete di PostPolicy untuk mengizinkan pengguna yang sesuai (misalnya, return $user->id === $post->user_id;).

FAQ

Apa itu CMS?

CMS (Content Management System) adalah aplikasi software yang memungkinkan pengguna untuk membuat, mengelola, dan mempublikasikan konten digital di website tanpa perlu pengetahuan teknis coding yang mendalam. Contoh populer termasuk WordPress, Joomla, dan Drupal.

Apakah Laravel cocok untuk CMS berskala besar?

Ya, Laravel sangat cocok untuk CMS berskala besar. Banyak CMS kustom dan bahkan admin panel seperti Laravel Nova atau Filament dibangun di atas Laravel. Skalabilitasnya, ditambah dengan ekosistem paket yang kaya, menjadikannya pilihan yang solid untuk proyek-proyek yang membutuhkan fleksibilitas dan performa tinggi.

Apa saja alternatif CMS atau admin panel di Laravel?

Selain membangun CMS dari nol seperti yang kita lakukan, Anda bisa mempertimbangkan:

  • Filament PHP: Admin panel builder yang modern, cepat, dan berbasis Livewire. Sangat direkomendasikan.
  • Laravel Nova: Admin panel premium dari tim Laravel, sangat kuat untuk manajemen resource.
  • Voyager: Admin panel gratis dengan banyak fitur out-of-the-box.
  • Backpack for Laravel: Solusi admin panel lain yang powerful dan fleksibel, cocok untuk proyek skala menengah hingga besar.

Kesimpulan

Anda telah berhasil membangun CMS sederhana menggunakan Laravel! Dari menyiapkan proyek, mengintegrasikan autentikasi dengan Laravel Breeze, hingga membuat fungsionalitas CRUD untuk post, kita telah meletakkan fondasi yang kuat. Pengalaman saya menunjukkan bahwa memahami konsep dasar ini adalah kunci untuk bisa mengembangkan aplikasi Laravel yang lebih kompleks.

CMS yang kita buat ini adalah titik awal. Dari sini, Anda bisa mulai menambahkan fitur-fitur lain seperti manajemen kategori, upload gambar, roles dan permissions yang lebih canggih, atau bahkan integrasi dengan API eksternal. Laravel memberikan fleksibilitas tak terbatas untuk kustomisasi. Teruslah bereksplorasi dan jangan ragu untuk menyelami dokumentasi Laravel yang sangat lengkap.

Proyek ini bukan hanya tentang menciptakan fungsionalitas, tetapi juga tentang memahami arsitektur dan filosofi Laravel. Dengan bekal ini, Anda siap untuk menghadapi tantangan pengembangan web yang lebih besar!

TAGS: Laravel, CMS, PHP, Web Development, Programming, Backend, Developer Tools, Tutorial


Baca Juga

You May Also Like

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *