pdoPage
Сниппет pdoPage позволяет вывести результаты работы других сниппетов с разбивкой на страницы.
Оглавление
pdoPage — сниппет позволяет вывести результаты работы других сниппетов с разбивкой на страницы.
Есть несколько серьезных отличий от сниппета getPage:
- 2 вида пагинации: с пропуском страниц и классическая (зависит от параметра &pageLimit).
- Пагинация не плавает. Если указано показывать 5 ссылок на страницы — всегда будет 5 и не больше.
- Можно указать чанки для вывода при отсутствии ссылок на первую, последнюю, следующую или предыдущую страницу.
- Параметр &maxLimit не позволяет пользователю затормозить ваш сайт большой выборкой.
- Редирект на первую страницу при отсутствии результатов или некорректном параметре &page.
- Работает со сниппетом pdoResources, по умолчанию.
- Поддержка работы через ajax.
Параметры
Параметры сниппета pdoPage.
Параметры организации пагинации
При вызове сниппета pdoPage указываются параметры сниппета, для которого производится пагинация. Данный сниппет должен понимать параметры &page и &limit. По умолчанию pdoPage принимает все параметры pdoTools и кроме того, некоторые свои:
Название | По умолчанию | Описание |
&plPrefix | Префикс для выставляемых плейсхолдеров. | |
&limit | 10 | Ограничение количества результатов на странице. Число должно быть больше 0, иначе вам не нужен этот сниппет. |
&maxLimit | 100 | Максимально возможный лимит выборки. Перекрывает лимит, указанный пользователем через url. |
&offset | 0 | Пропуск результатов от начала. |
&page | 1 | Номер страницы для вывода. Перекрывается номером, указанным пользователем через url. |
&pageVarKey | page | Имя переменной для поиска номера страницы в url. |
&totalVar | page.total | Имя плейсхолдера для сохранения общего количества результатов. |
&pageLimit | 5 | Количество ссылок на страницы. Если больше или равно 7 — включается продвинутый режим отображения. |
&element | pdoResources | Имя сниппета для запуска. |
&pageNavVar | page.nav | Имя плейсхолдера для вывода пагинации. |
&pageCountVar | pageCount | Имя плейсхолдера для вывода количества страниц. |
&pageLinkScheme | Шаблон генерации ссылок на страницы. Позволяет реализовать ЧПУ пагинацию. См. ниже. | |
&cache | 0 | Кэширование результатов работы сниппета. |
&cacheTime | 3600 | Время актуальности кэша, в секундах. |
&cache_user | ||
&toPlaceholder | Если не пусто, сниппет сохранит все данные в плейсхолдер с этим именем, вместо вывода не экран. | |
&ajax | Включить поддержку ajax запросов. | |
&ajaxMode | ||
&ajaxElemWrapper | #pdopage | jQuery селектор элемента-обёртки с результатами и пагинацией. |
&ajaxElemRows | #pdopage.rows | jQuery селектор элемента с результатами. |
&ajaxElemPagination | #pdopage.pagination | jQuery селектор элемента с пагинацией. |
&ajaxElemLink | #pdopage.pagination a | jQuery селектор ссылки на страницу. |
&ajaxElemMore | #pdopage.btn-more | jQuery селектор кнопки загрузки результатов при ajaxMode = button. |
&ajaxHistory | Сохранять номер страницы в url при работе в режиме ajax. | |
&frontend_js | [[+assetsUrl]]js/pdopage.min.js | Ссылка на javascript для подключения сниппетом. |
&frontend_css | [[+assetsUrl]]css/pdopage.min.css | Ссылка на css стили оформления для подключения сниппетом. |
&setMeta | 1 | Регистрация мета-тегов со ссылками на предыдущую и следующую страницу. |
&strictMode | 1 | Строгий режим работы. pdoPage делает редиректы при загрузке несуществующих страниц. |
Параметры шаблонов
Название | По умолчанию | Описание |
&tplPage | @INLINE <li><a href="[[+href]]">[[+pageNo]]</a></li> |
Чанк оформления обычной ссылки на страницу. |
&tplPageWrapper | @INLINE <div class="pagination"><ul class="pagination">[[+first]][[+prev]][[+pages]][[+next]][[+last]]</ul></div> |
Чанк оформления всего блока пагинации, содержит плейсхолдеры страниц. |
&tplPageActive | @INLINE <li class="active"><a href="[[+href]]">[[+pageNo]]</a></li> |
Чанк оформления ссылки на текущую страницу. |
&tplPageFirst | @INLINE <li class="control"><a href="[[+href]]">[[%pdopage_first]]</a></li> |
Чанк оформления ссылки на первую страницу. |
&tplPageLast | @INLINE <li class="control"><a href="[[+href]]">[[%pdopage_last]]</a></li> |
Чанк оформления ссылки на последнюю страницу. |
&tplPagePrev | @INLINE <li class="control"><a href="[[+href]]">«</a></li> |
Чанк оформления ссылки на предыдущую страницу. |
&tplPageNext | @INLINE <li class="control"><a href="[[+href]]">»</a></li> |
Чанк оформления ссылки на следующую страницу. |
&tplPageSkip | @INLINE <li class="disabled"><span>...</span></li> |
Чанк оформления пропущенных страниц при продвинутом режиме отображения (&pageLimit >= 7). |
&tplPageFirstEmpty | @INLINE <li class="control"><span>[[%pdopage_first]]</span></li> |
Чанк, выводящийся при отсутствии ссылки на первую страницу. |
&tplPageLastEmpty | @INLINE <li class="control"><span>[[%pdopage_last]]</span></li> |
Чанк, выводящийся при отсутствии ссылки на последнюю страницу. |
&tplPagePrevEmpty | @INLINE <li class="disabled"><span>«</span></li> |
Чанк, выводящийся при отсутствии ссылки на предыдущую страницу. |
&tplPageNextEmpty | @INLINE <li class="disabled"><span>»</span></li> |
Чанк, выводящийся при отсутствии ссылки на следующую страницу. |
&ajaxTplMore | @INLINE <button class="btn btn-default btn-more">[[%pdopage_more]]</button> |
Шаблон кнопки для загрузки новых результатов при ajaxMode = button |
Поддержка Ajax
pdoPage может выдавать JSON и прерывать работу движка при соответствии запроса трём характеристикам:
- У сниппета включен параметр &ajax.
- Запрос сделан при помощи XMLHttpRequest, то есть — ajax.
- В запросе содержится переменная, указанная у сниппета в &pageVarKey. По умолчанию, это page.
То есть, вам достаточно просто указать сниппету &ajax=`1` и отправить странице GET запрос типа:
$.get('document.html?page=5', function(response) {
console.log(response);
}, 'json');
И в ответ вы получите JSON c результатами работы, пагинацией и служебными данными: номер страницы, сколько всего страниц и сколько всего результатов. Учитывая, что pdoPage — это сниппет-обёртка, таким образом вы можете заставить работать через ajax многие другие сниппеты.
Встроенная Ajax пагинация
Начиная с версии 1.10 pdoPage умеет загружать страницы через ajax. Вам нужно только обернуть его вызов в специальную разметку:
/* modParser */
<div id="pdopage">
<div class="rows">
[[!pdoPage?
&parents=`0`
&ajaxMode=`default`
]]
</div>
[[!+page.nav]]
</div>
/* pdoParser */
<div id="pdopage">
<div class="rows">
{$_modx->runSnippet('!pdoPage', [
'parents' => 0,
'ajaxMode' => 'default',
])}
</div>
{'page.nav' | placeholder}
</div>
Внутри [[+page.nav]]
у нас div с классом pagination — так в pdoPage по умолчанию.
Вы можете менять идентификаторы этой разметки следующими параметрами:
- ajaxElemWrapper — jQuery селектор элемента-обёртки с результатами и пагинацией. По умолчанию
#pdopage
. - ajaxElemRows — jQuery селектор элемента с результатами. По умолчанию
#pdopage .rows
. - ajaxElemPagination — jQuery селектор элемента с пагинацией. По умолчанию
#pdopage .pagination
. - ajaxElemLink — jQuery селектор ссылки на страницу. По умолчанию
#pdopage .pagination a
.
Два последних селектора рассчитывают на то, что вы не меняли стандартное оформление блока пагинации в параметре &tplPageWrapper. Работа обеспечивается подключением javascript файла из параметра &frontent_js.
Параметр &ajax=`1` указывать необязательно. Не пустой &ajaxMode активирует его самостоятельно.
Загрузка кнопкой
В отличии от стандартной пагинации, этот тип работы предполагает, что пользователь будет двигаться только вниз, загружая новые элементы, и поэтому сдвигает блок пагинации при прокрутке.
Так что, логично его размещать вверху:
/* modParser */
<div id="pdopage">
[[!+page.nav]]
<div class="rows">
[[!pdoPage?
&parents=`0`
&ajaxMode=`button`
&limit=`5`
]]
</div>
</div>
/* pdoParser */
<div id="pdopage">
{'page.nav' | placeholder}
<div class="rows">
{$_modx->runSnippet('!pdoPage', [
'parents' => 0,
'ajaxMode' => 'button',
'limit' => 5,
])}
</div>
</div>
Используются всё те же селекторы, плюс:
- ajaxElemMore — jQuery селектор кнопки загрузки результатов при ajaxMode = button. По умолчанию
#pdopage .btn-more
. - ajaxTplMore — Шаблон кнопки для загрузки новых результатов при ajaxMode = button. Должен включать селектор, указанный в &ajaxElemMore. По умолчанию
@INLINE <button class="btn btn-default btn-more">[[%pdopage_more]]</button>
.
При нажатии на кнопку загружаются &limit элементов и добавляются в конец блока результатов. Если больше загружать нечего — кнопка прячется. Плавающий блок навигации показывает текущую страницу и позволяет быстро перейти куда нужно. Здесь клик уже не обрабатывается через ajax, потому что и так выходит довольно сложно.
Если вывод плавающего блока в пагинацией не нужен, то просто сделайте ему display: none в вашем css.
Загрузка при прокрутке
Этот способ очень похож на предыдущий, только нет кнопки и её не нужно нажимать — всё делается автоматически при прокрутке страницы.
/* modParser */
<div id="pdopage">
[[!+page.nav]]
<div class="rows">
[[!pdoPage?
&parents=`0`
&ajaxMode=`scroll`
]]
</div>
</div>
/* pdoParser */
<div id="pdopage">
{'page.nav' | placeholder}
<div class="rows">
{$_modx->runSnippet('!pdoPage', [
'parents' => 0,
'ajaxMode' => 'scroll',
])}
</div>
</div>
History API
pdoPage поддерживает работу с History API вашего браузера. Это значит, что когда &ajaxMode включен, сниппет может сохранять номер страницы в адресной строке, чтобы при перезагрузке ничего не терялось. Также правильно работает навигация кнопками «вперёд\назад» браузера.
Вы можете изменить это поведение параметром &ajaxHistory, включив или выключив его. По умолчанию он работает следующим образом:
- Если ajaxMode установлен в default, то History API используется, номер страницы сохраняется.
- Если ajaxMode установлен в scroll или button, то History API не используется.
При отключении &ajaxHistory блок в постраничной навигацией скрывается, чтобы страницы нельзя было переключать вручную.
Функции обратного вызова
Вы можете указать функции, которые будут вызываться до и после загрузки страницы через ajax вот так:
pdoPage.callbacks['before'] = function(config) {
console.log('Конфиг перед загрузкой!', config);
};
pdoPage.callbacks['after'] = function(config, response) {
console.log('Конфиг после загрузки!', config);
console.log('Ответ от сервера!', response);
}
С версии 1.11.0-pl появилась возможность добавления обработчика на событие pdopage_load:
$(document).on('pdopage_load', function(e, config, response) {
console.log(e, config, response);
});
Проверка данных в config позволит вам различить разные вызовы pdoPage на одной странице.
Человекопонятная навигация
С версии 2.2.2 можно использовать параметр &pageLinkScheme для указания схемы генерации ссылок на страницу. В параметре может быть всего 2 плейсхолдера:
[[+pageVarKey]]
— переменная с именем страницы. По умолчанию page.[[+page]]
— номер страницы
Для примера укажите такой параметр:
/* modParser */
[[!pdoPage?
&parents=`0`
&pageLinkScheme=`/[[+pageVarKey]]-[[+page]]`
]]
[[!+page.nav]]
/* pdoParser */
{$_modx->runSnippet('!pdoPage', [
'parents' => 0,
'pageLinkScheme' => '/{$pageVarKey}-{$page}',
])}
{'page.nav' | placeholder}
Это приведёт к генерации ссылок, типа
/res/news/
/res/news/page-2
/res/news/page-3
При переходе по этим ссылкам (кроме первой) MODx будет выдавать ошибку 404, потому что страниц с этими адресами не существует. Так что, нам нужно написать плагин для их обработки:
<?php
// Реагируем только на событие OnPageNotFound
if ($modx->event->name == 'OnPageNotFound') {
// Определяем ключ запроса из настроек
$req = $modx->getOption('request_param_alias');
// Ловим нужный ключ страницы
$pageVarKey = 'page';
// Если в запросе повторяется наш шаблон "pageVarKey-page", то работаем дальше
if (preg_match("#.*?({$pageVarKey}-(\d+))#", $_REQUEST[$req], $matches)) {
// Отрезаем ЧПУ строку и получаем точный адрес текущей страницы
$uri = str_replace($matches[1], '', $matches[0]);
// Ищем страницу по этому адресу
$id = 0;
// Сначала как есть, со слешем на конце
if (!$id = $modx->findResource($uri)) {
// Если не находим - то пробуем отрезать слэш и ищем повторно
$id = $modx->findResource(rtrim($uri, '/'));
}
// Если ресурс найден
if ($id) {
// Добавляем номер страницы в глобальные массивы, чтобы pdoPage их там увидел
$_GET[$pageVarKey] = $_REQUEST[$pageVarKey] = $matches[2];
// И загружаем эту страницу
$modx->sendForward($id);
}
// Если ресурс не был найден - ничего не делаем, возможно запрос поймает другой плагин
}
}
Теперь этот плагин будет обрабатывать вашу ЧПУ навигацию.
Примеры
Так как pdoPage является частью pdoTools, в параметре &element у него сразу прописан сниппет pdoResources. Поэтому простой вызов сниппета выведет вам дочерние ресурсы:
/* modParser */
[[!pdoPage?
&tpl=`@INLINE <p>[[+idx]] <a href="/[[+uri]]">[[+pagetitle]]</a></p>`
]]
[[!+page.nav]]
/* pdoParser */
{$_modx->runSnippet('!pdoPage', [
'tpl' => '@INLINE <p>{$idx} <a href="/{$uri}">{$pagetitle}</a></p>',
])}
{'page.nav' | placeholder}
Выводим все возможные документы сайта:
/* modParser */
[[!pdoPage?
&tpl=`@INLINE <p>[[+idx]] <a href="/[[+uri]]">[[+pagetitle]]</a></p>`
&parents=`0`
]]
[[!+page.nav]]
/* pdoParser */
{$_modx->runSnippet('!pdoPage', [
'tpl' => '@INLINE <p>{$idx} <a href="/{$uri}">{$pagetitle}</a></p>',
'parents' => 0,
])}
{'page.nav' | placeholder}
Включаем навигацию с пропуском страниц. Обратите внимание, что если страниц выходит меньше 7, то будет работать обычная навигация.
/* modParser */
[[!pdoPage?
&tpl=`@INLINE <p>[[+idx]] <a href="/[[+uri]]">[[+pagetitle]]</a></p>`
&parents=`0`
&pageLimit=`7`
]]
[[!+page.nav]]
/* pdoParser */
{$_modx->runSnippet('!pdoPage', [
'tpl' => '@INLINE <p>{$idx} <a href="/{$uri}">{$pagetitle}</a></p>',
'parents' => 0,
'pageLimit' => 7,
])}
{'page.nav' | placeholder}
Активируем кэш на 30 минут:
/* modParser */
[[!pdoPage?
&tpl=`@INLINE <p>[[+idx]] <a href="/[[+uri]]">[[+pagetitle]]</a></p>`
&parents=`0`
&pageLimit=`7`
&cache=`1`
&cacheTime=`1800`
]]
[[!+page.nav]]
/* pdoParser */
{$_modx->runSnippet('!pdoPage', [
'tpl' => '@INLINE <p>{$idx} <a href="/{$uri}">{$pagetitle}</a></p>',
'parents' => 0,
'pageLimit' => 7,
'cache' => 1,
'cacheTime' => 1800,
])}
{'page.nav' | placeholder}
Указываем максимальный лимит выборки. Теперь, какой бы limit не указал пользователь в url — все равно будет не больше 10 результатов на странице.
Время запросов: 0,1339 s
Количество запросов: 24
Источник: cache