Пункты меню из разделов инфоблока Битрикс

Просмотров: 101752

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

Добавляем разделы в инфоблок:

Предположим что нам нужно создать меню из подкатегорий новостей. У нас уже есть готовый инфоблок для новостей и он выведен на сайт. В общем новости работают. И наступил момент, что новостей стало достаточно много и пора их разбить на несколько категорий: "Спорт", "Финансы" и.т.д.

Для начала создаем эти разделы:

создание раздела в инфоблоке битрикс

Теперь задача создать пункты выпадающего меню, которое автоматически будет брать разделы в качестве своих пунктов. Для этого нужно создать необходимый тип меню в Управлении структурой. В моем случае я создаю тип меню "Меню подраздела"

создание меню

Создаем в нужном каталоге сайта этот тип меню и рядом с ним создаем такой же файл с приставкой _ext.php.

Создание ext меню

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

Настройка ext меню в битрикс

В меню сайта необходимо подключить соответствующее меню в пункте "Тип меню для остальных уровней:" и установить чекбокс для "Подключать файлы с именами вида .тип_меню.menu_ext.php:"

ext меню

В наше ..._ext.php меню вносим вот такие данные:

 <? 
 if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die(); 
      global $APPLICATION; 
      $aMenuLinksExt=$APPLICATION->IncludeComponent("bitrix:menu.sections", "", array( 
      "IS_SEF" => "Y", 
      "SEF_BASE_URL" => "/blog/", 
      "SECTION_PAGE_URL" => "#SECTION_ID#/", 
      "DETAIL_PAGE_URL" => "#SECTION_ID#/#ELEMENT_ID#.html", 
      "IBLOCK_TYPE" => "company", 
      "IBLOCK_ID" => "5", 
      "DEPTH_LEVEL" => "3", 
      "CACHE_TYPE" => "A", 
      "CACHE_TIME" => "36000000" 
      ), 
  false 
 ); 
 $aMenuLinks = array_merge($aMenuLinksExt, $aMenuLinks); 
 ?> 

Где:

  • "SEF_BASE_URL" => "/blog/", - каталог инфоблока на сайте
  • "SECTION_PAGE_URL" => "#SECTION_ID#/", - подставляем ID раздела
  • "DETAIL_PAGE_URL" => "#SECTION_ID#/#ELEMENT_ID#.html", - полный путь к элементу инфоблока
  • "IBLOCK_TYPE" => "company", - ID типа инфоблока из которого выводим
  • "IBLOCK_ID" => "5", ID инфоблока из которого выводим
  • "DEPTH_LEVEL" => "4", уровень вложенности, этой цифрой можно выводить подразделы разделов если иерархия многоуровневая

В настройках компонента инфоблока также прописываем аналогичный путь к элементам и разделам инфоблока

настройка ЧПУ битрикс

В итоге все вновь создаваемые разделы инфоблока будут автоматически попадать в выпадающее меню (в моем случае, вы можете проделать эти манипуляции для любого типа меню)

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

Элементы инфоблока в меню

Таким же образом можно сделать и меню из элементов инфоблока или вообще чего угодно. Просто, в файле меню с типом _ext наполняете массив $aMenuLinksExt нужными данными

Что бы получить элементы и их ссылки достаточно воспользоваться методом CIBlockElement::GetList

Быстрый пример:


if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
global $APPLICATION;
if(CModule::IncludeModule("iblock")) {
   $res = CIBlockElement::GetList(
             false, 
             array(
                "IBLOCK_ID"=> 5, // ID нужного инфоблока
                "ACTIVE"=>"Y"
             ),
            false,
            false, 
            array( // Нужны только названиеи ссылка
                "NAME"
                "DETAIL_PAGE_URL"
             ),
   );
   while($arFields = $res->Fetch()){
           $aMenuLinksExt[] = Array(
                $arFields['NAME'],
                $arFields['DETAIL_PAGE_URL'],
                Array(),
                Array(),
                ""
             );
    }
}
$aMenuLinks = array_merge($aMenuLinksExt, $aMenuLinks);
Михаил Базаров 22.05.2023
Цитата
Alex написал:
Месяц знакомлюсь с битриксом. Сделал вывод: если есть возможность, то лучше не использовать эту "технологию". С меню мучаюсь уже неделю. Не могу сделать меню из разделов и элементов раздела. Если бы я использовал реакт или даже нативный php, то сделал бы это меню за несколько часов. Здесь же я мучаюсь. Такой тупей шей реализации еще не встречал!  

Да, для такого лучше использовать catalog.section.list - элементы можно добавить в массив, для вывода меню, через result_modifier.php
Если есть время, совсем хорошо сделать свой компонент, что бы лишнее не тянуть.
Гость 28.09.2023
Михаил, А как сделать для лэндинга активными пункты меню с # и в пределах одной страницы?
Михаил Базаров 28.09.2023
Так вот не смогу дать готовый код, но думаю только с помощью js
Проверять какой блок находится в зоне видимости и по id пункта меню добавлять ему нужный class
То есть, грубо говоря, если блок с id="block1" сейчас по offset 0 от верха страницы, то добавить class="selected" для пункта меню с id="link_to_block1"
Гость 28.09.2023
Спасибо за ответ, Михаил ! Так и думал, что функционалом битрикса это не решить ...
Noob 23.11.2023
Здравствуйте. Подскажите, данный метод еще актуален? Не получается добавить ни элементы, ни разделы в меню - ничего не происходит. Спасибо
Noob 24.11.2023
Для меня сработал этот код:
Код
<? if(!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true)die();
global $APPLICATION;
if(CModule::IncludeModule('iblock')) {
   $IBLOCK_ID = 7; // ID инфоблока из которого берем элементы
   $arOrder = Array('NAME'=>'ASC'); // Выбрать сортировку
   $arSelect = Array('ID', 'NAME', 'IBLOCK_ID', 'DETAIL_PAGE_URL');
   $arFilter = Array('IBLOCK_ID'=>$IBLOCK_ID, 'ACTIVE'=>'Y', 'PROPERTY_razdel'=> $_REQUEST['SECTION_ID']);
   $res = CIBlockElement::GetList($arOrder, $arFilter, false, false, $arSelect);
   while($ob = $res->GetNextElement()) {
      $arFields = $ob->GetFields();
      $aMenuLinksExt[] = Array(
         $arFields['NAME'],
         $arFields['DETAIL_PAGE_URL'],
         Array(),
         Array(),
         ''
      );
   }
}
$aMenuLinks = array_merge($aMenuLinksExt, $aMenuLinks);
?>

Если честно, впервые столкнулся с Битрикс и .php
Михаил, не могли бы вы объяснить разницу между Вашим решением и вышеприведённым? Спасибо
* При внедрении Вашего решения неоднократно чистил кэш как в настройках Битрикс, так и через админпанель
Noob 24.11.2023
А возможно вывести картинку для анонса или детальное изображение (не  важно) из каталога рядом с названием пункта меню? К примеру, чтобы слева  от текста располагалось изображение?

Попробовал поменять код файла .тип_меню.menu_ext.php:
Код
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();global $APPLICATION;
if (CModule::IncludeModule('iblock')) {
    $IBLOCK_ID = 11; // ID инфоблока из которого берем элементы
    $arOrder = Array('NAME' => 'ASC'); // Выбрать сортировку
    $arSelect = Array('ID', 'NAME', 'IBLOCK_ID', 'DETAIL_PAGE_URL', 'PREVIEW_PICTURE'); // Включить PREVIEW_PICTURE в выборку
    $arFilter = Array('IBLOCK_ID' => $IBLOCK_ID, 'ACTIVE' => 'Y', 'PROPERTY_razdel' => $_REQUEST['SECTION_ID']);
    $res = CIBlockElement::GetList($arOrder, $arFilter, false, false, $arSelect);
    while ($ob = $res->GetNextElement()) {
        $arFields = $ob->GetFields();
        $imageSrc = !empty($arFields['PREVIEW_PICTURE']) ? CFile::GetPath($arFields['PREVIEW_PICTURE']) : ''; // Получаем путь к изображению
        $aMenuLinksExt[] = Array(
            $arFields['NAME'],
            $arFields['DETAIL_PAGE_URL'],
            Array(),
            Array(),
            '',
            'PARAMS' => array(
                'IMG_SRC' => $imageSrc, // Передаем путь к изображению в параметрах
            ),
        );
    }
}
$aMenuLinks = array_merge($aMenuLinksExt, $aMenuLinks);
?>

Код шаблона меню:

Код
<? if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die(); ?>

<? if (!empty($arResult)): ?>
<ul id="horizontal-multilevel-menu">
    <?
    $previousLevel = 0;
    foreach ($arResult as $arItem):
    $imageSrc = !empty($arItem['PREVIEW_PICTURE']) ? CFile::GetPath($arItem['PREVIEW_PICTURE']) : ''; // Получаем путь к изображению

    if ($previousLevel && $arItem["DEPTH_LEVEL"] < $previousLevel) {
        echo str_repeat("</ul></li>", ($previousLevel - $arItem["DEPTH_LEVEL"]));
    }

    if ($arItem["IS_PARENT"]) {
    if ($arItem["DEPTH_LEVEL"] == 1) {
    ?>
    <li>
        <?php if (!empty($imageSrc)): ?>
            <img src="<?= $imageSrc ?>" alt="<?= $arItem["TEXT"] ?>" class="menu-item-image">
        <?php endif; ?>
        <a href="<?= $arItem["LINK"] ?>" class="<?= $arItem["SELECTED"] ? 'root-item-selected' : 'root-item' ?>">
            <?= $arItem["TEXT"] ?>
        </a>
        <ul>
            <?php
            } else {
            ?>
            <li<?= $arItem["SELECTED"] ? ' class="item-selected"' : '' ?>>
                <a href="<?= $arItem["LINK"] ?>" class="parent"><?= $arItem["TEXT"] ?></a>
                <ul>
                    <?php
                    }
                    } else {
                        if ($arItem["PERMISSION"] > "D") {
                            if ($arItem["DEPTH_LEVEL"] == 1) {
                                ?>
                                <li>
                                    <?php if (!empty($imageSrc)): ?>
                                        <img src="<?= $imageSrc ?>" alt="<?= $arItem["TEXT"] ?>" class="menu-item-image">
                                    <?php endif; ?>
                                    <a href="<?= $arItem["LINK"] ?>"
                                       class="<?= $arItem["SELECTED"] ? 'root-item-selected' : 'root-item' ?>">
                                        <?= $arItem["TEXT"] ?>
                                    </a>
                                </li>
                                <?php
                            } else {
                                ?>
                                <li<?= $arItem["SELECTED"] ? ' class="item-selected"' : '' ?>>
                                    <a href="<?= $arItem["LINK"] ?>"><?= $arItem["TEXT"] ?></a>
                                </li>
                                <?php
                            }
                        } else {
                            if ($arItem["DEPTH_LEVEL"] == 1) {
                                ?>
                                <li>
                                    <a href=""
                                       class="<?= $arItem["SELECTED"] ? 'root-item-selected' : 'root-item' ?>"
                                       title="<?= GetMessage("MENU_ITEM_ACCESS_DENIED") ?>">
                                        <?= $arItem["TEXT"] ?>
                                    </a>
                                </li>
                                <?php
                            } else {
                                ?>
                                <li>
                                    <a href="" class="denied"
                                       title="<?= GetMessage("MENU_ITEM_ACCESS_DENIED") ?>"><?= $arItem["TEXT"] ?></a>
                                </li>
                                <?php
                            }
                        }
                    }

                    $previousLevel = $arItem["DEPTH_LEVEL"];
                    endforeach;

                    if ($previousLevel > 1) {
                        echo str_repeat("</ul></li>", ($previousLevel - 1));
                    }
                    ?>

                </ul>
                <div class="menu-clear-left"></div>
                <? endif ?>
В итоге ничего не меняется. Визуально все остается таким же, код работает. 
Если просто добавить 
[/COLOR][/FONT][/COLOR][CODE]$arFields['PREVIEW_PICTURE'],            
$arFields ['DETAIL_PICTURE'],

в массив $aMenuLinksExt, то меню ломается, вылезает ошибка.

Подскажите, что я делаю не так? Опыт битрикс и php нулевой, извините за тупость

Михаил Базаров 24.11.2023
Способ точно рабочий, но в вашем случае, раз уж все равно выводите и разделы и элементы (так понял из сообщений) проще воспользоваться компонентом catalog.section.list - он умеет выводить все данные разделов включя картинки.
А дополучить внутри них элементы уже дело техники - там не сложно.
Гость 24.02.2024
Добрый день,
как сделать для нескольких инфоблоков?
Михаил Базаров 24.02.2024
Цитата
Гость написал:
Добрый день,
как сделать для нескольких инфоблоков?

Нужно будет кастомизировать компонент  bitrix:menu.sections
Но лучше написать свой, который параметрами будет принимать нужны инфоблоки и собирать массив arResult в шаблон