Как сделать пагинацию

Добавил пользователь Валентин П.
Обновлено: 05.10.2024

В статье рассмотрим, как добавляется и настраивается пагинация WordPress для удобного поиска информации посетителями.

Постраничная навигация: что это, зачем нужна

Нужна для того, чтобы группировать и сортировать большие объемы данных.

Бывает двух видов: алфавитная и числовая. Первая – для удобного представления словаря или раздела F.A.Q. Числовая помогает пользователю ориентироваться и находить нужный контент.

Навигация может поддерживать AJAX – технологию, которая подгружает посты без перезагрузки страницы.

Делаем алфавитную пагинацию

Вывести информацию по буквам алфавита просто: с помощью Alphabetic Pagination .

1. Перейдите Плагины -> Добавить новый, введите “Alphabetic Pagination” в форму поиска и нажмите клавишу [Enter].
2. Установите и активируйте.
3. Перейдите Настройки – Alphabetic Pagination.

Основные настройки

Implementation – автоматический или ручной вывод алфавита. Если выбрано первое, то разбивка встроится автоматически. Она будет показана под основным меню. Для ручного режима выведется шорткод.

Display on all lists? – выбор мест и разделов вывода алфавитной пагинации.

Hide/Show pagination if only one post available? – показать/скрыть разбивку, если на сайте один пост.

DOM Position? – место вывода. Оставьте по умолчанию.

Language selection? – язык. Выберите “русский”.

Styles – стиль алфавитного блока (горизонтальный, вертикальный, строчные или прописные буквы).

Disable Empty Alphabets? – показать/скрыть разбивку, если нет постов.

4. Установите нужные опции и нажмите кнопку Save Changes.

Если выбрана автоматическая вставка, то главная будет иметь вид:

Алфавитная пагинация на главной странице сайта

В другом случае – вывод набора шорткодов для вставки.

5. Добавьте шорткоды в файлы шаблонов.

Вывод числовой пагинации WordPress

Постраничная разбивка есть почти во всех темах WP. Одни используют стандартную, а другие – с технологией AJAX.

Но иногда нужно изменить или создать свой функционал навигации. Есть 2 способа: плагин, кастомная функция.

Плагин

Есть несколько хороших дополнений для решения задачи. Рассмотрим на примере бесплатного WP-PageNavi .

1. Установите и активируйте.
2. В админке перейдите в раздел Настройки -> WP-PageNavi.
3. Сделайте основные настройки (шаблон, количество и диапазон страниц для показа) и нажмите кнопку Сохранить изменения.
4. В шаблонах темы добавьте код:

Если нужно заменить/добавить постраничную навигацию для блога, используйте шаблоны index.php, archive.php, search.php.

Числовая пагинация wordpress с помощью WP-PageNavi

Кастомная функция

Если установка/работа плагина не устраивает, можно создать свою функцию.

Откройте файл functions.php активной темы и вставьте код:

Измените код под свои нужды (отмечено в комментариях).

Чтобы разбивка отображалась, пропишите PHP-строку в шаблон темы:

Отдельно о пагинации постов

В движке также можно разбить посты и страницы. Для этого откройте на редактирование запись, активируйте режим Текст и вставьте тег .

Пагинация wordpress поста

Для нового редактора Gutenberg есть блок Разрыв страницы.

Пагинация wordpress поста в Gutenberg

С точки зрения SEO, к подстраницам нужно добавлять атрибут каноникал. Тут приходит на помощь All in One SEO Pack . Просто перейдите All in One SEO -> Общие настройки и включите опцию Использовать nofollow для страниц/записей с пагинацией.

Настройка плагина All in One SEO Pack

Если не работает переход

Обычно в итоге выводится ошибка 404.

Ошибка 404

Это значит, что запрошенная страница сайта не существует. Способы решения:

  • перейдите в админке в раздел Настройки -> Постоянные ссылки и нажмите кнопку Сохранить изменения;
  • очистите кэш на сайте и в браузере;
  • проверьте корректность работы всех активных плагинов;
  • пересмотрите добавленный вручную код на предмет ошибок.

Нажмите, пожалуйста, на одну из кнопок, чтобы узнать понравилась статья или нет.

Зачастую в тестовых заданиях на джунов присутствует пункт о реализации пагинации в какой-нибудь системе. И мне довольно часто прилетают просьбы показать как это делается, так как зачастую это задание ставит в тупик начинающих разработчиков. Что-ж, давайте разбираться.

Теперь давайте добавим побольше статей в базу, чтобы было по чему пагинацию делать.

Посмотрим на имеющиеся у нас статьи. Отсортируем их в обратном порядке.

Все записи без пагинации

Теперь, если вы еще не в курсе, нужно познакомиться с двумя конструкциями языка SQL: LIMIT и OFFSET. Они позволяют получить только часть строк из тех, что были получены запросом. LIMIT задаёт лимит записей, OFFSET задает количество строк, которые нужно пропустить.

Например, мы хотим пропустить первые 5 строк, и вывести следующие 10 строк:

OFFSET и LIMIT

Как видим, у нас пропустились первые 5 строк с id: 22,21,20,19,18, которые присутствовали в результате запроса без LIMIT и OFFSET. Также мы видим, что строк у нас здесь 10.

Как нетрудно догадаться, для реализации пагинации нам можно воспользоваться этими конструкциями. Если мы хотим выводить на каждой странице нашего блога по 5 записей, то для получения записей на первой странице стоит использовать запрос:

Первые 5 записей

Для второй страницы запрос будет следующим:

Следующие 5 записей

То есть здесь мы пропустили первые 5 записей и вывели следующие 5.

Аналогично строим запрос для третьей страницы:

И так далее, пока записи не закончатся.

Получаем формулу для получения запроса, которые выводит записи на n-ой странице блога, где k-число записей на одной странице:

Чтобы понять, сколько у нас будет страниц, нам нужно число записей разделить на число записей, выводимых на одной странице. Полученное число округляем в большую сторону. К примеру, если у нас 22 записи, и на одной странице выводим 5, то число страниц будет 22/5 = 4,4. Округляем в большую сторону и получаем 5. На первых четырех страницах у нас будет по 5 записей, а на последней будет 2 записи.
Получить общее число записей можно с помощью запроса:

Число записей

Осталось всё это дело закодить. Начнём с самого простого – выведем ссылки на странички со статьями.
В классе ActiveRecordEntity добавляем метод для получения количества страниц. Метод будет принимать на вход количество записей на одной странице.

В MainController вызовем этот метод и передадим в шаблон число страниц.

Добавим в шаблоне внизу странички номера страниц.

Номера страничек

Обратите внимание: при формировании ссылки на страницу мы проверяем, является ли страничка первой, и если это так, то формируем ссылку на главную страницу, иначе формируем ссылку вида: /n, где n – номер страницы.
Посмотрим на результат:

Теперь давайте напишем метод для получения записей на n-ой страничке. Для этого в классе ActiveRecordEntity добавим метод getPage(), принимающий на вход количество записей на одной странице и номер страницы.

Добавим в MainController экшен для странички.

Переписываем экшен main.

Первая страница

Проверяем главную страницу:

Добавляем роут для страничек с номерами.

Всё. Пагинация готова. Можно переходить по страничкам. Так выглядит пятая страница.

Из улучшений можно сделать текущий номер страницы не ссылкой, а просто текстом. Для этого передадим номер текущей странички в шаблон.

В шаблоне будем сравнивать текущий номер страницы с тем, который в текущей итерации.

Вот такая простая пагинация у нас получилась. Она подойдет для большинства проектов без высокой нагрузки и с небольшим количеством записей. А для крупных проектов потребуется более специфичное решение, которое я рассмотрю в одном из ближайших уроков.

Разрабатывая любой проект часто приходиться сталкиваться с необходимостью создания постраничной навигации или как еще называют — пагинация. Будь-то список статей, пользователей или любые другие выборки с базы данных, где большое количество записей требуют лимитированного вывода. Такой вывод можно реализовать двумя способами:

1. Выгружать все данные и показывать пользователю только часть.
2. Выгружать только часть данных, которые непосредственно показывать.

Каждый из способов имеет свои плюсы и минусы, очевидно, если записей в базе очень много, то выгружая все, мы очень сильно нагружаем компьютер пользователя. Просто представьте, что при открытии страницы у вас подгружается 100.000 записей, с другой стороны, если выгрузка имеет только 100 элементов, то такой способ будет работать быстрее, так как не нужно постоянно обращаться к серверу.

В статье мы разберем второй способ, а именно выгрузку только тех данных, которые отдаются пользователю на текущей странице.

1. Функция pagePrint(), печатает ссылку на заданую страницу

2. Начальный конфиг

3. Пример выборки данных из базы

Для выборки используется LIMIT, где старт вычисляется по формуле (page-1)*limit, то есть для первой страницы start = 0.

4. Подсчет кол-ва страниц и проверка основных условий.

С подсчетом количества страниц иногда возникают проблемы, так как страниц может быть только целое число, а при делении (кол-во записей)/(лимит записей на странице) может получится дробное. Данный результат необходимо округлить в больную строну, потому что, обычное округление round(), выдаст ошибочный результат.

Пример, всего записей 31, на странице публикуем по 10, таким образом по формуле получается 3.1 страница, при округлении round(3.1) = 3, что неправильно, так как теряется одна запись. Поэтому используется функция ceil(), ceil(3.1) = 4.

5. Выводим на экран:

Вот и все, алгоритм разобран, ниже представлен код для вывода пагинации на Javascript:

В других фреймворках постраничная навигация может быть очень болезненной. Мы надеемся, что подход Laravel к разбиению на страницы станет глотком свежего воздуха. Пагинатор Laravel интегрирован с построителем запросов и Eloquent ORM и обеспечивает удобную, простую в использовании разбивку на страницы записей базы данных с нулевой конфигурацией.

По умолчанию HTML, генерируемый пагинатором, совместим с фреймворком Tailwind CSS; однако, также доступна поддержка разбивки на страницы с использованием Bootstrap.

Основы использования

Разбиение результатов построителя запросов

Простая пагинация

Метод paginate подсчитывает общее количество записей, соответствующих запросу, перед извлечением записей из базы данных. Это сделано для того, чтобы пагинатор знал, сколько всего страниц с записями необходимо сформировать. Однако, если вы не планируете отображать общее количество страниц в пользовательском интерфейсе вашего приложения, запрос количества записей не нужен.

Разбиение результатов Eloquent

Вы также можете разбивать запросы Eloquent на страницы. В этом примере мы разобьем модель App\Models\User на страницы и укажем, что мы планируем отображать 15 записей на странице. Как видите, синтаксис почти идентичен разбивке на страницы результатов построителя запросов:

Конечно, вы можете вызвать метод paginate после указания других ограничений для запроса, таких как выражения where :

Вы также можете использовать метод simplePaginate при разбиении на страницы моделей Eloquent:

Точно так же вы можете использовать метод cursorPaginate для курсорной пагинации моделей Eloquent:

Несколько экземпляров пагинации на странице

Иногда вам может потребоваться отобразить два отдельных модуля пагинации на одном экране, который отображается вашим приложением. Однако, если оба экземпляра пагинации используют параметр строки запроса page для хранения текущей страницы, они будут конфликтовать. Чтобы разрешить этот конфликт, вы можете передать имя параметра строки запроса, который вы хотите использовать для хранения текущей страницы, через третий аргумент, предоставленный методам paginate , simplePaginate и cursorPaginate :

Cursor-пагинация

В то время как paginate и simplePaginate создают запросы с использованием SQL-оператора "offset", Cursor-пагинация работает путем создания конструкции "where", которая сравнивает значения упорядоченных столбцов, содержащихся в запросе, обеспечивая наиболее эффективную производительность базы данных среди всех возможных, доступную среди всех методов пагинации Laravel. Этот метод пагинации особенно хорошо подходит для больших наборов данных и пользовательских интерфейсов с "бесконечной" прокруткой.

Вы можете создать экземпляр Cursor-пагинации с помощью метода cursorPaginate , предлагаемого построителем запросов. Этот метод возвращает экземпляр Illuminate\Pagination\CursorPaginator :

После того как вы получили экземпляр Cursor-пагинации, вы можете отобразить результаты постраничной навигации как обычно при использовании методов paginate и simplePaginate . Для получения дополнительной информации о методах экземпляра, предлагаемых средством Cursor-пагинации, обратитесь к документации по методам экземпляра Cursor Paginator.

"Cursor" против "Offset" пагинации

Чтобы проиллюстрировать различия между "Cursor" и "Offset" постраничной навигацией, давайте рассмотрим несколько примеров SQL-запросов. Оба следующих запроса будут отображать "вторую страницу" результатов для таблицы users , упорядоченных по id :

Cursor-пагинация предлагает следующие преимущества перед Offset-пагинацией:

  • Для больших наборов данных Cursor-пагинация обеспечивать лучшую производительность, если столбцы "order by" проиндексированы. Это связано с тем, что предложение "offset" сканирует все ранее сопоставленные данные.
  • Для наборов данных с частыми записями Offset-пагинация может пропускать записи или отображать дубликаты, если результаты были недавно добавлены или удалены со страницы, которую пользователь просматривает в данный момент.

Однако, Cursor-пагинация имеет следующие ограничения:

Самостоятельное создание пагинатора

По желанию можно вручную создать экземпляр пагинатора, передав ему массив элементов, которые у вас уже есть в памяти. Вы можете сделать это, создав экземпляр Illuminate\Pagination\Paginator , Illuminate\Pagination\LengthAwarePaginator или Illuminate\Pagination\CursorPaginator , в зависимости от ваших потребностей.

Классам Paginator и CursorPaginator не требуется знать общее количество элементов в результирующем наборе; однако, из-за этого у классов нет методов для получения индекса последней страницы. Класс LengthAwarePaginator принимает почти те же аргументы, что и Paginator ; однако, для этого требуется подсчет общего количества элементов в результирующем наборе.

Другими словами, Paginator соответствует методу simplePaginate построителя запросов, CursorPaginator соответствует методу cursorPaginate , а LengthAwarePaginator соответствует методу paginate .

Настройка URL-адресов постраничной навигации

Добавление значений в строку запроса

Вы можете добавить параметр в строку запроса навигационных ссылок с помощью метода appends . Например, чтобы добавить sort=votes к каждой ссылке пагинации, вы должны сделать следующий вызов appends :

Вы можете использовать метод withQueryString , если хотите добавить все значения строки текущего запроса к ссылкам постраничной навигации:

Добавление фрагментов хеша

Отображение результатов постраничной навигации

При вызове метода paginate вы получите экземпляр Illuminate\Pagination\LengthAwarePaginator , вызов метода simplePaginate возвращает экземпляр Illuminate\Pagination\Paginator . И, наконец, вызов метода cursorPaginate возвращает экземпляр Illuminate\Pagination\CursorPaginator .

Эти объекты содержат несколько методов, описывающих результирующий набор. В дополнение к этим вспомогательным методам, экземпляры пагинатора являются итераторами и могут быть перебраны как массив. Итак, как только вы получили результаты, вы можете отобразить результаты и отрисовать ссылки на страницы, используя Blade:

Метод links отрисует ссылки на остальные страницы в результирующем наборе. Каждая из этих ссылок уже будет содержать соответствующую строковую переменную запроса page . Помните, что HTML, сгенерированный методом links , совместим с фреймворком Tailwind CSS.

Регулирование количества отображаемых ссылок

Когда пагинатор отображает навигационные ссылки, включающие номер текущей страницы, а также ссылки для трех страниц до и после текущей. Используя метод onEachSide , вы можете контролировать, сколько дополнительных ссылок отображается с каждой стороны от текущей страницы в среднем скользящем окне ссылок, созданных пагинатором:

Преобразование результатов в JSON

Классы пагинатора Laravel реализуют контракт интерфейса Illuminate\Contracts\Support\Jsonable и содержат метод toJson , поэтому очень легко преобразовать результаты в JSON. Вы также можете преобразовать экземпляр пагинатора в JSON, вернув его из маршрута или действия контроллера:

JSON из пагинатора будет включать метаинформацию, такую как total , current_page , last_page и другие. Записи результатов доступны через ключ data в массиве JSON. Вот пример JSON, созданного путем возврата экземпляра пагинатора из маршрута:

Настройка вида пагинации

По умолчанию сгенерированные шаблоны для отображения навигационных ссылок, совместимы со структурой фреймворка Tailwind CSS. Однако, если вы не используете Tailwind, вы можете определять свои собственные шаблоны для отображения этих ссылок. При вызове метода links в экземпляре пагинатора вы можете передать имя шаблона в качестве первого аргумента метода:

Однако, самый простой способ отредактировать шаблоны постраничной навигации – это экспортировать их в каталог resources/views/vendor с помощью команды vendor:publish :

Эта команда поместит шаблоны в каталог resources/views/vendor/pagination вашего приложения. Файл tailwind.blade.php в этом каталоге соответствует шаблону постраничной навигации по умолчанию. Вы можете отредактировать этот файл для изменения HTML-кода навигации.

Если вы хотите назначить другой файл в качестве шаблона постраничной навигации по умолчанию, вы можете вызвать методы defaultView и defaultSimpleView пагинатора в методе boot вашего класса App\Providers\AppServiceProvider :

Использование Bootstrap

Laravel содержит шаблоны постраничной навигации, созданные с использованием Bootstrap CSS. Чтобы использовать эти шаблоны вместо шаблонов Tailwind по умолчанию, вы можете вызвать метод пагинатора useBootstrap в методе boot класса App\Providers\AppServiceProvider :

Методы экземпляра Paginator и LengthAwarePaginator

Каждый экземпляр пагинатора содержит дополнительную информацию о постраничной навигации с помощью следующих методов:

Метод Описание
$paginator->count() Получить количество элементов для текущей страницы.
$paginator->currentPage() Получить номер текущей страницы.
$paginator->firstItem() Получить номер первого элемента в результатах.
$paginator->getOptions() Получить параметры пагинатора.
$paginator->getUrlRange($start, $end) Создать диапазон URL-адресов для пагинации.
$paginator->hasPages() Определить, достаточно ли элементов для разделения на несколько страниц.
$paginator->hasMorePages() Определить, есть ли еще элементы в хранилище данных.
$paginator->items() Получить элементы для текущей страницы.
$paginator->lastItem() Получить номер последнего элемента в результатах.
$paginator->lastPage() Получить номер последней доступной страницы. (Недоступно при использовании simplePaginate ).
$paginator->nextPageUrl() Получить URL-адрес следующей страницы.
$paginator->onFirstPage() Определить, находится ли пагинатор на первой странице.
$paginator->perPage() Количество элементов, отображаемых на каждой странице.
$paginator->previousPageUrl() Получить URL-адрес предыдущей страницы.
$paginator->total() Определить общее количество элементов запроса в хранилище данных. (Недоступно при использовании simplePaginate ).
$paginator->url($page) Получить URL-адрес для конкретного номера страницы.
$paginator->getPageName() Получить переменную строки запроса, используемую для хранения страницы.
$paginator->setPageName($name) Установить переменную строки запроса, используемую для хранения страницы.

Методы экземпляра Cursor Paginator

Каждый экземпляр Cursor-пагинатора предоставляет дополнительную информацию о постраничной навигации с помощью следующих методов:

Читайте также: