Элементы инфоблока в меню Битрикс: разделы и корень каталога
Файлы меню: статические и расширенные
Пункты навигации в «1С-Битрикс» задаются наборами .menu.php рядом с разделами сайта. Если нужно подмешать данные из инфоблока, добавляют соседний файл с суффиксом _ext — именно там удобно собирать ссылки через PHP без ручного редактирования меню после каждой правки контента.
Разделы и «корневые» карточки рядом с каталогом
Готовый вывод деревьев разделов уже закрывает компонент bitrix:menu.sections. Отдельного штатного блока только для элементов нет — поэтому цепочка обычно такая: сначала тянем разделы через компонент, затем выборкой CIBlockElement::GetList добавляем активные элементы без привязки к разделу (фильтр по пустому IBLOCK_SECTION_ID).
Чтобы подменю «подвешивалось» к пункту вида Каталог, файл расширения кладётся в ту же директорию, что открывает страницу каталога, например /catalog/.left.menu_ext.php для типа, указанного в CHILD_MENU_TYPE основного меню (часто это left).
Пример файла расширения с кешем и тегами
Ниже — базовый сценарий: разделы из компонента, затем элементы из корня инфоблока, собранные в том же массиве пунктов и объединённые с уже существующими $aMenuLinks. Чтобы запросы к базе не били при каждом хите, включён управляемый кеш и тег iblock_id_* для автоматической инвалидации при изменении инфоблока. У компонента разделов кеш отключён — он не дублирует общую стратегию.
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
die();
}
global $APPLICATION;
use Bitrix\Main\Data\Cache;
use Bitrix\Main\Application;
$inventoryBlockId = 8;
$navCacheHandle = Cache::createInstance();
$tagEngine = Application::getInstance()->getTaggedCache();
$navBucketKey = 'catalog_nav_fusion_' . $inventoryBlockId;
if ($navCacheHandle->initCache(36000, $navBucketKey, $navBucketKey)) {
$menuExtensionItems = $navCacheHandle->getVars();
} elseif ($navCacheHandle->startDataCache()) {
$tagEngine->startTagCache($navBucketKey);
$menuExtensionItems = $APPLICATION->IncludeComponent(
'bitrix:menu.sections',
'',
[
'ID' => '',
'IBLOCK_TYPE' => 'trade_offers',
'IBLOCK_ID' => $inventoryBlockId,
'SECTION_URL' => '',
'DEPTH_LEVEL' => '1',
'CACHE_TYPE' => 'N',
'CACHE_TIME' => '3600',
]
);
$rootRows = CIBlockElement::GetList(
['SORT' => 'ASC', 'NAME' => 'ASC'],
[
'IBLOCK_ID' => $inventoryBlockId,
'IBLOCK_SECTION_ID' => false,
'ACTIVE' => 'Y',
],
false,
false,
['ID', 'NAME', 'DETAIL_PAGE_URL']
);
while ($item = $rootRows->GetNext()) {
$url = $item['DETAIL_PAGE_URL'];
$menuExtensionItems[] = [
$item['NAME'],
$url,
[$url],
[
'FROM_IBLOCK' => true,
'IS_PARENT' => false,
'DEPTH_LEVEL' => '1',
],
];
}
$tagEngine->registerTag('iblock_id_' . $inventoryBlockId);
$tagEngine->endTagCache();
$navCacheHandle->endDataCache($menuExtensionItems);
}
$aMenuLinks = array_merge($aMenuLinks, $menuExtensionItems);Общая сортировка с разделами
В таком виде блок из компонента и материалы из базы просто дописываются друг за другом. Если нужно «перемешать» раздел и карточку по полю сортировки, придётся, чтобы число SORT было доступно для всех элементов строки меню.
Стандартный menu.sections может не пробрасывать сортировку разделов в финальный массив — типичное решение: скопировать компонент в /local/components/custom/menu.sections/, аккуратно добавить нужное поле при построении ссылок, а в меню подключить уже свой вариант через custom:menu.sections. После этого один проход usort по индексу SORT в параметрах пункта выравнивает порядок: меньший SORT поднимает ссылку выше, в том числе над соседним разделом.
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
die();
}
global $APPLICATION;
use Bitrix\Main\Data\Cache;
use Bitrix\Main\Application;
$inventoryBlockId = 8;
$navCacheHandle = Cache::createInstance();
$tagEngine = Application::getInstance()->getTaggedCache();
$navBucketKey = 'catalog_nav_mixed_' . $inventoryBlockId;
if ($navCacheHandle->initCache(36000, $navBucketKey, $navBucketKey)) {
$menuExtensionItems = $navCacheHandle->getVars();
} elseif ($navCacheHandle->startDataCache()) {
$tagEngine->startTagCache($navBucketKey);
$menuExtensionItems = $APPLICATION->IncludeComponent(
'custom:menu.sections',
'',
[
'ID' => '',
'IBLOCK_TYPE' => 'trade_offers',
'IBLOCK_ID' => $inventoryBlockId,
'SECTION_URL' => '',
'DEPTH_LEVEL' => '1',
'CACHE_TYPE' => 'N',
'CACHE_TIME' => '3600',
]
);
$flatElements = CIBlockElement::GetList(
[],
[
'IBLOCK_ID' => $inventoryBlockId,
'IBLOCK_SECTION_ID' => false,
'ACTIVE' => 'Y',
],
false,
false,
['ID', 'NAME', 'DETAIL_PAGE_URL', 'SORT']
);
while ($item = $flatElements->GetNext()) {
$rank = isset($item['SORT']) ? (int)$item['SORT'] : 0;
$url = $item['DETAIL_PAGE_URL'];
$menuExtensionItems[] = [
$item['NAME'],
$url,
[$url],
[
'FROM_IBLOCK' => true,
'IS_PARENT' => false,
'DEPTH_LEVEL' => '1',
'SORT' => $rank,
],
];
}
usort($menuExtensionItems, static function ($left, $right) {
$a = isset($left[3]['SORT']) ? (int)$left[3]['SORT'] : 0;
$b = isset($right[3]['SORT']) ? (int)$right[3]['SORT'] : 0;
return $a <=> $b;
});
$tagEngine->registerTag('iblock_id_' . $inventoryBlockId);
$tagEngine->endTagCache();
$navCacheHandle->endDataCache($menuExtensionItems);
}
$aMenuLinks = array_merge($aMenuLinks, $menuExtensionItems);Что помнить перед выкладкой
- Значение
$inventoryBlockIdи символьный код типа инфоблока замените на реальные из административной панели. - Скопируйте ядросный компонент целиком, не вырезая зависимости, и включите свой вариант только после локального теста.
- Разумный TTL кеша и тегирование сберегут производительность и не потребуют ручного сброса после правок элементов.
Сочетание .menu_ext.php, готовых разделов и явной выборки корневых элементов даёт управляемое меню без костылей в шаблоне и допускает дальнейшую кастомизацию порядка пунктов одной точкой конфигурации.
Не хотите копаться сами?
Починю за 1-3 дня. Без предоплаты — оплата по результату.
15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии