Меню из разделов инфоблока с элементами инфоблока
Готовый код можно скачать в моем репозитории на GitFlic.
В битриксе можно создавать меню из разделов инфоблока, для этого к компоненту menu
подключается файл типа .*.menu_ext.php
, подробнее об этом тут, в нем вызывается компонент menu.sections
. У этого подхода нет возможности включать в меню элементы разделов, а это иногда бывает нужно.
Для этого я сделал компонент menu.sections.elements
, подключается он так же в файле .*.menu_ext.php
.
.description.php
menu.sections.elements/.description.php<?php
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
$arComponentDescription = array(
// название компонента
'NAME' => 'Список разделов и элементов для sitemap.html',
// описание компонента
'DESCRIPTION' => 'Получаем список разделов и элементов для компонента main.map',
// путь к иконке компонента относительно папки компонента
'ICON' => '/images/eaddlist.gif',
// показывать кнопку очистки кеша
'CACHE_PATH' => 'Y',
// порядок сортировки в визуальном редакторе
'SORT' => 30,
// признак комплексного компонента
'COMPLEX' => 'N',
// расположение компонента в визуальном редакторе
'PATH' => array(
// идентификатор верхнего уровеня в редакторе
'ID' => 'likee',
// название верхнего уровня в редакторе
'NAME' => 'Лайки',
)
);
.parameters.php
menu.sections.elements/.parameters.php<?php
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
// проверяем установку модуля «Информационные блоки»
if (!CModule::IncludeModule('iblock')) {
return;
}
// получаем массив всех типов инфоблоков для возможности выбора
$arTypesEx = CIBlockParameters::GetIBlockTypes(array("all" => " "));
// пустой массив для вывода
$arIBlocks = array();
// метод выборки информационных блоков
$db_iblock = CIBlock::GetList(array("SORT" => "ASC"), array("SITE_ID" => $_REQUEST["site"], "TYPE" => ($arCurrentValues["IBLOCK_TYPE"] != "all" ? $arCurrentValues["IBLOCK_TYPE"] : "")));
// перебираем и выводим в адмику доступные информационные блоки
while ($arRes = $db_iblock->Fetch()) {
$arIBlocks[$arRes["ID"]] = $arRes["NAME"];
}
$arComponentParameters = array(
"GROUPS" => array(),
"PARAMETERS" => array(
"IBLOCK_TYPE" => array(
"PARENT" => "BASE",
"NAME" => "Выберите тип инфоблока",
"TYPE" => "LIST",
"VALUES" => $arTypesEx,
"DEFAULT" => "",
"ADDITIONAL_VALUES" => "N",
"REFRESH" => "Y",
),
"IBLOCK_ID" => array(
"PARENT" => "BASE",
"NAME" => "Выберите родительский инфоблок",
"TYPE" => "LIST",
"VALUES" => $arIBlocks,
"DEFAULT" => '',
"MULTIPLE" => "N",
"ADDITIONAL_VALUES" => "N",
"REFRESH" => "Y",
),
"DEPTH_LEVEL" => array(
"PARENT" => "DATA_SOURCE",
"NAME" => "Уровень вложенности",
"TYPE" => "STRING",
"DEFAULT" => "1",
),
"DELETE_SECTION" => array(
"PARENT" => "DATA_SOURCE",
"NAME" => "Исключения по ID для секций",
"TYPE" => "STRING",
"DEFAULT" => "",
),
"DELETE_ELEMENT" => array(
"PARENT" => "DATA_SOURCE",
"NAME" => "Исключения по ID для секций",
"TYPE" => "STRING",
"DEFAULT" => "",
),
"CACHE_TIME" => array("DEFAULT" => 36000000),
),
);
class.php
menu.sections.elements/class.php<?php
/**
* @author Эйч Маркетинг <info@hmarketing.ru>
* @copyright 2014-2024 The hmarketing.ru
*/
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
// пространство имен для работы с языковыми файлами
use Bitrix\Main\Localization\Loc;
// пространство имен для всех исключений в системе
use Bitrix\Main\SystemException;
// пространство имен для загрузки необходимых файлов, классов, модулей
use Bitrix\Main\Loader;
// пространство имен для работы с кешем
use \Bitrix\Main\Data\Cache;
use \Bitrix\Main\Application;
/**
* основной класс компонента
*
*/
class sitemapHtml extends CBitrixComponent
{
/**
* ID секций для фильтра
*
* @var array
*/
public $arSectionId = array();
/**
* данные элементов и разделов
*
* @var array
*/
public $menuItems = array();
/**
* выполняет основной код компонента, аналог конструктора (метод подключается автоматически)
*
* @return void
*/
public function executeComponent()
{
try {
// подключаем метод проверки подключения модуля «Информационные блоки»
$this->checkModules();
// подключаем метод подготовки массива $arResult
return $this->getResult();
} catch (SystemException $e) {
ShowError($e->getMessage());
}
}
/**
* подключение языковых файлов (метод подключается автоматически)
*
* @return void
*/
public function onIncludeComponentLang()
{
Loc::loadMessages(__FILE__);
}
/**
* проверяем установку модуля «Информационные блоки» (метод подключается внутри класса try...catch)
*
* @return void
*/
protected function checkModules()
{
// если модуль не подключен
if (!Loader::includeModule('iblock')) {
// выводим сообщение в catch
throw new SystemException(Loc::getMessage('IBLOCK_MODULE_NOT_INSTALLED'));
}
}
/**
* обработка массива $arParams (метод подключается автоматически)
*
* @param array $arParams
* @return array
*/
public function onPrepareComponentParams($arParams)
{
// настройки $arParams кеширование
if (!isset($arParams['CACHE_TIME'])) {
$arParams['CACHE_TIME'] = 3600;
} else {
$arParams['CACHE_TIME'] = intval($arParams['CACHE_TIME']);
}
// настройки $arParams ID инфоблока
$arParams['IBLOCK_ID'] = intval($arParams['IBLOCK_ID']);
// настройки $arParams уровень
$arParams['DEPTH_LEVEL'] = intval($arParams['DEPTH_LEVEL']);
// настройки $arParams исключение секций
$arParams['DELETE_SECTION'] = preg_replace("#[^0-9\,]#", '', $arParams['DELETE_SECTION']);
// настройки $arParams исключение элементов
$arParams['DELETE_ELEMENT'] = preg_replace("#[^0-9\,]#", '', $arParams['DELETE_ELEMENT']);
return $arParams;
}
/**
* подготовка массива $arResult (метод подключается внутри класса try...catch)
*
* @return array
*/
protected function getResult()
{
// служба кеширования
$cache = Cache::createInstance();
// служба пометки кеша тегами
$taggedCache = Application::getInstance()->getTaggedCache();
$cachePath = 'sitemap-html';
$cacheTtl = $this->arParams['CACHE_TIME'];
$cacheKey = 'sitemapHtm';
// если кеш есть
if ($cache->initCache($cacheTtl, $cacheKey, $cachePath)) {
$this->arResult = $cache->getVars();
return $this->arResult;
}
// если кеша нет
elseif ($cache->startDataCache()) {
// начинаем записывать тегированый кеш
$taggedCache->startTagCache($cachePath);
// кеш сбрасываем при изменении данных в инфоблоке с ID который передаем
$taggedCache->registerTag('iblock_id_' . $this->arParams['IBLOCK_ID']);
//*********************************//
// Секции //
//*********************************//
// поля
$arSelect = array(
'ID',
'DEPTH_LEVEL',
'NAME',
'SECTION_PAGE_URL',
'IBLOCK_SECTION_ID',
);
// фильтр
$arFilter = array(
'IBLOCK_ID' => $this->arParams['IBLOCK_ID'],
'GLOBAL_ACTIVE' => 'Y',
'ACTIVE' => 'Y',
'<=DEPTH_LEVEL' => $this->arParams['DEPTH_LEVEL'],
'!=ID' => [$this->arParams['DELETE_SECTION']],
);
// сортировка
$arOrder = array(
'SORT' => 'ASC',
);
// запрос
$rsSections = CIBlockSection::GetList($arOrder, $arFilter, false, $arSelect);
// перебираем секции
while ($arSection = $rsSections->GetNext()) {
// секция всегда 1
$arSection['IS_SECTION'] = 1;
// ссылка на раздел
$arSection['LINK'] = $arSection['SECTION_PAGE_URL'];
// проверяем ID группы, если не задан то корень
if ($arSection['IBLOCK_SECTION_ID']) {
$this->menuItems[$arSection['IBLOCK_SECTION_ID']][] = $arSection;
} else {
$this->menuItems['ROOT'][] = $arSection;
}
// записываем ID секции
$arSectionId[] = $arSection['ID'];
}
//*********************************//
// Элементы //
//*********************************//
// поля
$arSelect = array(
'ID',
'NAME',
'DETAIL_PAGE_URL',
'IBLOCK_SECTION_ID'
);
// фильтр
$arFilter = array(
'IBLOCK_ID' => $this->arParams['IBLOCK_ID'],
'ACTIVE' => 'Y',
array(
'LOGIC' => 'OR',
array('SECTION_ID' => $arSectionId),
array('SECTION_ID' => false),
),
'!=ID' => [$this->arParams['DELETE_ELEMENT']],
);
// сортировка
$arOrder = array(
'SORT' => 'ASC'
);
// запрос
$res = CIBlockElement::GetList($arOrder, $arFilter, false, false, $arSelect);
// перебираем элементы
while ($ob = $res->GetNextElement()) {
// получаем элемент
$arFields = $ob->GetFields();
// элемент всегда 0
$arFields['IS_SECTION'] = 0;
// ссылка на элемент
$arFields['LINK'] = $arFields['DETAIL_PAGE_URL'];
// проверяем ID группы, если не задан то корень
if ($arFields['IBLOCK_SECTION_ID']) {
$this->menuItems[$arFields['IBLOCK_SECTION_ID']][] = $arFields;
} else {
$this->menuItems['ROOT'][] = $arFields;
}
}
// прогоняем через метод
$this->createMenuArray($this->menuItems['ROOT'], 1);
// заканчиваем записывать тегированый кеш
$taggedCache->endTagCache();
// записываем результат в тегированный кеш
$cache->endDataCache($this->arResult);
return $this->arResult;
}
}
/**
* наполняем массив $arResult разделяя корневые элементы и вложенные
*
* @param array $menuItemsRoot корневые элементы
* @param int $depthLevel уровень вложенности
* @return void
*/
function createMenuArray($menuItemsRoot, $depthLevel)
{
// перебираем корневые элементы
foreach ($menuItemsRoot as $item) {
// если секция и в $menuItems есть вложенные элементы
$isParent = ($item['IS_SECTION'] && isset($this->menuItems[$item['ID']]));
// наполняем $arResult
$this->arResult[] = array(
htmlspecialchars($item['~NAME']),
$item['LINK'],
array(),
array(
'FROM_IBLOCK' => true,
'IS_PARENT' => $isParent,
'DEPTH_LEVEL' => $depthLevel,
),
);
// если секция и в $menuItems есть вложенные элементы, дергаем createMenuArray и заполняем ими $arResult
if ($isParent) {
$this->createMenuArray($this->menuItems[$item['ID']], $depthLevel + 1);
}
}
}
}
Вызов в .*.menu_ext.php
.sitemap_section.menu_ext.php<?php
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
global $APPLICATION;
$aMenuLinksExt = $APPLICATION->IncludeComponent(
"likee:menu.sections.elements",
"",
array(
"IBLOCK_TYPE" => "POLEZNOE",
"IBLOCK_ID" => "14",
"DEPTH_LEVEL" => "5",
"CACHE_TYPE" => "A",
"DELETE_SECTION" => "",
"DELETE_ELEMENT" => "",
"CACHE_TIME" => "3600"
),
false
);
$aMenuLinks = array_merge($aMenuLinksExt, $aMenuLinks);