Когда на вашем сайте скапливаются сотни товаров, статей или пользовательских отзывов, возникает вопрос: как удобно отобразить всё это богатство, не перегружая страницу? Ответ — пагинация. Это не просто технический приём, а важный элемент UX, который мы сегодня разберём от А до Я, реализовав на чистом PHP.
Что такое пагинация и зачем она нужна?
Пагинация (разбивка на страницы) — это способ представления большого массива данных частями. Представьте библиотеку, где все книги свалены в одну кучу. Пагинация — это аккуратные полки с номерами. Основные преимущества:
- Скорость загрузки: Загружается 10-50 записей вместо 10 000.
- Удобство навигации: Пользователь не теряется в бесконечной ленте.
- SEO-дружественность: Каждая страница получает уникальный URL.
Ключевые компоненты пагинации
Любая система пагинации строится на трёх китах:
- LIMIT и OFFSET в SQL-запросе — выбираем только нужную порцию данных.
- Расчёт общего количества страниц — делим общее число записей на лимит.
- Генерация ссылок — создаём навигационные кнопки.
Важно! Всегда используйте подготовленные выражения (prepared statements) при подстановке значений в SQL-запрос для защиты от SQL-инъекций. Особенно это касается параметров, приходящих из URL.
Пошаговая реализация на PHP
Шаг 1: Получаем параметры из URL
Текущую страницу обычно передают через GET-параметр, например, ?page=2. Нужно обработать этот параметр безопасно.
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
if ($page < 1) $page = 1;
Шаг 2: Определяем лимит и смещение
Решите, сколько записей будет на одной странице. Стандартные значения — 10, 20, 50.
$limit = 10;
$offset = ($page - 1) * $limit;
Шаг 3: Выполняем два SQL-запроса
Первый запрос — для получения общего количества записей. Второй — для выборки данных для текущей страницы.
// Подключение к БД (пример с PDO)
$stmt = $pdo->query('SELECT COUNT(*) as total FROM articles');
$totalItems = $stmt->fetchColumn();
// Основной запрос с пагинацией
$sql = 'SELECT * FROM articles ORDER BY created_at DESC LIMIT :limit OFFSET :offset';
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$articles = $stmt->fetchAll();
Шаг 4: Рассчитываем общее количество страниц
$totalPages = ceil($totalItems / $limit);
Шаг 5: Генерируем навигационные ссылки
Создаём блок с кнопками «Назад», номерами страниц и «Вперёд». Важно не выводить ссылку на текущую страницу активной.
echo '';
Для больших наборов данных (миллионы записей) используйте ключевой метод пагинации (keyset pagination) вместо LIMIT/OFFSET. Он работает быстрее, так как не пересчитывает все предыдущие строки.
Продвинутые техники
Динамический лимит
Позвольте пользователю выбирать количество элементов на странице через выпадающий список.
AJAX-пагинация
Загружайте новые страницы без перезагрузки, используя JavaScript (Fetch API). Это улучшает плавность интерфейса.
SEO-оптимизация
Для поисковых систем используйте атрибуты rel=\"prev\" и rel=\"next\" в тегах <link> внутри <head> для указания связи между страницами.
FAQ: Часто задаваемые вопросы
Как обработать несуществующий номер страницы?
После расчёта $totalPages добавьте проверку: if ($page > $totalPages && $totalPages > 0) { header('Location: ?page=' . $totalPages); exit; }. Либо показывайте пользователю сообщение «Страница не найдена».
Пагинация замедляет сайт?
Нет, она его ускоряет! Медленным может быть только запрос COUNT(*) на огромных таблицах. В таких случаях рассмотрите приблизительный подсчёт или кеширование результата.
Можно ли сделать пагинацию без перезагрузки страницы?
Да, это называется AJAX-пагинация. Логика на PHP остаётся той же, но данные запрашиваются и вставляются на страницу с помощью JavaScript.
Как стилизовать пагинацию под дизайн сайта?
Используйте CSS-классы для элементов <ul> и <li>. Популярные фреймворки, такие как Bootstrap, имеют готовые стили для класса .pagination.
Что лучше: пагинация или «Загрузить ещё»?
Пагинация предсказуема и хороша для контента, где важна навигация (каталоги, статьи). Кнопка «Загрузить ещё» (бесконечный скролл) лучше подходит для лент новостей, где цель — непрерывное потребление контента.