Snippet prevnextPage



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

Собственно для этого мною и был написан сниппет prevnextPage

Он делает простую вещь, устанавливает плейсхолдеры [+pnp_prev+] и [+pnp_next+]. Шаблон плейсхолдера можно задать как в коде так и в чанке. Можно установить префикс для плейсхолдеров, для множественного вызова на странице.

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

В общем не вижу преград для его использования =)

<?php
/**
 * @name prevnextPage
 * @author Gorbarov Iliya at gorbarov.ru
 * @version 1.1
 * @desc Создает ссылки на предыдущую и следующую страницы
 *
 * Сниппет устанавливает плейсхолдеры [+pnp_prev+] [+pnp_next+]
 *
 * В плейсхолдерах находятся ссылки на предыдущую и следующую страницы, в зависимости от настроек сниппета
 * Плейсхолдеры устанавливаются только для документов в папке c &folderId
 *
 * &folderId - id папки
 * &sortBy - поле в базе данных для сортировки, например pub_date
 * &sortDir - Порядок сортировки ASC или DESC
 * &showHidden - Показывать скрытые пункты в меню, по умолчанию - 0
 * &letsCycle - Зациклить ссылки, по умолчанию - нет.
 * &prevTpl - Чанк для предыдущей ссылки
 * &nextTpl - Чанк для следующей ссылки
 * &id - Префикс плейсхолдеров для мультивызовов. По умолчанию 'pnp_'
 * &nextClass - CSS класс
 * &prevClass - CSS класс
 * &directOutput - Выводить результат напрямую, по умолчанию - использовать плейсхолдеры
 * &directOutputTpl - Шаблоны прямого вывода, строка, по умолчанию, [+prev+] | [+next+]
 *
 * Пример самого "обычного вызова": [[prevnextPage? &directOutput=`1`]]
 *
 */

if (!isset($folderId)) $folderId = 'parent';
if (!isset($sortBy)) $sortBy = 'menuindex';
if (!isset($sortDir)) $sortDir = 'ASC';
if (!isset($showHidden)) $showHidden = 0;
if (!isset($letsCycle)) $letsCycle = 0;
if (!isset($nextTpl) || !isset($prevTpl)) $useBuildInTpl = true;
if (!isset($nextClass)) $nextClass = '';
if (!isset($prevClass)) $prevClass = '';
if (!isset($directOutput)) $directOutput = 0;
if (!isset($directOutputTpl)) $directOutputTpl = '[+prev+] | [+next+]';
if (!isset($prevTpl)) $prevTpl = '<a href="[~[+id+]~]" class="'.$prevClass.'" title="[+pagetitle+]">[+pagetitle+]</a>';
if (!isset($nextTpl)) $nextTpl = '<a href="[~[+id+]~]" class="'.$nextClass.'" title="[+pagetitle+]">[+pagetitle+]</a>';
if (!isset($id)) $id = 'pnp_';

if (!function_exists('parseString')) {
    function parseString($tpl,$data,$prefix = '[+',$suffix = '+]') {
        foreach($data as $k => $v) {
            $tpl = str_replace($prefix.(string)$k.$suffix, (string)$v, $tpl);
        }
        return $tpl;
    };
}

$curId = $modx->documentIdentifier;
if ($folderId == 'parent') $folderId = array_pop($modx->getParentIds($curId,1));

$docs = $modx->getDocumentChildren ($folderId, 1, 0, 'id, pagetitle, parent', 'hidemenu = '.$showHidden, $sortBy, $sortDir, '');

foreach ($docs as $key=>$doc) {
    if ($doc['id'] == $curId) $curKey = $key;
}

$curDoc = $docs[$curKey];
$next = $docs[$curKey + 1];
$prev = $docs[$curKey - 1];

if (!isset($next) && $letsCycle) {
    $next = $docs[0];
}

if (!isset($prev) && $letsCycle) {
    $prev = $docs[count($docs) - 1];
}

if ($useBuildInTpl) {
    $rNext = parseString($nextTpl,array('id'=>$next['id'],'pagetitle'=>$next['pagetitle']));
    $rPrev = parseString($prevTpl,array('id'=>$prev['id'],'pagetitle'=>$prev['pagetitle']));
} else {
    $rNext = $modx->parseChunk($nextTpl,array('id'=>$next['id'],'pagetitle'=>$next['pagetitle']),'[+','+]');
    $rPrev = $modx->parseChunk($prevTpl,array('id'=>$prev['id'],'pagetitle'=>$prev['pagetitle']),'[+','+]');
}

if ($curDoc['parent'] == $folderId) {
    if ($directOutput) {
        echo parseString($directOutputTpl,array('next' => $rNext, 'prev' => $rPrev));
    } else {
        if (isset($next)) $modx->setPlaceholder($id.'next',$rNext);
        if (isset($prev)) $modx->setPlaceholder($id.'prev',$rPrev);
    }
}
?>


Как использовать?

А очень просто, достаточно вызвать сниппет в коде страницы и в нужном месте вставить плейсхолдеры [+pnp_prev+] и [+pnpNext+].

Или указать параметр &directOutput и тогда сниппет вернет результат выполнения и не будет устанавливать плейсхолдеры.

Также важно задать для сниппета порядок и поле по которому будет производится сортировка документов.

Пример:

[[prevnextPage?directOutput=`1`]]


Кажется все, пользуйтесь! =)

UPD: Теперь версия 1.1:
— Учитывать или не учитывать скрытые в меню пункты
— Теперь можно «зацикливать» ссылки
— Использовать или не использовать плейсхолдеры
— Ну и упростил код, чтобы его было удобней модифицировать под свои нужды

47 комментариев

avatar
Спасибо, Илья! :)
avatar
почему бы по-умолчанию не делать folderId равной [*parent*]?
ведь это наверное 99% случаев применения?
avatar
а ведь и правда! =)
avatar
и еще было бы удобно, если б можно было класс ссылке задавать параметром, например &class=`sidenav` и он подставлялся бы в тег
<a class="sidenav">...</a>


а сниппет нужный :)
avatar
Ну для этого шаблоны prevTpl-nextTpl и сделаны в принципе-то =)
avatar
это лишний чанк создавать. гораздо быстрее вписывается класс :)
avatar
Тогда сниппет подправить проще, не? =)

Вон Breadcrumbs вообще шаблон в сниппете и без вариантов =)

Кстати, обновил код, чтобы по умолчанию был parent.
avatar
Сейчас прикрутил на готовый сайт и первым делом пришлось прописать css класс!

Посему, добавились два параметра ;)
avatar
avatar
Спасибо, но когда искал я не нашел решения, поэтому сделал.

К тому же изобретение велосипедов развивает скилл разработчика =)
avatar
Это да. Выбор тоже хорошо :)
avatar
выбор безусловно это хорошо, но субъективно какое лучше решение?
pitbull +1 безусловно… при любом раскладе :)
avatar
Не знаю =)

Я свое использовал, мне было достаточно ;)
avatar
Случайно нашел еще одно изделие на эту тему: habrahabr.ru/blogs/modx/71722/
avatar
Это дело конечно хорошее, и впринцепе все эти переключалки страниц похожи одна на одну. Но вот у меня возникла другая задача, чтобы страницы выбирались из одной папки, но переключать можно было по-тематике (tv-параметру), что-то вроде filter в функции ditto. К сожалению колдуя над ditto 100% решения так и не нашел. :(
avatar
В тексте «Как использовать?» и примере опечатка [+pnpNext+] --> [+pnp_next+]

Поставил, все работает.
Спасибо за сниппет.
avatar
Спасибо, исправил, наслаждайтесь ;)
комментарий был удален
avatar
Хороший сниппет, но неплохо было бы добавить параметр «не показывать документы не показываемы в меню», удобно если хочешь что-бы не перескакивало на некоторые доки из папки.

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

P.S. Вначале поставил его, но пришлось отказаться к сожалению из-за того что показывает скрытые для других доки, которые не видны в меню. Но автору респект, просто и со вкусом…
  • SDee
  • 0
avatar
Вот действительно такие бы возможности реализовать.
А может есть в каком-нить из подобных?
avatar
Сделать это несложно, вот только некогда, но если надо очень, то можно ;)
avatar
Жду с нетерпением :)
avatar
А версия для Revo будет?)
avatar
Ну как начну Revo использовать и потребуется такая возможность =)
avatar
Когда же уже будет новая версия, руки чешутся на сайт прикрутить сей девайс :)
  • SDee
  • 0
avatar
Пардноьте, но не раньше чем через неделю =)
avatar
Ну как там время не появилось? :)
avatar
Ну как, руки не дошли? :)
avatar
Дошли, спасибо за насточивость!
avatar
Теперь версия 1.1:
— Учитывать или не учитывать скрытые в меню пункты
— Теперь можно «зацикливать» ссылки
— Использовать или не использовать плейсхолдеры
— Ну и упростил код, чтобы его было удобней модифицировать под свои нужды
avatar
Шикарно! Спасибо, сегодня попробую поставить.
avatar
А я правильно понял, что если не указывать id, то он просто будет листать в текущей папке? А то у меня для 5 папок шаблон одинаковый, сниппет внутри папки каждой тогда будет листать или сразу все папки?
  • SDee
  • 0
avatar
По умолчанию внутри папки листает.
avatar
Спасибо за ответ
avatar
Просто не хотелось бы ради листалки делать пять шаблонов :( и в каждом указывать ид папки.
  • SDee
  • 0
avatar
Теперь бы ещё у кого-нибудь руки дошли до реализации этого вопроса :) community.modx-cms.ru/blog/questions/1145.html вещь для сео весьма полезная!
  • SDee
  • 0
avatar
Отличный сниппет, часто использую его, еще раз спасибо автору!
Возникла необходимость прицепить тв-параметр документа к ссылкам вперед-назад, как это можно реализовать? Просто есть необходимость подцеплять к конопочкам маленькие превьюшки в статьях.

Спасибо!
avatar
Большое спасибо!

Особенно порадовала гибкость настроек
avatar
Так и не ответили по поводу «тв-параметр документа к ссылкам вперед-назад» (
avatar
В отчете просмотр событий пишется ошибка на снипете
«Only variables should be passed by reference»
В чем может быть дело, что не так?
Evo 1.0.5
  • w3d
  • 0
avatar
Тот же вопрос, снипет работает ошибка «Only variables should be passed by reference»
avatar
Тот же вопрос, снипет работает ошибка «Only variables should be passed by reference»

$curId = $modx->documentIdentifier;
if ($folderId == 'parent') $folderId = array_pop($modx->getParentIds($curId,1));

заменить на

$curId = $modx->documentIdentifier;
$Arr=$modx->getParentIds($curId,1);
if ($folderId == 'parent') $folderId = array_pop($Arr);
avatar
Подскажите, как указать глубину просмотра документов?
Чтобы после указания &folderId сниппет прошёлся по всем документам каталога.
avatar
спасибо. помогло
avatar
Нашел глюк.
если в подразделе имеется только одна статья и лестать вперед назад некуда больше. То ссылка принимает такой вид [~~], а по идее вообще не должна появляться.
avatar
спасибо. отличный сниппет
avatar
А как добавить поддержку вывода данных из TV?
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.