Saat menampilkan data dalam jumlah besar dari database, memuat semuanya sekaligus dalam satu halaman bukan pilihan yang baik โ halaman jadi lambat dan pengguna kesulitan menavigasi. Solusinya adalah pagination (paginasi): membagi data menjadi beberapa halaman dengan jumlah baris tertentu per halaman. Pada tutorial ini, kita akan membangun pagination dari nol menggunakan PHP native dan MySQL.
Konsep Dasar Pagination
Pagination bekerja dengan memanfaatkan klausa SQL LIMIT dan OFFSET:
LIMITโ jumlah baris yang diambil per halaman (misalnya 10).OFFSETโ berapa baris yang dilewati sebelum mulai mengambil data.
Misalnya, untuk halaman 3 dengan 10 data per halaman: LIMIT 10 OFFSET 20 (skip 20 baris pertama, ambil 10 berikutnya). Rumusnya: OFFSET = (halaman_sekarang - 1) * data_per_halaman.
Persiapan Database
Pastikan kamu memiliki tabel dengan cukup banyak data. Untuk uji coba, gunakan tabel artikel sederhana:
CREATE TABLE artikel (
id INT AUTO_INCREMENT PRIMARY KEY,
judul VARCHAR(200) NOT NULL,
isi TEXT,
tanggal DATE NOT NULL
);
-- Isi dengan data dummy (jalankan beberapa kali)
INSERT INTO artikel (judul, isi, tanggal) VALUES
('Artikel PHP 1', 'Konten artikel 1...', '2024-01-01'),
('Artikel PHP 2', 'Konten artikel 2...', '2024-01-02'),
('Artikel PHP 3', 'Konten artikel 3...', '2024-01-03');
-- Tambahkan hingga 50+ baris untuk tes yang baik
File Koneksi Database
<?php
// koneksi.php
$dsn = "mysql:host=localhost;dbname=nama_database;charset=utf8mb4";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
$pdo = new PDO($dsn, 'root', '', $options);
Logika Pagination PHP
Buat file daftar_artikel.php dengan logika pagination lengkap:
<?php
require 'koneksi.php';
// Konfigurasi pagination
$per_halaman = 10; // jumlah data per halaman
// Ambil nomor halaman dari URL, default ke 1
$halaman = max(1, (int) ($_GET['halaman'] ?? 1));
// Hitung total data
$total_data = (int) $pdo->query("SELECT COUNT(*) FROM artikel")->fetchColumn();
// Hitung total halaman
$total_halaman = (int) ceil($total_data / $per_halaman);
// Pastikan halaman tidak melebihi total
$halaman = min($halaman, max(1, $total_halaman));
// Hitung offset
$offset = ($halaman - 1) * $per_halaman;
// Ambil data untuk halaman ini
$stmt = $pdo->prepare(
"SELECT id, judul, tanggal FROM artikel ORDER BY tanggal DESC LIMIT :limit OFFSET :offset"
);
$stmt->bindValue(':limit', $per_halaman, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$artikel = $stmt->fetchAll();
?>
<!-- Tampilkan data -->
<h2>Daftar Artikel (Halaman <?= $halaman ?> dari <?= $total_halaman ?>)</h2>
<p>Total: <?= $total_data ?> artikel</p>
<ul>
<?php foreach ($artikel as $item): ?>
<li>
<a href="artikel.php?id=<?= $item['id'] ?>">
<?= htmlspecialchars($item['judul']) ?>
</a>
<small>โ <?= $item['tanggal'] ?></small>
</li>
<?php endforeach; ?>
</ul>
Perhatikan penggunaan bindValue() dengan PDO::PARAM_INT untuk LIMIT dan OFFSET โ ini wajib karena nilai integer tidak bisa diparameterisasi dengan ? biasa di beberapa konfigurasi PDO.
Membuat Navigasi Halaman
Tambahkan kode berikut setelah daftar artikel untuk menampilkan link navigasi:
<?php
function buatLinkPaginasi(int $halaman, int $total_halaman, string $url_dasar = '?'): string
{
$html = '<nav><ul style="list-style:none; display:flex; gap:8px;">';
// Tombol "Sebelumnya"
if ($halaman > 1) {
$prev = $halaman - 1;
$html .= "<li><a href='{$url_dasar}halaman=$prev'>« Sebelumnya</a></li>";
}
// Nomor halaman (tampilkan maksimal 5 halaman di sekitar halaman aktif)
$mulai = max(1, $halaman - 2);
$akhir = min($total_halaman, $halaman + 2);
if ($mulai > 1) {
$html .= "<li><a href='{$url_dasar}halaman=1'>1</a></li>";
if ($mulai > 2) {
$html .= "<li><span>...</span></li>";
}
}
for ($i = $mulai; $i <= $akhir; $i++) {
$aktif = ($i === $halaman) ? ' style="font-weight:bold;"' : '';
$html .= "<li><a href='{$url_dasar}halaman=$i'$aktif>$i</a></li>";
}
if ($akhir < $total_halaman) {
if ($akhir < $total_halaman - 1) {
$html .= "<li><span>...</span></li>";
}
$html .= "<li><a href='{$url_dasar}halaman=$total_halaman'>$total_halaman</a></li>";
}
// Tombol "Berikutnya"
if ($halaman < $total_halaman) {
$next = $halaman + 1;
$html .= "<li><a href='{$url_dasar}halaman=$next'>Berikutnya »</a></li>";
}
$html .= '</ul></nav>';
return $html;
}
// Tampilkan navigasi
echo buatLinkPaginasi($halaman, $total_halaman);
Pagination dengan Filter Pencarian
Untuk menggabungkan pagination dengan fitur pencarian, pastikan parameter pencarian ikut terbawa di setiap link halaman:
<?php
$keyword = htmlspecialchars(trim($_GET['q'] ?? ''));
$per_halaman = 10;
$halaman = max(1, (int) ($_GET['halaman'] ?? 1));
// Query dengan filter pencarian
$stmt_count = $pdo->prepare("SELECT COUNT(*) FROM artikel WHERE judul LIKE :q");
$stmt_count->execute([':q' => "%$keyword%"]);
$total_data = (int) $stmt_count->fetchColumn();
$total_halaman = (int) ceil($total_data / $per_halaman);
$offset = ($halaman - 1) * $per_halaman;
$stmt = $pdo->prepare(
"SELECT id, judul, tanggal FROM artikel WHERE judul LIKE :q ORDER BY tanggal DESC LIMIT :limit OFFSET :offset"
);
$stmt->bindValue(':q', "%$keyword%", PDO::PARAM_STR);
$stmt->bindValue(':limit', $per_halaman, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$artikel = $stmt->fetchAll();
// URL dasar menyertakan parameter pencarian
$url_dasar = "?q=" . urlencode($keyword) . "&";
echo buatLinkPaginasi($halaman, $total_halaman, $url_dasar);
Kesimpulan
Pagination sederhana dengan PHP dan MySQL hanya membutuhkan beberapa konsep dasar: menghitung total data, menentukan offset berdasarkan halaman aktif, menggunakan LIMIT dan OFFSET di query SQL, lalu membuat link navigasi yang menyertakan parameter halaman di URL. Fungsi pagination yang sudah dibuat bisa digunakan ulang di banyak halaman. Dari fondasi ini, kamu bisa mengembangkannya lebih lanjut dengan AJAX untuk pengalaman yang lebih mulus.