Bitrix: menu ext с деревом разделов и элементов

от автора

в
Время чтения: 3 мин.

Чтобы создать компонент с древовидным списком разделов и элементами инфоблока для подключения в .left.menu_ext.php, нужно адаптировать компонент для работы в контексте левого меню. Основная задача — вывести разделы и элементы в виде дерева, которое будет интегрировано в левое меню сайта.


1. Структура компонента

Создайте папку для компонента в директории /local/components/.

Например:

/local/components/custom/section.tree.menu/

Внутри создайте следующие файлы:

  • .description.php — описание компонента.
  • class.php — основной код компонента.

2. Описание компонента (.description.php)

Этот файл описывает параметры компонента.

<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();

$arComponentDescription = [
    'NAME' => 'Древовидное меню разделов с элементами',
    'DESCRIPTION' => 'Получает разделы инфоблока в виде пунктов для левого меню',
    'PATH' => [
        'ID' => 'custom',
        'NAME' => 'Кастомные компоненты',
    ],
];

3. Основной код компонента (class.php)

Этот файл содержит логику компонента.

<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();

class SectionTreeMenuComponent extends CBitrixComponent
{
    // Подготовка параметров
    public function onPrepareComponentParams($arParams)
    {
        if (!isset($arParams['CACHE_TIME'])) {
            $arParams['CACHE_TIME'] = 36000;
        }

        return $arParams;
    }

    // Инициализация компонента
    public function executeComponent()
    {
        if ($this->startResultCache()) {
            if (CModule::IncludeModule('iblock')) {
                $this->arResult = $this->buildMenu($this->getSectionTree());
                $this->endResultCache();
            } else {
                $this->abortResultCache();
            }
        }

        return $this->arResult;
    }

    // Получение дерева разделов с элементами
    protected function getSectionTree()
    {
        $iblockId = $this->arParams['IBLOCK_ID']; // ID инфоблока
        $sections = [];
        $elements = [];

        // Получаем разделы
        $rsSections = CIBlockSection::GetList(
            ['LEFT_MARGIN' => 'ASC'],
            ['IBLOCK_ID' => $iblockId, 'ACTIVE' => 'Y'],
            false,
            ['ID', 'NAME', 'DEPTH_LEVEL', 'IBLOCK_SECTION_ID', 'SECTION_PAGE_URL']
        );

        while ($section = $rsSections->Fetch()) {
            $sections[$section['ID']] = $section;
        }

        // Получаем элементы
        $rsElements = CIBlockElement::GetList(
            [],
            ['IBLOCK_ID' => $iblockId, 'ACTIVE' => 'Y'],
            false,
            false,
            ['ID', 'NAME', 'IBLOCK_SECTION_ID', 'DETAIL_PAGE_URL']
        );

        while ($element = $rsElements->Fetch()) {
            $elements[$element['IBLOCK_SECTION_ID']][] = $element;
        }

        // Формируем дерево
        $tree = $this->buildTree($sections, $elements);

        return $tree;
    }

    // Построение дерева разделов с элементами
    protected function buildTree($sections, $elements)
    {
        $tree = [];

        // Сначала создаём плоский массив с указанием родительских разделов
        foreach ($sections as $id => $section) {
            $sections[$id]['CHILDREN'] = []; // Инициализируем массив для дочерних разделов
            $sections[$id]['ELEMENTS'] = isset($elements[$id]) ? $elements[$id] : []; // Добавляем элементы
        }

        // Строим дерево
        foreach ($sections as $id => $section) {
            if ($section['IBLOCK_SECTION_ID']) {
                // Если у раздела есть родитель, добавляем его в CHILDREN родителя
                $sections[$section['IBLOCK_SECTION_ID']]['CHILDREN'][] = &$sections[$id];
            } else {
                // Если это корневой раздел, добавляем его в дерево
                $tree[] = &$sections[$id];
            }
        }

        return $tree;
    }

    // Функция построения пунктов меню
    protected function buildMenu($menuItems)
    {
        $aMenuLinks = [];

        $this->addMenuItems($aMenuLinks, $menuItems);

        return $aMenuLinks;
    }

    // Функция для рекурсивного добавления пунктов меню
    function addMenuItems(&$aMenuLinks, $items, $depthLevel = 1)
    {
        foreach ($items as $item) {
            // Добавляем раздел
            $aMenuLinks[] = [
                $item['NAME'], // Название раздела
                $item['SECTION_PAGE_URL'], // Ссылка на раздел
                [],
                [
                    'FROM_IBLOCK' => true,
                    'IS_PARENT' => false,
                    'DEPTH_LEVEL' => $depthLevel,
                ],

            ];

            // Добавляем элементы раздела
            if (!empty($item['ELEMENTS'])) {
                $aMenuLinks[count($aMenuLinks) - 1][3]['IS_PARENT'] = true;
                foreach ($item['ELEMENTS'] as $element) {
                    $aMenuLinks[] = [
                        $element['NAME'], // Название элемента
                        $element['DETAIL_PAGE_URL'], // Ссылка на элемент
                        [],
                        [
                            'FROM_IBLOCK' => true,
                            'IS_PARENT' => false,
                            'DEPTH_LEVEL' => $depthLevel + 1,
                        ],
                    ];
                }
            }

            // Рекурсивно добавляем дочерние разделы
            if (!empty($item['CHILDREN'])) {
                $aMenuLinks[count($aMenuLinks) - 1][3]['IS_PARENT'] = true;
                $this->addMenuItems($aMenuLinks, $item['CHILDREN'], $depthLevel + 1);
            }
        }
    }
}

4. Подключение компонента в .left.menu_ext.php

Чтобы подключить компонент в левом меню, откройте файл .left.menu_ext.php и добавьте вызов компонента:

if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();

/** @global CMain $APLICATION */
/** @var array $aMenuLinks */

global $APPLICATION;

$aMenuLinksExt = $APPLICATION->IncludeComponent(
    'custom:section.tree.menu',
    '',
    [
        'IBLOCK_ID' => 5, // ID инфоблока
    ]
);

$aMenuLinks = array_merge($aMenuLinks, $aMenuLinksExt);

Итог

Теперь у вас есть компонент, который выводит древовидное меню разделов с элементами инфоблока и может быть подключен в .left.menu_ext.php. Если нужно доработать или добавить функционал, дайте знать! 😊


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Сколько будет 7 + 8?