Битрикс. Самописный компонент «Структура разделов»
31.12.2018
Теги: CMS • Web-разработка • Битрикс • Иерархия • Компонент • Меню • Навигация • РазделИнфоблока • Структура
Давайте создадим простой компонент, который будет уметь формировать структуру разделов инфоблока в виде дерева. Такой компонент можно использовать для создания вспомогательного меню или при формировании страницы карты сайта. В настройках можно будет выбрать инфоблок и задать глубину вложенности разделов.
Файл описания компонента .description.php
:
<?php /* * Файл local/components/tokmakov/iblock.tree/.description.php */ if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die(); $arComponentDescription = array( 'NAME' => 'Структура разделов', // название компонента 'DESCRIPTION' => 'Выводит дерево разделов инфоблока', 'ICON' => '/images/icon.gif', // иконка компонента относительно папки компонента 'CACHE_PATH' => 'Y', // показывать кнопку очистки кеша 'SORT' => 50, // порядок сортировки в визуальном редакторе 'COMPLEX' => 'N', // признак комплексного компонента 'PATH' => array( // расположение компонента в визуальном редакторе 'ID' => 'other_components', // идентификатор верхнего уровеня в редакторе 'NAME' => 'Прочие компоненты', // название верхнего уровня в редакторе 'CHILD' => array( // второй уровень в визуальном редакторе 'ID' => 'other_iblock', // идентификатор второго уровня в редакторе 'NAME' => 'Информационный блок' // название второго уровня в редакторе ) ) );
Настройки компонента для визуального редактора:
<?php /* * Файл local/components/tokmakov/iblock.element/.parameters.php */ if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die(); // проверяем, установлен ли модуль «Информационные блоки»; если да — то подключаем его if (!CModule::IncludeModule('iblock')) { return; } /* * Получаем массив всех типов инфоблоков — для возможности выбора */ $arIBlockType = CIBlockParameters::GetIBlockTypes(); /* * Получаем массив инфоблоков — для возможности выбора; фильтруем их по * выбранному типу и по активности */ $arInfoBlocks = array(); $arFilter = array('ACTIVE' => 'Y'); // если уже выбран тип инфоблока, выбираем инфоблоки только этого типа if (!empty($arCurrentValues['IBLOCK_TYPE'])) { $arFilter['TYPE'] = $arCurrentValues['IBLOCK_TYPE']; } $rsIBlock = CIBlock::GetList( array('SORT' => 'ASC'), $arFilter ); while($iblock = $rsIBlock->Fetch()) { $arInfoBlocks[$iblock['ID']] = '['.$iblock['ID'].'] '.$iblock['NAME']; } /* * Настройки компонента */ $arComponentParameters = array( 'PARAMETERS' => array( // выбор типа инфоблока 'IBLOCK_TYPE' => array( 'PARENT' => 'BASE', 'NAME' => 'Выберите тип инфоблока', 'TYPE' => 'LIST', 'VALUES' => $arIBlockType, 'REFRESH' => 'Y', ), // выбор самого инфоблока 'IBLOCK_ID' => array( 'PARENT' => 'BASE', 'NAME' => 'Выберите инфоблок', 'TYPE' => 'LIST', 'VALUES' => $arInfoBlocks, ), // до какой глубины вложенности выбирать разделы 'DEPTH_LEVEL' => array( 'PARENT' => 'BASE', 'NAME' => 'До какой глубины вложенности выбирать разделы', 'TYPE' => 'STRING', 'DEFAULT' => '2' ), // шаблон ссылки на страницу раздела 'SECTION_URL' => array( 'PARENT' => 'URL_TEMPLATES', 'NAME' => 'URL, ведущий на страницу с содержимым раздела', 'TYPE' => 'STRING', 'DEFAULT' => '#SITE_DIR#/#IBLOCK_CODE#/category/id/#SECTION_ID#/' ), // настройки кеширования 'CACHE_TIME' => array('DEFAULT'=>3600), 'CACHE_GROUPS' => array( // учитывать права доступа? 'PARENT' => 'CACHE_SETTINGS', 'NAME' => 'Учитывать права доступа', 'TYPE' => 'CHECKBOX', 'DEFAULT' => 'Y', ), ), );
Код компонента, который выбирает разделы инфоблока с сортировкой по LEFT_MARGIN
:
<?php /* * Файл local/components/infoblock/iblock.tree/component.php */ if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die(); /** @var CBitrixComponent $this */ /** @var array $arParams */ /** @var array $arResult */ /** @var string $componentPath */ /** @var string $componentName */ /** @var string $componentTemplate */ /** @global CDatabase $DB */ /** @global CUser $USER */ /** @global CMain $APPLICATION */ if (!CModule::IncludeModule('iblock')) { ShowError('Модуль «Информационные блоки» не установлен'); return; } if (!isset($arParams['CACHE_TIME'])) { $arParams['CACHE_TIME'] = 3600; } // тип инфоблока $arParams['IBLOCK_TYPE'] = trim($arParams['IBLOCK_TYPE']); // идентификатор инфоблока $arParams['IBLOCK_ID'] = intval($arParams['IBLOCK_ID']); // до какой глубины выбирать разделы $arParams['DEPTH_LEVEL'] = intval($arParams['DEPTH_LEVEL']); // шаблон ссылки на страницу с содержимым раздела $arParams['SECTION_URL'] = trim($arParams['SECTION_URL']); if ($this->StartResultCache(false, $arParams['CACHE_GROUPS']==='N' ? false: $USER->GetGroups())) { /* * Выбираем все разделы инфоблока до выбранной глубины */ // какие поля раздела инфоблока выбираем $arSelect = array( 'ID', 'NAME', 'PICTURE', 'DESCRIPTION', 'DESCRIPTION_TYPE', 'SECTION_PAGE_URL', 'DEPTH_LEVEL' ); // условия выборки раздела инфоблока $arFilter = array( 'IBLOCK_ID' => $arParams['IBLOCK_ID'], 'IBLOCK_ACTIVE' => 'Y', 'ACTIVE' => 'Y', 'GLOBAL_ACTIVE' => 'Y', '<=DEPTH_LEVEL' => $arParams['DEPTH_LEVEL'] ); // сортировка разделов для построения дерева $arSort = array( 'LEFT_MARGIN' => 'ASC', 'SORT' => 'ASC' ); // выполняем запрос к базе данных $dbResult = CIBlockSection::GetList( array(), $arFilter, false, $arSelect ); // устанавливаем шаблон пути для раздела, вместо того, // который указан в настройках информационного блока $dbResult->SetUrlTemplates('', $arParams['SECTION_URL']); while ($arSection = $dbResult->GetNext()) { // маленькая картинка раздела if ($arSection['PICTURE'] > 0) { $arSection['PICTURE'] = CFile::GetFileArray($arSection['PICTURE']); } else { $arSection['PICTURE'] = false; } $arResult[] = $arSection; } if (!empty($arResult)) { // если данные успешно получены $this->IncludeComponentTemplate(); } else { // что-то пошло не так $this->AbortResultCache(); } }
Шаблон компонента просто выводит список разделов инфоблока:
<?php /* * Файл local/components/tokmakov/iblock.tree/templates/.default/template.php */ if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die(); /** @var array $arParams */ /** @var array $arResult */ /** @global CMain $APPLICATION */ /** @global CUser $USER */ /** @global CDatabase $DB */ /** @var CBitrixComponentTemplate $this */ /** @var string $templateName */ /** @var string $templateFile */ /** @var string $templateFolder */ /** @var string $componentPath */ /** @var CBitrixComponent $component */ $this->setFrameMode(true); ?> <?php if (!empty($arResult)): ?> <ul id="iblock-section-tree"> <?php foreach ($arResult as $arSection): ?> <li class="section-level-<?= $arSection['DEPTH_LEVEL']; ?>"> <a href="<?= $arSection['SECTION_PAGE_URL']; ?>"><?= $arSection['NAME']; ?></a> </li> <?php endforeach; ?> </ul> <?php endif; ?>
Зададим стили, чтобы получился не просто список, а дерево:
/*
* Файл local/components/tokmakov/iblock.tree/templates/.default/style.css
*/
#iblock-section-tree > .section-level-2 {
margin-left: 20px;
}
#iblock-section-tree > .section-level-3 {
margin-left: 40px;
}
Массив $arResult
, доступный в шаблоне компонента:
Array ( [0] => Array ( [ID] => 16 [NAME] => Породы кошек [PICTURE] => Array ( [ID] => 945 [MODULE_ID] => iblock [HEIGHT] => 200 [WIDTH] => 200 [FILE_SIZE] => 21194 [CONTENT_TYPE] => image/jpeg .......... [SRC] => /upload/iblock/c16/c16acb4b686640c521df122f575acdb9.jpg ) [DESCRIPTION] => Быть может, кошка и не лучший друг человека (это почетное звание оспаривают... [DESCRIPTION_TYPE] => html [SECTION_PAGE_URL] => /articles/category/id/16/ [DEPTH_LEVEL] => 1 [CODE] => porody-koshek [EXTERNAL_ID] => 29 [IBLOCK_TYPE_ID] => content [IBLOCK_ID] => 5 [IBLOCK_CODE] => articles [GLOBAL_ACTIVE] => Y ) [1] => Array ( [ID] => 17 [NAME] => Длинношерстные [PICTURE] => Array ( [ID] => 984 [MODULE_ID] => iblock [HEIGHT] => 700 [WIDTH] => 700 [FILE_SIZE] => 193845 [CONTENT_TYPE] => image/jpeg ......... [SRC] => /upload/iblock/317/317346676253ea0776365b83b83c7dba.jpg ) [DESCRIPTION] => Длинношерстные кошки – настоящие красавицы, которые не оставят равнодушными... [DESCRIPTION_TYPE] => text [SECTION_PAGE_URL] => /articles/category/id/17/ [DEPTH_LEVEL] => 2 [CODE] => dlinnosherstnye [IBLOCK_TYPE_ID] => content [IBLOCK_ID] => 5 [IBLOCK_CODE] => articles [GLOBAL_ACTIVE] => Y ) [2] => Array ( [ID] => 18 [NAME] => Короткошерстные [PICTURE] => Array ( [ID] => 983 [MODULE_ID] => iblock [HEIGHT] => 700 [WIDTH] => 700 [FILE_SIZE] => 71596 [CONTENT_TYPE] => image/jpeg .......... [SRC] => /upload/iblock/17b/17ba9590bb537f17a9eb8a5edb912819.jpg ) [DESCRIPTION] => Короткошёрстные кошки очень полюбились владельцам квартир, так как они не требуют... [SECTION_PAGE_URL] => /articles/category/id/18/ [DEPTH_LEVEL] => 2 [CODE] => korotkosherstnye [IBLOCK_TYPE_ID] => content [IBLOCK_ID] => 5 [IBLOCK_CODE] => articles [GLOBAL_ACTIVE] => Y ) [3] => Array ( [ID] => 19 [NAME] => Породы собак [PICTURE] => Array ( [ID] => 951 [MODULE_ID] => iblock [HEIGHT] => 200 [WIDTH] => 200 [FILE_SIZE] => 20142 [CONTENT_TYPE] => image/jpeg .......... [SRC] => /upload/iblock/54b/54b6016bcfdda68acb57b3f7e54a1b73.jpg ) [DESCRIPTION] => Более 20 тысяч лет назад первобытный человек привел в свое жилище совершенно... [DESCRIPTION_TYPE] => html [SECTION_PAGE_URL] => /articles/category/id/19/ [DEPTH_LEVEL] => 1 [CODE] => porody-sobak [EXTERNAL_ID] => 28 [IBLOCK_TYPE_ID] => content [IBLOCK_ID] => 5 [IBLOCK_CODE] => articles [GLOBAL_ACTIVE] => Y ) [4] => Array ( [ID] => 20 [NAME] => Декоративные породы [PICTURE] => Array ( [ID] => 953 [MODULE_ID] => iblock [HEIGHT] => 200 [WIDTH] => 200 [FILE_SIZE] => 25689 [CONTENT_TYPE] => image/jpeg .......... [SRC] => /upload/iblock/ffa/ffa1f34cc799b4bcc86381ecd06e332f.jpg ) [DESCRIPTION] => Декоративные собаки — собирательное определение пород собак, не предназначенных... [DESCRIPTION_TYPE] => html [SECTION_PAGE_URL] => /articles/category/id/20/ [DEPTH_LEVEL] => 2 [CODE] => dekorativnye-porody [IBLOCK_TYPE_ID] => content [IBLOCK_ID] => 5 [IBLOCK_CODE] => articles [GLOBAL_ACTIVE] => Y ) [5] => Array ( [ID] => 21 [NAME] => Служебные породы [PICTURE] => Array ( [ID] => 955 [MODULE_ID] => iblock [HEIGHT] => 200 [WIDTH] => 200 [FILE_SIZE] => 24596 [CONTENT_TYPE] => image/jpeg .......... [SRC] => /upload/iblock/b1a/b1a0c6fed22467a3da087c3fdae64241.jpg ) [DESCRIPTION] => К ним относится ряд пород, которые человек использует для работы. Использование... [DESCRIPTION_TYPE] => html [SECTION_PAGE_URL] => /articles/category/id/21/ [DEPTH_LEVEL] => 2 [CODE] => sluzhebnye-porody [IBLOCK_TYPE_ID] => content [IBLOCK_ID] => 5 [IBLOCK_CODE] => articles [GLOBAL_ACTIVE] => Y ) )
Чтобы сформировать многоуровневый список, нужно модифицировать массив $arResult
<?php /* * Файл local/components/tokmakov/iblock.tree/templates/.default/result_modifier.php */ if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die(); if (!empty($arResult)) { foreach ($arResult as $key => $value) { $arResult[$key]['IS_PARENT'] = false; if (isset($arResult[$key+1]) && $arResult[$key+1]['DEPTH_LEVEL'] > $value['DEPTH_LEVEL']) { $arResult[$key]['IS_PARENT'] = true; } } }
Тогда шаблон компонента будет таким:
<?php /* * Файл local/components/tokmakov/iblock.tree/templates/.default/template.php */ if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die(); /** @var array $arParams */ /** @var array $arResult */ /** @global CMain $APPLICATION */ /** @global CUser $USER */ /** @global CDatabase $DB */ /** @var CBitrixComponentTemplate $this */ /** @var string $templateName */ /** @var string $templateFile */ /** @var string $templateFolder */ /** @var string $componentPath */ /** @var CBitrixComponent $component */ $this->setFrameMode(true); ?> <?php if (!empty($arResult)): ?> <ul> <?php $previousLevel = 0; ?> <?php foreach ($arResult as $arSection): ?> <?php if ($previousLevel && $arSection['DEPTH_LEVEL'] < $previousLevel): ?> <?= str_repeat('</ul></li>', ($previousLevel - $arSection['DEPTH_LEVEL'])); ?> <?php endif; ?> <?php if ($arSection['IS_PARENT']): /* если есть дочерние элементы */ ?> <?php if ($arSection['DEPTH_LEVEL'] == 1): /* корневой элемент */ ?> <li class="root parent"> <a href="<?= $arSection['SECTION_PAGE_URL']; ?>"><?= $arSection['NAME']; ?></a> <ul> <?php else: /* элемент второго, третьего уровня */ ?> <li class="parent"> <a href="<?= $arSection['SECTION_PAGE_URL']; ?>"><?= $arSection['NAME']; ?></a> <ul> <?php endif; ?> <?php else: /* если нет дочерних элементов */ ?> <?php if ($arSection['DEPTH_LEVEL'] == 1): /* корневой элемент */ ?> <li class="root"> <a href="<?= $arSection['SECTION_PAGE_URL']; ?>"><?= $arSection['NAME']; ?></a> </li> <?php else: /* элемент второго, третьего уровня */ ?> <li> <a href="<?= $arSection['SECTION_PAGE_URL']; ?>"><?= $arSection['NAME']; ?></a> </li> <?php endif; ?> <?php endif; ?> <?php $previousLevel = $arSection['DEPTH_LEVEL']; ?> <?php endforeach; ?> <?php if ($previousLevel > 1): ?> <?= str_repeat('</ul></li>', ($previousLevel-1)); ?> <?php endif; ?> </ul> <?php endif; ?>
А сформированный шаблоном html-код будет таким:
<ul> <li class="root parent"> <a href="/articles/category/id/16/">Породы кошек</a> <ul> <li> <a href="/articles/category/id/17/">Длинношерстные</a> </li> <li> <a href="/articles/category/id/18/">Короткошерстные</a> </li> </ul> </li> <li class="root parent"> <a href="/articles/category/id/19/">Породы собак</a> <ul> <li> <a href="/articles/category/id/20/">Декоративные породы</a> </li> <li> <a href="/articles/category/id/21/">Служебные породы</a> </li> </ul> </li> </ul>
Пример вызова компонента:
$APPLICATION->IncludeComponent( "tokmakov:iblock.tree", "", Array( "CACHE_GROUPS" => "Y", "CACHE_TIME" => "3600", "CACHE_TYPE" => "A", "DEPTH_LEVEL" => "2", "IBLOCK_ID" => "5", "IBLOCK_TYPE" => "content", "SECTION_URL" => "#SITE_DIR#/#IBLOCK_CODE#/category/id/#SECTION_ID#/" ) );
Поиск: CMS • Web-разработка • Битрикс • Иерархия • Компонент • Меню • Навигация • Раздел инфоблока