Битрикс. Меню из разделов инфоблока

01.08.2018

Теги: CMSWeb-разработкаБитриксИнфоблокКомпонентМенюНавигацияРазделИнфоблокаСтруктура

Пусть у нас на сайте уже есть меню, которое содержит пункты: Каталог, Доставка, Оплата, Контакты. Для показа меню используется компонент bitrix:menu, который в визуальном редакторе расположен по пути «Служебные • Навигация • Меню». А сами пункты меню сохраняются в файле .main.menu.php, в корне сервера. Нам нужно, чтобы вместо пункта «Каталог» выводились названия корневых разделов каталога: Обувь, Одежда, Сумки.

<?php
$aMenuLinks = array(
    array(
        "Каталог", 
        "/catalog/", 
        array(), 
        array(), 
        "" 
    ),
    array(
        "Доставка", 
        "/delivery/", 
        array(), 
        array(), 
        "" 
    ),
    array(
        "Оплата", 
        "/payment/", 
        array(),
        array(),
        "" 
    ),
    array(
        "Контакты", 
        "/contacts/", 
        array(), 
        array(), 
        "" 
    )
);

Для решения этой задачи существует компонент «Пункты меню», который дополняет уже созданное меню названиями разделов инфоблоков. В визуальном редакторе компонент расположен по пути: «Служебные • Навигация • Пункты меню». Вызов этого компонета происходит в файле .main.menu_ext.php.

Система Bitrix Framework позволяет создавать меню динамического типа. Т.е. массив данных таких меню генерируется автоматически на основании некоторых данных, получаемых с помощью программного кода. Данный код должен храниться в папке соответствующего раздела сайта в файле с именем .type.menu_ext.php. Основная задача подобных файлов — это манипуляция массивом $aMenuLinks.

Чтобы файл .main.menu_ext.php мог изменять массив $aMenuLinks, надо в настройках компонента «Меню» отметить checkbox «Подключать файлы с именами вида .тип.menu_ext.php»:

Теперь создадим такой файл и разместим в нем код:

<?php
/*
 * Файл .main.menu_ext.php в корне сервера
 */
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();

global $APPLICATION;
$aMenuLinksExt = array();

if (CModule::IncludeModule('iblock')) {
    $arFilter = array(
        "CODE" => "catalog",
        "SITE_ID" => SITE_ID,
    );

    $dbIBlock = CIBlock::GetList(array('SORT' => 'ASC', 'ID' => 'ASC'), $arFilter);
    $dbIBlock = new CIBlockResult($dbIBlock);

    if ($arIBlock = $dbIBlock->GetNext()) {
        // для сбоса кеша при изменении инфоблока
        if (defined("BX_COMP_MANAGED_CACHE")) {
            $GLOBALS["CACHE_MANAGER"]->RegisterTag("iblock_id_" . $arIBlock["ID"]);
        }

        if ($arIBlock["ACTIVE"] == "Y") {
            $aMenuLinksExt = $APPLICATION->IncludeComponent(
                "bitrix:menu.sections",
                "",
                array(
                    "IS_SEF" => "Y",
                    "SEF_BASE_URL" => "",
                    "SECTION_PAGE_URL" => $arIBlock['SECTION_PAGE_URL'],
                    "DETAIL_PAGE_URL" => $arIBlock['DETAIL_PAGE_URL'],
                    "IBLOCK_TYPE" => $arIBlock['IBLOCK_TYPE_ID'],
                    "IBLOCK_ID" => $arIBlock['ID'],
                    "DEPTH_LEVEL" => "1",
                    "CACHE_TYPE" => "N",
                ),
                false,
                array('HIDE_ICONS' => 'Y')
            );
        }
    }

    // для сброса кеша при добавлении нового инфоблока
    if (defined("BX_COMP_MANAGED_CACHE")) {
        $GLOBALS["CACHE_MANAGER"]->RegisterTag("iblock_id_new");
    }
}

$aMenuLinks = array_merge($aMenuLinksExt, $aMenuLinks);
CDBResult CIBlock::GetList(
    array arOrder = array("SORT"=>"ASC"),
    array arFilter = array(),
    bool bIncCnt = false
);

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

CIBlockResult — вспомогательный класс для работы с объектами результатов выборок, наследуется от класса CDBResult и содержит все его параметры и методы. Объекты данного класса возвращают методы CIBlockElement::GetList(), CIBlockElement::GetByID() и функции GetIBlockElementList(), GetIBlockElementListEx.

Методы класса

  • GetNext() — Возвращает из выборки список полей элемента, с замененными ссылками в полях DETAIL_PAGE_URL и LIST_PAGE_URL.
  • GetNextElement() — Возвращает объект _CIBElement элемента из выборки.
  • SetUrlTemplates() — Устанавливает шаблоны путей для элементов.
  • SetSectionContext() — Метод устанавливает поля раздела в качестве родителя элемента для подстановки в шаблоны путей.

Осталось только удалить пункт меню «Каталог» из файла .main.menu.php

<?php
$aMenuLinks = array(
    array(
        "Доставка",
        "/delivery/",
        array(), 
        array(), 
        "" 
    ),
    array(
        "Оплата", 
        "/payment/", 
        array(),
        array(),
        "" 
    ),
    array(
        "Контакты",
        "/contacts/",
        array(),
        array(),
        "" 
    )
);

Если кроме корневых разделов каталога нам нужно еще выводить и подразделы, в файле .main.menu_ext.php изменяем "DEPTH_LEVEL"=>"1" на "DEPTH_LEVEL"=>"2" и вносим изменения в шаблон компонента:

<?php
/*
 * Файл local/templates/.default/components/bitrix/menu/.default/template.php, старый вариант
 */
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
?>

<?php if (!empty($arResult)): ?>
    <ul>
    <?php foreach ($arResult as $arItem): ?>
        <?php if ($arItem["SELECTED"]): ?>
            <li class="active"><a href="<?= $arItem["LINK"]; ?>"><?= $arItem["TEXT"]; ?></a></li>
        <?php else:?>
            <li><a href="<?= $arItem["LINK"]; ?>"><?= $arItem["TEXT"]; ?></a></li>
        <?php endif; ?>
    <?php endforeach; ?>
    </ul>
<?php endif; ?>
<?php
/*
 * Файл local/templates/.default/components/bitrix/menu/.default/template.php, новый вариант
 */
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
?>

<?php if (!empty($arResult)): ?>
    <?php $previousLevel = 0; ?>
    <ul>
    <?php foreach ($arResult as $arItem): ?>
        <?php if ($arItem["DEPTH_LEVEL"] == $previousLevel): ?>
            </li>
        <?php endif; ?>

        <?php if ($arItem["DEPTH_LEVEL"] > $previousLevel): /* открыть вложенный список */ ?>
            <?php if ($previousLevel > 0): ?>
                <ul>
            <?php endif; ?>
        <?php elseif ($arItem["DEPTH_LEVEL"] < $previousLevel): /* закрыть вложенный список */ ?>
            </li>
            </ul>
            </li>
        <?php endif; ?>

        <?php if ($arItem["SELECTED"]): /* элемент списка <li> */ ?>
            <li class="active">
        <?php else: ?>
            <li>
        <?php endif; ?>

        <a href="<?= $arItem["LINK"]; ?>"><?= $arItem["TEXT"]; ?></a>

        <?php $previousLevel = $arItem["DEPTH_LEVEL"]; ?>
    <?php endforeach; ?>
    </li>
    </ul>
<?php endif; ?>

Результат работы этого кода:

<ul>
    <li>
        <a href="/catalog/list.php?SECTION_ID=18">Обувь</a>
        <ul>
            <li>
                <a href="/catalog/list.php?SECTION_ID=20">Босоножки</a>
            </li>
            <li>
                <a href="/catalog/list.php?SECTION_ID=19">Туфли</a>
            </li>
            <li>
                <a href="/catalog/list.php?SECTION_ID=21">Сапоги</a>
            </li>
        </ul>
    </li>
    <li>
        <a href="/catalog/list.php?SECTION_ID=22">Одежда</a>
        <ul>
            <li>
                <a href="/catalog/list.php?SECTION_ID=24">Брюки</a>
            </li>
            <li>
                <a href="/catalog/list.php?SECTION_ID=16">Платья</a>
            </li>
            <li>
                <a href="/catalog/list.php?SECTION_ID=23">Юбки</a>
            </li>
        </ul>
    </li>
    <li>
        <a href="/catalog/list.php?SECTION_ID=17">Сумки</a>
    </li>
    <li>
        <a href="/payment/">Оплата</a>
    </li>
    <li>
        <a href="/delivery/">Доставка</a>
    </li>
    <li>
        <a href="/contacts/">Контакты</a>
    </li>
</ul>

Нам осталось только набросать стили:

#menu {
    margin-top: 5px;
}
    #menu ul { /* многоуровневый список */
        margin: 0;
        padding: 0;
        list-style: none;
        background: #323232;
    }
        #menu > ul > li {
            float: left;
        }
        #menu > ul > li > ul {
            top: 100%;
            left: 0;
        }
    #menu li {
        position: relative;
    }
    #menu a {
        display: block;
        white-space: nowrap;
        text-decoration: none;
        color: #fff;
        padding: 10px;
        line-height: 1.2;
        text-transform: uppercase;
        min-width: 120px;
    }
            #menu ul li li ul {
                top: 0;
                left: 100%;
            }
        #menu ul ul {
            visibility: hidden;
            position: absolute;
            z-index: 2;
            min-width: 200px;
        }
        #menu li:hover > ul {
            visibility: visible;
        }
    #menu:after {
        content: "";
        clear: both;
        display: block;
    }
    #menu a:hover {
        background: #5390cc;
    }
        #menu > ul > li > ul > li > a, #menu > ul > li > ul > li > ul > li > a {
            border-top: 1px solid #4f5254;
            padding: 7px 10px;
        }

Если нужен трехуровневый список, в файле .main.menu_ext.php изменяем "DEPTH_LEVEL"=>"2" на "DEPTH_LEVEL"=>"3" и вносим изменения в шаблон компонента:

<?php
/*
 * Файл local/templates/.default/components/bitrix/menu/.default/template.php, новый вариант
 */
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
?>

<?php if (!empty($arResult)): ?>
    <ul>
    <?php $previousLevel = 0; ?>
    <?php foreach ($arResult as $arItem): ?>

        <?php if ($previousLevel && $arItem["DEPTH_LEVEL"] < $previousLevel): ?>
            <?= str_repeat("</ul></li>", ($previousLevel - $arItem["DEPTH_LEVEL"])); ?>
        <?php endif; ?>

        <?php if ($arItem["IS_PARENT"]): /* если есть дочерние элементы */ ?>
            <?php if ($arItem["DEPTH_LEVEL"] == 1): /* корневой элемент */ ?>
                <li class="root parent<?php if ($arItem["SELECTED"]): ?> active<?php endif; ?>">
                    <a href="<?= $arItem["LINK"]; ?>"><?= $arItem["TEXT"]; ?></a>
                    <ul>
            <?php else: /* элемент второго, третьего уровня */ ?>
                <li class="parent<?php if ($arItem["SELECTED"]): ?> active<?php endif; ?>">
                    <a href="<?= $arItem["LINK"]; ?>"><?= $arItem["TEXT"]; ?></a>
                    <ul>
            <?php endif; ?>
        <?php else: /* если нет дочерних элементов */ ?>
            <?php if ($arItem["DEPTH_LEVEL"] == 1): /* корневой элемент */ ?>
                <li class="root<?php if ($arItem["SELECTED"]): ?> active<?php endif; ?>">
                    <a href="<?= $arItem["LINK"]; ?>"><?= $arItem["TEXT"]; ?></a>
                </li>
            <?php else: /* элемент второго, третьего уровня */ ?>
                <li<?php if ($arItem["SELECTED"]): ?> class="active"<?php endif; ?>>
                    <a href="<?= $arItem["LINK"]; ?>"><?= $arItem["TEXT"]; ?></a>
                </li>
            <?php endif; ?>
        <?php endif; ?>

        <?php $previousLevel = $arItem["DEPTH_LEVEL"]; ?>

    <?php endforeach; ?>

    <?php if ($previousLevel > 1): ?>
        <?= str_repeat("</ul></li>", ($previousLevel-1)); ?>
    <?php endif; ?>
    </ul>
<?php endif; ?>
<ul>
    <li class="root parent">
        <a href="/catalog/list.php?SECTION_ID=18">Обувь</a>
        <ul>
            <li>
                <a href="/catalog/list.php?SECTION_ID=20">Босоножки</a>
            </li>
            <li>
                <a href="/catalog/list.php?SECTION_ID=19">Туфли</a>
            </li>
            <li class="parent">
                <a href="/catalog/list.php?SECTION_ID=21">Сапоги</a>
                <ul>
                    <li>
                        <a href="/catalog/list.php?SECTION_ID=25">Зимние сапоги</a>
                    </li>
                    <li>
                        <a href="/catalog/list.php?SECTION_ID=26">Осенние сапоги</a>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
    <li class="root parent">
        <a href="/catalog/list.php?SECTION_ID=22">Одежда</a>
        <ul>
            <li>
                <a href="/catalog/list.php?SECTION_ID=24">Брюки</a>
            </li>
            <li>
                <a href="/catalog/list.php?SECTION_ID=16">Платья</a>
            </li>
            <li>
                <a href="/catalog/list.php?SECTION_ID=23">Юбки</a>
            </li>
        </ul>
    </li>
    <li class="root">
        <a href="/catalog/list.php?SECTION_ID=17">Сумки</a>
    </li>
    <li class="root">
        <a href="/payment/">Оплата</a>
    </li>
    <li class="root">
        <a href="/delivery/">Доставка</a>
    </li>
    <li class="root">
        <a href="/contacts/">Контакты</a>
    </li>
</ul>

Поиск: .type.menu_ext.php • CMS • Web-разработка • Битрикс • Инфоблок • Компонент • Меню • Навигация • Раздел инфоблока • Структура

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.