Cara Membuat Paging (Pagination) Halaman dengan PHP dan MySQL

Paging atau pagination adalah teknik membagi data menjadi beberapa halaman agar tidak ditampilkan sekaligus. Ini sangat penting untuk website yang memiliki banyak data, karena menampilkan ratusan atau ribuan data sekaligus akan membuat halaman lambat dan sulit dinavigasi.
Dalam tutorial ini, kita akan membuat pagination dengan PHP dan MySQL dari yang paling sederhana sampai yang lebih advanced dengan AJAX dan infinite scroll.
Kenapa Pagination Penting?
- Performa —加载少量 data lebih cepat
- UX — pengguna bisa navigasi dengan mudah
- SEO — search engine lebih suka halaman yang terstruktur
- Resource — mengurangi beban server dan database
Persiapan Database
CREATE DATABASE pagination_db;
USE pagination_db;
CREATE TABLE mahasiswa (
id INT AUTO_INCREMENT PRIMARY KEY,
nim VARCHAR(12) NOT NULL,
nama VARCHAR(100) NOT NULL,
jurusan VARCHAR(50) NOT NULL,
angkatan INT NOT NULL,
ipk DECIMAL(3,2) DEFAULT 0.00,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Insert 50 data contoh
INSERT INTO mahasiswa (nim, nama, jurusan, angkatan, ipk) VALUES
('2021001', 'Ahmad Fauzi', 'Teknik Informatika', 2021, 3.45),
('2021002', 'Budi Santoso', 'Sistem Informasi', 2021, 3.20),
('2021003', 'Citra Dewi', 'Teknik Informatika', 2021, 3.78),
('2021004', 'Dian Permata', 'Sistem Informasi', 2021, 3.55),
('2021005', 'Eko Prasetyo', 'Teknik Komputer', 2021, 3.10),
('2021006', 'Fitri Handayani', 'Teknik Informatika', 2021, 3.89),
('2021007', 'Gunawan Wibisono', 'Sistem Informasi', 2021, 2.95),
('2021008', 'Hana Sari', 'Teknik Informatika', 2021, 3.67),
('2021009', 'Irfan Hakim', 'Teknik Komputer', 2021, 3.33),
('2021010', 'Juli Astuti', 'Sistem Informasi', 2021, 3.42),
('2022001', 'Kurniawan', 'Teknik Informatika', 2022, 3.50),
('2022002', 'Lina Marlina', 'Sistem Informasi', 2022, 3.72),
('2022003', 'Muhammad Rizki', 'Teknik Informatika', 2022, 3.15),
('2022004', 'Nadia Putri', 'Teknik Komputer', 2022, 3.88),
('2022005', 'Oscar Firmansyah', 'Sistem Informasi', 2022, 2.80),
('2022006', 'Putri Rahayu', 'Teknik Informatika', 2022, 3.60),
('2022007', 'Qori Aulia', 'Teknik Komputer', 2022, 3.25),
('2022008', 'Rendi Saputra', 'Sistem Informasi', 2022, 3.40),
('2022009', 'Sinta Amelia', 'Teknik Informatika', 2022, 3.75),
('2022010', 'Taufik Hidayat', 'Teknik Komputer', 2022, 3.05);
Metode 1: Pagination Sederhana
Buat file index.php:
<?php
require_once 'config/database.php';
// ===== KONFIGURASI PAGINATION =====
$per_page = 10; // Jumlah data per halaman
$halaman_sekarang = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
$offset = ($halaman_sekarang - 1) * $per_page;
// ===== AMBIL DATA =====
// Hitung total data
$total_data = $pdo->query('SELECT COUNT(*) FROM mahasiswa')->fetchColumn();
// Hitung total halaman
$total_halaman = ceil($total_data / $per_page);
// Ambil data untuk halaman saat ini
$stmt = $pdo->prepare('SELECT * FROM mahasiswa ORDER BY id DESC LIMIT ? OFFSET ?');
$stmt->bindValue(1, $per_page, PDO::PARAM_INT);
$stmt->bindValue(2, $offset, PDO::PARAM_INT);
$stmt->execute();
$data = $stmt->fetchAll();
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pagination PHP - Data Mahasiswa</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Segoe UI', Arial, sans-serif; background: #f3f4f6; padding: 30px; }
.container { max-width: 900px; margin: 0 auto; }
h1 { color: #1e293b; margin-bottom: 5px; }
.info { color: #6b7280; margin-bottom: 20px; }
table { width: 100%; border-collapse: collapse; background: white; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
th, td { padding: 12px 15px; text-align: left; border-bottom: 1px solid #e5e7eb; }
th { background: #1e293b; color: white; font-size: 13px; text-transform: uppercase; }
tr:hover { background: #f9fafb; }
.badge { padding: 3px 10px; border-radius: 12px; font-size: 12px; font-weight: 600; }
.badge-ti { background: #dbeafe; color: #1d4ed8; }
.badge-si { background: #dcfce7; color: #16a34a; }
.badge-tk { background: #fef3c7; color: #d97706; }
/* Pagination */
.pagination { display: flex; justify-content: center; align-items: center; gap: 5px; margin-top: 25px; flex-wrap: wrap; }
.pagination a, .pagination span {
padding: 8px 14px;
border: 1px solid #d1d5db;
border-radius: 6px;
text-decoration: none;
color: #374151;
font-size: 14px;
transition: all 0.2s;
}
.pagination a:hover { background: #f3f4f6; border-color: #9ca3af; }
.pagination .active { background: #3b82f6; color: white; border-color: #3b82f6; }
.pagination .disabled { color: #d1d5db; pointer-events: none; }
.page-info { color: #6b7280; font-size: 14px; margin-top: 10px; text-align: center; }
</style>
</head>
<body>
<div class="container">
<h1>Data Mahasiswa</h1>
<p class="info">Menampilkan <?= count($data) ?> dari <?= $total_data ?> data</p>
<table>
<thead>
<tr>
<th>No</th>
<th>NIM</th>
<th>Nama</th>
<th>Jurusan</th>
<th>Angkatan</th>
<th>IPK</th>
</tr>
</thead>
<tbody>
<?php if (empty($data)): ?>
<tr><td colspan="6" style="text-align:center;padding:30px;color:#6b7280;">Tidak ada data</td></tr>
<?php else: ?>
<?php foreach ($data as $i => $row): ?>
<tr>
<td><?= $offset + $i + 1 ?></td>
<td><?= htmlspecialchars($row['nim']) ?></td>
<td><?= htmlspecialchars($row['nama']) ?></td>
<td>
<?php
$badge_class = match(true) {
str_contains($row['jurusan'], 'Informatika') => 'badge-ti',
str_contains($row['jurusan'], 'Informasi') => 'badge-si',
default => 'badge-tk'
};
?>
<span class="badge <?= $badge_class ?>"><?= htmlspecialchars($row['jurusan']) ?></span>
</td>
<td><?= $row['angkatan'] ?></td>
<td><?= $row['ipk'] ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
<!-- Pagination Links -->
<?php if ($total_halaman > 1): ?>
<div class="pagination">
<!-- Tombol Previous -->
<?php if ($halaman_sekarang > 1): ?>
<a href="?page=<?= $halaman_sekarang - 1 ?>">« Prev</a>
<?php else: ?>
<span class="disabled">« Prev</span>
<?php endif; ?>
<!-- Nomor Halaman -->
<?php
$start = max(1, $halaman_sekarang - 2);
$end = min($total_halaman, $halaman_sekarang + 2);
if ($start > 1): ?>
<a href="?page=1">1</a>
<?php if ($start > 2): ?><span>...</span><?php endif; ?>
<?php endif;
for ($i = $start; $i <= $end; $i++): ?>
<?php if ($i === $halaman_sekarang): ?>
<span class="active"><?= $i ?></span>
<?php else: ?>
<a href="?page=<?= $i ?>"><?= $i ?></a>
<?php endif; ?>
<?php endfor;
if ($end < $total_halaman): ?>
<?php if ($end < $total_halaman - 1): ?><span>...</span><?php endif; ?>
<a href="?page=<?= $total_halaman ?>"><?= $total_halaman ?></a>
<?php endif; ?>
<!-- Tombol Next -->
<?php if ($halaman_sekarang < $total_halaman): ?>
<a href="?page=<?= $halaman_sekarang + 1 ?>">Next »</a>
<?php else: ?>
<span class="disabled">Next »</span>
<?php endif; ?>
</div>
<p class="page-info">Halaman <?= $halaman_sekarang ?> dari <?= $total_halaman ?></p>
<?php endif; ?>
</div>
</body>
</html>
Penjelasan logika pagination:
$per_page = 10— menampilkan 10 data per halaman$halaman_sekarang— halaman yang sedang aktif, diambil dari URL?page=X$offset— posisi data pertama yang diambil (halaman 1 = offset 0, halaman 2 = offset 10)LIMIT ? OFFSET ?— query MySQL untuk mengambil data sesuai halamanceil($total_data / $per_page)— menghitung total halaman dengan pembulatan ke atas- Ellipsis (
...) — ditampilkan jika ada banyak halaman, supaya tidak terlalu panjang
Metode 2: Pagination dengan Search dan Filter
<?php
require_once 'config/database.php';
// Konfigurasi
$per_page = 10;
$halaman_sekarang = max(1, (int)($_GET['page'] ?? 1));
$offset = ($halaman_sekarang - 1) * $per_page;
// Parameter pencarian
$search = trim($_GET['search'] ?? '');
$jurusan = $_GET['jurusan'] ?? '';
// Build WHERE clause
$where = [];
$params = [];
if ($search) {
$where[] = '(nama LIKE ? OR nim LIKE ?)';
$params[] = "%$search%";
$params[] = "%$search%";
}
if ($jurusan) {
$where[] = 'jurusan = ?';
$params[] = $jurusan;
}
$where_clause = !empty($where) ? 'WHERE ' . implode(' AND ', $where) : '';
// Hitung total
$stmt_count = $pdo->prepare("SELECT COUNT(*) FROM mahasiswa $where_clause");
$stmt_count->execute($params);
$total_data = $stmt_count->fetchColumn();
$total_halaman = ceil($total_data / $per_page);
// Ambil data
$query = "SELECT * FROM mahasiswa $where_clause ORDER BY id DESC LIMIT ? OFFSET ?";
$stmt = $pdo->prepare($query);
$all_params = array_merge($params, [$per_page, $offset]);
foreach ($all_params as $i => $val) {
$type = is_int($val) ? PDO::PARAM_INT : PDO::PARAM_STR;
$stmt->bindValue($i + 1, $val, $type);
}
$stmt->execute();
$data = $stmt->fetchAll();
// Query string untuk pagination link
$query_string = http_build_query(array_filter([
'search' => $search,
'jurusan' => $jurusan
]));
?>
Dengan cara ini, parameter search dan filter tetap ada saat user pindah halaman.
Metode 3: Pagination dengan AJAX
Untuk pagination tanpa reload halaman, gunakan AJAX:
// File: script.js
function loadHalaman(page) {
fetch('data.php?page=' + page)
.then(response => response.json())
.then(data => {
// Update tabel
let html = '';
data.data.forEach((row, i) => {
html += `<tr>
<td>${data.offset + i + 1}</td>
<td>${row.nim}</td>
<td>${row.nama}</td>
<td>${row.jurusan}</td>
<td>${row.ipk}</td>
</tr>`;
});
document.querySelector('tbody').innerHTML = html;
// Update pagination
updatePagination(data.total_halaman, page);
});
}
// Load halaman pertama saat halaman dimuat
document.addEventListener('DOMContentLoaded', () => loadHalaman(1));
Tips Pagination
1. Batasi nomor halaman yang ditampilkan Jangan tampilkan semua nomor jika halamannya banyak. Tampilkan maksimal 5-7 nomor di sekitar halaman aktif.
2. Gunakan URL yang SEO-friendly
// Biasa
?page=3&search=ahmad
// SEO-friendly (dengan .htaccess)
/mahasiswa/page/3?search=ahmad
3. Tambahkan rel=“prev” dan rel=“next”
Untuk SEO, tambahkan tag di <head>:
<?php if ($halaman_sekarang > 1): ?>
<link rel="prev" href="?page=<?= $halaman_sekarang - 1 ?>">
<?php endif; ?>
<?php if ($halaman_sekarang < $total_halaman): ?>
<link rel="next" href="?page=<?= $halaman_sekarang + 1 ?>">
<?php endif; ?>
4. Cache hasil query Untuk data yang jarang berubah, cache hasil query COUNT untuk menghindari query berulang.
5. Gunakan cursor-based pagination untuk data sangat besar
Untuk tabel dengan jutaan baris, OFFSET menjadi lambat. Gunakan cursor-based pagination:
-- Daripada OFFSET (lambat untuk data besar)
SELECT * FROM mahasiswa WHERE id > ? ORDER BY id LIMIT 10
-- Lebih cepat karena menggunakan index
Praktik Terbaik
Beberapa tips saat menulis kode PHP:
- Gunakan prepared statement — Hindari SQL injection dengan menggunakan PDO atau MySQLi prepared statement, jangan concatenate query secara langsung.
- Validasi input — Selalu validasi dan sanitasi data dari user menggunakan
filter_var(),htmlspecialchars(), atau library validasi. - Error reporting — Saat development, aktifkan
error_reporting(E_ALL)dandisplay_errorsuntuk memudahkan debugging. - Gunakan autoloading — Manfaatkan Composer autoload atau PSR-4 untuk mengelola file class secara otomatis.
- Pisahkan logic dan view — Gunakan pola MVC atau minimal pisahkan kode PHP dan HTML agar lebih rapi dan mudah dipelihara.
Dengan menerapkan praktik di atas, kode PHP Anda akan lebih aman, bersih, dan mudah dikembangkan.
- Cara Menggunakan Function Explode dan Implode di PHP
- Fungsi array_count_values() pada PHP
- Tipe Data PHP: Panduan Lengkap dan Penggunaannya
Kesimpulan
Cara membuat paging halaman dengan PHP:
- Hitung total data dengan
COUNT(*) - Hitung total halaman dengan
ceil(total / per_page) - Ambil data per halaman dengan
LIMITdanOFFSET - Tampilkan link navigasi dengan nomor halaman, prev, dan next
- Pertahankan parameter search/filter di link pagination
Pagination sederhana dengan LIMIT OFFSET sudah cukup untuk sebagian besar kasus. Untuk data yang sangat besar, pertimbangkan cursor-based pagination atau AJAX pagination.

