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

В этом посте сделаем переход к предыдущей и следующей статье по ссылкам в детальном описании компонента bitrix:news.detail.
Данный код также будет работать и в компоненте bitrix:catalog.element.


Для наглядности, чтобы было понятно, что будем делать, выглядеть это будет вот так, как на моем сайте:
Переход к предыдущей и следующей статье по ссылкам в детальном описании статьи компонента bitrix:news.detail

Т.е. открыли статью, любую, если есть элементы до и после они будут выводиться слева или справа. Если статья последняя, значит выводиться будет слева предыдущая статья, и наоборот.
Также, для удобства сделаем возможность листать статьи по клавишам на клавиатуре ← Ctrl и  Ctrl →.

Все вычисления сделаем в файле result_modifier.php  в шаблоне компонента bitrix:news.detail, а html-код навигации и jQuery-код сделаем в самом шаблоне в файле template.php. В случае включенного управляемого кеширования все будет работать и кешироваться.


Итак, копируем шаблон компонента bitrix:news.detail если не скопирован, если скопирован и нет в нем файла result_modifier.php,то создаем этот файл.
У меня шаблон скопирован сюда, у Вас будет другой путь к шаблону.
Шаблон компонента bitrix:news.detail

PHP-код файла result_modifier.php

<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
/**
 * Bitrix vars
 *
 * @var CBitrixComponent $component
 * @var CBitrixComponentTemplate $this
 * @var array $arParams
 * @var array $arResult
 * @var array $arLangMessages
 * @var array $templateData
 *
 * @var string $templateFile
 * @var string $templateFolder
 * @var string $parentTemplateFolder
 * @var string $templateName
 * @var string $componentPath
 *
 * @var CDatabase $DB
 * @var CUser $USER
 * @var CMain $APPLICATION
 */

// Прямая сортировка, чтобы последний элемент был справа от текущего, при обратной будет наоборот, слева.
$arSort = array(
    'ACTIVE_FROM' => 'ASC',
    'ID' => 'ASC',
);

// минимальные поля ID, NAME, DETAIL_PAGE_URL
$arSelect = array(
    'ID',
    'NAME',
    'DETAIL_PAGE_URL',
    //'DATE_CREATE',
    //'DATE_ACTIVE_FROM',
    //'PREVIEW_PICTURE',
    //'DETAIL_PICTURE',
);

// выбираем активные элементы из нужного инфоблока по фильтру, вообще фильтр должен совпадать с фильтром компонента
// иначе могут в пагинацию попасть левые элементы инфоблока, которых не будет на сайте.
$arFilter = array(
    'IBLOCK_ID'             => $arParams['IBLOCK_ID'],
    //'SECTION_CODE'          => $arParams['SECTION_CODE'],
    //'SECTION_CODE'          => $arResult['SECTION']['CODE'],
    //'SECTION_ID'            => $arResult['IBLOCK_SECTION_ID'],
    'ACTIVE'                => 'Y',
    'ACTIVE_DATE'           => 'Y',
    'SECTION_ACTIVE'        => 'Y',
    'SECTION_GLOBAL_ACTIVE' => 'Y',
    'INCLUDE_SUBSECTIONS'   => 'Y',
    'CHECK_PERMISSIONS'     => 'Y',
    'MIN_PERMISSION'        => 'R',
);


// тут получим по 1 соседу с каждой стороны от текущего элемента
$arNavParams = array(
    'nPageSize'  => 1,
    'nElementID' => $arResult['ID'],
);
$arElements     = Array();
$rsElements   = CIBlockElement::GetList($arSort, $arFilter, FALSE, $arNavParams, $arSelect);
if($arParams['DETAIL_URL'])
    $rsElements->SetUrlTemplates($arParams['DETAIL_URL']);

while($obElement = $rsElements->GetNextElement()) {
    $arElements[] = $obElement->GetFields();
}

// в $arResult['RIGHT_PAGE'] и $arResult['LEFT_PAGE']  массивы с информацией о соседних элементах для текущего
switch(count($arElements))
{
    case '3': //Сработает, когда справа и слева есть элементы
    {
        $RIGHT_PAGE = array_pop($arElements); // Последний элемент справа
        $LEFT_PAGE = array_shift($arElements); // Первый элемент слева

        $arResult['RIGHT_PAGE'] = Array(
            'NAME' => $RIGHT_PAGE['NAME'],
            'URL'  => $RIGHT_PAGE['DETAIL_PAGE_URL']
        );
        $arResult['LEFT_PAGE']  = Array(
            'NAME' => $LEFT_PAGE['NAME'],
            'URL'  => $LEFT_PAGE['DETAIL_PAGE_URL']
        );
    }
    break;

    case '2': //Сработает либо на первом, либо на последнем элементе
    {
        $RIGHT_PAGE = array_pop($arElements); // Последний элемент справа
        $LEFT_PAGE = array_shift($arElements); // Первый элемент слева

        // тут проверяем, слева или справа будет текущий открытый элемент, его исключаем

        if($LEFT_PAGE["ID"] && $LEFT_PAGE["ID"] != $arResult["ID"])
        {
            $arResult['RIGHT_PAGE'] = Array();
            $arResult['LEFT_PAGE']  = Array(
                'NAME' => $LEFT_PAGE['NAME'],
                'URL'  => $LEFT_PAGE['DETAIL_PAGE_URL']
            );
        }
        elseif($RIGHT_PAGE && $RIGHT_PAGE != $arResult["ID"])
        {
            $arResult['LEFT_PAGE'] = Array();
            $arResult['RIGHT_PAGE']  = Array(
                'NAME' => $RIGHT_PAGE['NAME'],
                'URL'  => $RIGHT_PAGE['DETAIL_PAGE_URL']
            );
        }
        else
        {
            $arResult['RIGHT_PAGE'] = Array();
            $arResult['LEFT_PAGE']  = Array();
        }
    }
    break;

    default: //Если что-то пойдет не так, постраничка выводиться не будет
    {
        $arResult['RIGHT_PAGE'] = Array();
        $arResult['LEFT_PAGE']  = Array();
    }
}


Тут следует обратить особое внимание на сортировку элементов в самом начале в массиве:
$arSort = array(
    'ACTIVE_FROM' => 'ASC',
    'ID' => 'ASC',
);

У меня на сайте задана в статьях обратная сортировка "DESC", если мне взять сортировку из настроек компонента, то соседние элементы будут выбираться наоборот, т.е. в массиве $RIGHT_PAGE будет предыдущий элемент, а в массиве $LEFT_PAGE будет следующий элемент, что для меня не логично и может запутать при большом коде, наоборот получается выборка, я вручную задаю сортировку обратную той, что у компонента, т.е. прямую "ASC" и все работает логично, и правильно.


Также обратите внимание на фильтр $arFilter:

  1. Он должен совпадать с фильтром компонента, иначе могут в пагинацию попасть те элементы инфоблока, которых не будет  видно на сайте.
  2. На моем сайте переход по соседним статьям не зависит от раздела, сквозной, поэтому ключ SECTION_ID  закомментирован, если Вам нужно сделать переход по соседним элементам инфоблока  в зависимости от раздела, то надо раскомментировать эту строку/ключ, но учтите, что ID-раздела в разных компонентах может передаваться в шаблон по-разному, где через $arResult, где через $arParams, т.к. компонент может быть комплексным, может быть простым.

HTML-код в файле шаблона template.php

<div class="uk-grid uk-margin-large next-prev-pager">
    <div class="uk-width-medium-1-2 uk-text-left uk-text-bold">
    <?if(!empty($arResult["LEFT_PAGE"])):?>
        <a class="ts-prev-page" title="&larr; ctrl предыдущая" href="<?=$arResult["LEFT_PAGE"]["URL"]?>" data-uk-tooltip> <i class="uk-icon-caret-left"></i> <?=$arResult["LEFT_PAGE"]["NAME"]?></a>
    <?endif?>
    </div>
    <div class="uk-width-medium-1-2  uk-text-right  uk-text-bold">
    <?if(!empty($arResult["RIGHT_PAGE"])):?>
        <a class="ts-next-page" title="следующая ctrl &rarr;"  href="<?=$arResult["RIGHT_PAGE"]["URL"]?>" data-uk-tooltip><?=$arResult["RIGHT_PAGE"]["NAME"]?> <i class="uk-icon-caret-right"></i></a>
    <?endif?>
    </div>
</div>

Тут обращаю внимание, что верстка от css-фреймворка Uikit, у Вас как у меня выводиться не будет, нужно применить еще стили, можете скопировать их с моего сайта.

jQuery-код в файле шаблона template.php

<script type="text/javascript">
    $(document).keyup(function(event){
        event = event || window.event;
        var link = null;

        if (!event.ctrlKey)
            return;

        var key = (event.keyCode ? event.keyCode : (event.which ? event.which : null));

        if (!key)
            return;

        if (key == 39)
            link = $('.next-prev-pager .ts-next-page');
        else if (key == 37)
            link = $('.next-prev-pager .ts-prev-page');

        if (link && link.attr('href'))
            document.location = link.attr('href');
        else if(key == 39 || key == 37)
            alert('Дальше новостей пока нет, заходите попозже или подпишитесь на мои статьи в форме в самом низу!');

    });
</script>

jQuery-код добавьте в самом конце шаблона, самым последним.


Вот, собственно и весь код, навигация по соседним элементам инфоблока готова!

Скачать шаблон навигации из ссылок по соседним элементам: navigation-links-adjacent-elements-bitrix.rar
Имя *
Логин (мин. 3 символа)
E-mail *
*— обязательные для заполнения поля
Логин или e-mail
TUNING-SOFT.RU Разработка умных веб-сервисов