Dengan 15 post di database, menampilkan semuanya sekaligus di satu halaman mulai terasa berat dan sulit dinavigasi. Episode ini kita tambahkan dua fitur klasik: search dan pagination — keduanya sudah didukung Eloquent secara built-in, tidak butuh library tambahan.
Search box dan navigasi pagination di halaman daftar post (16 hasil, 3 halaman).
Search dengan when()
public function index(Request $request)
{
$search = $request->query('search');
$posts = Post::with('category')
->when($search, fn ($query) => $query->where('title', 'like', "%{$search}%"))
->latest()
->paginate(6)
->withQueryString();
return view('posts.index', compact('posts', 'search'));
}
->when($search, ...) adalah conditional query builder — closure di dalamnya hanya dijalankan kalau $search bernilai truthy (tidak null/kosong). Ini menghindari kita menulis:
if ($search) {
$query->where('title', 'like', "%{$search}%");
}
secara manual dengan if-else yang memutus method chaining.
Pagination dengan paginate()
Ganti ->get() jadi ->paginate(6) dan Laravel otomatis:
- Membatasi hasil ke 6 item per halaman
- Menyediakan object pagination lengkap dengan info halaman saat ini, total halaman, dst
- Menyediakan method
->links()untuk generate navigasi halaman di blade
->withQueryString() memastikan parameter ?search=... ikut terbawa saat pindah halaman — tanpa ini, klik "halaman 2" akan menghilangkan filter search yang sedang aktif.
Styling pagination dengan Bootstrap
Laravel 13 secara default pakai style Tailwind untuk pagination links. Karena project ini pakai Bootstrap, kita ganti default-nya di AppServiceProvider:
use Illuminate\Pagination\Paginator;
public function boot(): void
{
Paginator::useBootstrapFive();
}
Satu baris ini membuat SEMUA pagination di aplikasi otomatis pakai class Bootstrap (page-link, page-item, dst) tanpa perlu ubah view satu-satu.
Form search dan render pagination di view
<form method="GET" action="{{ route('posts.index') }}" class="mb-4 d-flex gap-2">
<input type="text" name="search" value="{{ $search }}" placeholder="Search by title..." class="form-control">
<button type="submit" class="btn btn-primary">Search</button>
</form>
@forelse ($posts as $post)
<!-- ... -->
@empty
<x-alert type="info">No posts found.</x-alert>
@endforelse
{{ $posts->links() }}
Perhatikan: {{ $posts->links() }} — cukup satu baris ini untuk render navigasi halaman lengkap (Previous, nomor halaman, Next), tidak perlu hitung manual jumlah halaman.
Kenapa search pakai GET, bukan POST?
Search adalah operasi "baca" (tidak mengubah data), jadi secara konvensi HTTP harus pakai GET. Keuntungan praktisnya: hasil pencarian punya URL sendiri (/posts?search=laravel) yang bisa di-bookmark atau di-share, sesuatu yang tidak mungkin dengan form POST.
Testing
curl "http://laravel13-blog-dasar.test/posts?search=laravel"
curl "http://laravel13-blog-dasar.test/posts?page=2"
Coba juga kombinasi keduanya, ?search=xxx&page=2 — berkat withQueryString(), filter search tetap aktif walau pindah halaman.
Selanjutnya
Fitur blog publik sudah cukup lengkap. Sekarang saatnya membatasi siapa yang boleh mengelola konten — episode berikutnya kita pasang sistem autentikasi dengan Laravel UI.