Меню из разделов инфоблока с элементами
24.09.2013
В битриксе можно создавать меню из разделов инфоблока, для этого к компоненту menu подключается файл типа *.menu_ext.php, а в нем вызывается компонент menu.sections. Но нет возможности включать в меню элементы разделов, а это иногда бывает полезно. Так, кстати, сделано на этом сайте.
Для этого я сделал компонент menu.sections.elements, подключается он так же в файле *.menu_ext.php, коды я приведу ниже:
.parameters.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"=>GetMessage("CP_BMS_IBLOCK_TYPE"),
"TYPE"=>"LIST",
"VALUES"=>$arTypesEx,
"DEFAULT"=>"catalog",
"ADDITIONAL_VALUES"=>"N",
"REFRESH" => "Y",
),
"IBLOCK_ID" => Array(
"PARENT" => "BASE",
"NAME"=>GetMessage("CP_BMS_IBLOCK_ID"),
"TYPE"=>"LIST",
"VALUES"=>$arIBlocks,
"DEFAULT"=>'1',
"MULTIPLE"=>"N",
"ADDITIONAL_VALUES"=>"N",
"REFRESH" => "Y",
),
"DEPTH_LEVEL" => Array(
"PARENT" => "DATA_SOURCE",
"NAME" => GetMessage("CP_BMS_DEPTH_LEVEL"),
"TYPE" => "STRING",
"DEFAULT" => "1",
),
"CACHE_TIME" => Array("DEFAULT"=>36000000),
),
);
component.php
if (!function_exists('createMenuArray')){
function createMenuArray(&$res,&$menuItems,$arParent,$depthLevel){
foreach($arParent as $item){
$isParent = ($item['IS_SECTION']&&isset($menuItems[$item['ID']]));
$res[] = array(
htmlspecialchars($item['~NAME']),
$item['LINK'],
array(), //массив доп ссылок
array(
'FROM_IBLOCK' => true,
'IS_PARENT' => $isParent,
'DEPTH_LEVEL' => $depthLevel,
),
);
if ($isParent){
createMenuArray($res,$menuItems,$menuItems[$item['ID']],$depthLevel+1);
}
}
}
}
if(!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die();
if(!isset($arParams['CACHE_TIME']))
$arParams['CACHE_TIME'] = 36000000;
$arParams['IBLOCK_ID'] = intval($arParams['IBLOCK_ID']);
$arParams['DEPTH_LEVEL'] = intval($arParams['DEPTH_LEVEL']);
if($arParams['DEPTH_LEVEL']<=0)
$arParams['DEPTH_LEVEL']=1;
if($this->StartResultCache()) {
CModule::IncludeModule('iblock');
$arSectionId = array();
$arFilter = array(
'IBLOCK_ID'=>$arParams['IBLOCK_ID'],
'GLOBAL_ACTIVE'=>'Y',
'ACTIVE'=>'Y',
'<=DEPTH_LEVEL' => $arParams['DEPTH_LEVEL'],
);
$arOrder = array(
'SORT'=>'ASC',
);
$rsSections = CIBlockSection::GetList($arOrder, $arFilter, false, array(
'ID',
'DEPTH_LEVEL',
'NAME',
'SECTION_PAGE_URL',
'IBLOCK_SECTION_ID',
));
$menuItems = array();
while($arSection = $rsSections->GetNext()){
$arSection['IS_SECTION'] = 1;
$arSection['LINK'] = $arSection['SECTION_PAGE_URL'];
if ($arSection['IBLOCK_SECTION_ID']){
$menuItems[$arSection['IBLOCK_SECTION_ID']][] = $arSection;
} else {
$menuItems['ROOT'][] = $arSection;
}
$arSectionId[] = $arSection['ID'];
}
//Получим элементы
$arSelect = Array('ID', 'NAME','DETAIL_PAGE_URL', 'IBLOCK_SECTION_ID');
$arFilter = Array(
'IBLOCK_ID' => $arParams['IBLOCK_ID'],
'ACTIVE' => 'Y',
array(
'LOGIC' => 'OR',
array('SECTION_ID' => $arSectionId),
array('SECTION_ID' => false),
),
);
$arOrder = Array('SORT' => 'ASC');
$res = CIBlockElement::GetList($arOrder, $arFilter, false, false, $arSelect);
while ($ob = $res->GetNextElement()){
$arFields = $ob->GetFields();
$arFields['IS_SECTION'] = 0;
$arFields['LINK'] = $arFields['DETAIL_PAGE_URL'];
if ($arFields['IBLOCK_SECTION_ID']){
$menuItems[$arFields['IBLOCK_SECTION_ID']][] = $arFields;
} else {
$menuItems['ROOT'][] = $arFields;
}
}
//Рекурсивно сформируем итоговый массив для меню
$arResult = array();
createMenuArray($arResult,$menuItems,$menuItems['ROOT'],1);
$this->EndResultCache();
}
return $arResult;
.left.menu_ext.php (для примера)
<?
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
global $APPLICATION;
$aMenuLinksExt=$APPLICATION->IncludeComponent(
"max22:menu.sections.elements",
"",
array(
"IBLOCK_TYPE" => "content",
"IBLOCK_ID" => "1",
"DEPTH_LEVEL" => "5",
"CACHE_TYPE" => "A",
"CACHE_TIME" => "36000000"
),
false
);
$aMenuLinks = array_merge($aMenuLinksExt, $aMenuLinks);
?>
Не забываем размещать свои компоненты в своем пространстве имен, в примере это max22
Комментарии:
Lia
24.07.2014 19:26:48
Кирилл
29.08.2014 18:05:30
Костя
16.09.2014 16:44:44
Bronskiy
12.01.2015 11:48:16
Максим
12.01.2015 14:13:02
Bronskiy
12.01.2015 20:19:29
Иван
14.01.2015 12:24:13
Максим
14.01.2015 19:59:45
Варианты отличаются по типу создаваемой нагрузки на сервер, какой выбрать оптимальнее нужно смотреть по конкретной ситуации.
Иван
15.01.2015 11:59:50
Максим
15.01.2015 12:42:14
Alex
16.01.2015 14:50:53
Заранее Спасибо!
Максим
16.01.2015 18:03:52
Alex
16.01.2015 19:31:27
Алекс
27.02.2015 11:00:08
Спасибо большое за компонент, очень выручил.
Возник вопрос, не удалось настроить сортировку разделов и элементов между собой.
То есть сначала выводятся разделы и сортируются между собой, а потом выводятся элементы и сортируются между собой.
Есть ли возможно пересортировать элементы и разделы между собой?
Максим
27.02.2015 17:10:58
Для добавления данного функционала можно модернизировать функцию createMenuArray, в начале функции до цикла проводить сортировку массива $arParent, согласно полю SORT
Nosferatv
22.06.2015 17:14:28
Сергей
21.07.2015 12:10:41
Максим
21.07.2015 12:50:38
Дмитрий
17.09.2015 17:11:35
Nick
23.09.2015 11:18:52
Nick
23.09.2015 11:30:42
Создал папку /bitrix/components/Nick/menu.sections.elements
в ней два файла .parameters.php и component.php потом подключил в меню и получил menu.sections.elements' is not a component ... ((
Максим
23.09.2015 12:04:44
Думаю вы к компоненту обращаетесь bitrix:menu.sections.elements или max22:menu.sections.elements, а нужно Nick:menu.sections.elements
Nick здесь это пространство имен компонентов.
Nick
23.09.2015 14:04:16
Максим
23.09.2015 18:58:35
либо попробуйте переименовать папку и назвать все маленькими буквами, т.к. я например, не припомню чтобы видел названия пространств в большой буквы. Но врятли в этом дело.
Может быть, если с именами все ок, то просто у сервера прав на чтение не хватает, например, если апатч из под одного юзера работает, а вы папку из под рута создавали. Но это тоже врятли.
Думаю имеет место быть опечатка или что то в этом роде.
Nick
24.09.2015 03:43:22
Подключился компонент, но по-моему что то не так... Если в настройках я ставлю уровень вложенности 1 тогда получаю меню из списка разделов/элементов инфоблока + 1й пункт состоит из раздела/элемента + подразделы + элементы подраздела, т.е. это вроде как лишнее. Т.е. тогда уж и первый пункт должен быть не разворачивающийся.
Если ставлю глубину 2 тогда получаю меню из разделов/элементов и подразделов + элемент подраздела, это уже подходит, но как убрать элементы подразделов?
И еще настройки URL в файле вызова модуля никак не влияют на URL пунктов меню, у меня выдает так .ru/fo_bud_dlia_gragdan/list.php?SECTION_ID=145 fo_bud_dlia_gragdan это тип инфоблока ну верный, ID секции тоже правильный откуда берет list.php ? Вообще должна быть ссылка типа .ru/about/dependents/finansovyy-otdel/byudzhet-dlya-grazhdan/?SECTION_ID=142
Максим
24.09.2015 06:12:10
>И еще настройки URL в файле вызова модуля никак не влияют на URL
там и нет настроек урл, если смотреть файл .parameters.php, просто я в примере вызова забыл убрать эти параметры (сейчас убрал). А Урл должен настраиваться в настройке инфоблока: https://yadi.sk/i/0imlg6vBjHQfa
Nick
24.09.2015 10:09:40
>Элементы всегда будут подключаться, т.е. если глубина 1, то будут разделы 1-го уровня и их элементы. На выходе имеем 2-х уровневое меню.
Если я не ошибаюсь, сейчас меню работает ни так. Не пойму как поправить код чтобы при глубине 1 не показывались элементы первого пункта меню, и почему именно первый в остальных же не показывает...
Вот скриншоты:
глубина 1 - http://www.picshare.ru/uploads/150924/v5tU2aHGQX.jpg
глубина 2 - http://www.picshare.ru/uploads/150924/AYLc52Uc9l.jpg
Nick
29.09.2015 04:05:40
Насчет сортировки:
Алекс, в текущей реализации такой возможности нет. Действительно сначала выводятся разделы, потом элементы.
Для добавления данного функционала можно модернизировать функцию createMenuArray, в начале функции до цикла проводить сортировку массива $arParent, согласно полю SORT
В массиве нет поля Sort, как его туда добавить??? Подскажите пожалуйста очень хочется настроить все как надо уж больно хороший компонент. :)
Nick
29.09.2015 05:26:59
Максим
29.09.2015 07:54:59
на
И затем перед
Добавить
Nick
01.10.2015 03:44:32
Nick
01.10.2015 08:52:08
Вот здесь описал подробно проблему http://dev.1c-bitrix.ru/community/forums/messages/forum6/topic75312/message390070/index.php#message390070
это может быть ошибка в компоненте???
Nick
06.10.2015 05:18:44
Подскажите, вот у меня когда я нахожусь в каком нибудь разделе инфоблока меню разворачивает полностью все пункты меню до указанной в настройках глубины, это так задумано или у меня проблема с шаблоном?
При этом свернуть развернутые пункты я не могу при нажатии на пункт просто меняется значек напротив пункта,а сам пункт меню не сворачивается...
Нуб
13.10.2015 14:10:26
foxufo
20.10.2015 12:34:29
а почему именно так htmlspecialchars($item['~NAME']), у меня так пустые названия получились.. заменил на $item['NAME'] и все хорошо..
Nikolay
02.12.2015 15:40:13
Евгений
18.12.2015 01:34:28
Евегний
27.12.2015 22:15:49
Не знаю насколько правильно, возможно это жуткий костыль, но он работает.
В компонент, перед вызовом функции createMenuArray добавляем
$iblock=CIBlock::GetArrayByID($arParams['IBLOCK_ID'],""); //получаем инфоблок
$link='/'.$iblok['CODE'].'/'; //получаем ссылку из кода инфоблока, тут, наверно надо проверять включен ли ЧПУ, у меня включен, поэтому не проверяю
$name=htmlspecialchars($iblock['NAME']); //получаем имя, у меня оно почему-то ////составное - [s1] Услуги, поэтому следующий шаг
$name=explode(" ", $name); // разбиваем имя на части
$iblock1= array('NAME'=>$name[1],'LINK'=>$link);//формируем массив
$firsttime=TRUE; //маркер первого запуска, т.к. функция рекурсивная
createMenuArray($arResult,$menuItems,$menuItems['ROOT'],1,$iblok1,$firsttime);
и в самой функции перед циклом перебора массивов добавил
if ($ft){
$res[] = array(
htmlspecialchars($iblock['NAME']),
$iblock['LINK'],
array(), //массив доп ссылок
array(
'FROM_IBLOCK' => true,
'IS_PARENT' => 1,
'DEPTH_LEVEL' => 1,
),
);
$ft = FALSE;
}
Кирилл
07.03.2016 08:22:28
Дмитрий
01.06.2016 10:18:33
Еще раз благодарю)
Алеша
06.07.2016 16:10:26
gagra33332
04.09.2016 03:46:10
Jack
01.11.2016 16:56:48
Jack
01.11.2016 18:10:36
Максим
02.11.2016 05:26:16
в массив параметров добавьте параметра IS_SECTION => $item['IS_SECTION'], вот так:
В шаблоне по этому параметру будете определять раздел это или нет.
PS Что за проблема была со ссылками? Шаблоны пути были не указаны в настройках инфоблока?
Jack
02.11.2016 10:15:49
Со ссылками - да, раньше я выводил элементы каталога более тривиальными способами и меня устраивали дефотлные пути, потписанные его разделам:
#SITE_DIR#/catalog/index.php?ID=#IBLOCK_ID#
#SITE_DIR#/catalog/list.php?SECTION_ID=#SECTION_ID#
#SITE_DIR#/catalog/detail.php?ID=#ELEMENT_ID#
Для вашего меню пришлось поправить, но теперь вроде все заработало, осталось разобраться с внешним видом.
А вообще очень здорово вы сделали. Я перебрал 3 или 4 варианта этого кастомного компонента и ни один нормально не работал.
Jack
02.11.2016 16:47:52
Максим
02.11.2016 16:58:13
Я первым делам в шаблоне пишу:
Смотрю что приходит из компонента.
Jack
02.11.2016 17:17:26
Но почему тогда при фильтрации они не различаются. Может, неправильно обращаюсь? Как писать:
<?if($arFields['IS_SECTION'] == 1):?>
или
<?if($arParams['IS_SECTION'] == 1):?>
Максим
02.11.2016 18:25:58
Jack
03.11.2016 10:29:57
Сергей
08.11.2016 20:55:00
Валентина
16.11.2016 22:30:39
Асем
13.01.2017 12:54:21
Спасибо!
Максим
13.01.2017 15:00:23
Вам нужно в админке к разделу добавить пользовательское свойство с типом да/нет, задать код свойства, например, UF_NOT_SHOW_IN_MENU, проставить галочку на разделе, который вам не нужен в меню.
затем фильтр по разделам изменить следующим образом:
Асем
16.01.2017 07:07:21
Олег
16.01.2017 15:20:36
А как вывести элементы, которые привязаны к нескольким разделам? Сейчас выводятся только те, которые находятся в одном разделе
Максим
17.01.2017 06:37:04
В коде берется основной раздел IBLOCK_SECTION_ID, а вам нужно добавить цикл - обход всех разделов элемента. Получить их можно с помощью:
CIBlockElement::GetElementGroups
Авель
17.01.2017 10:48:02
Асем
14.02.2017 10:01:25
Виктор
01.04.2017 19:34:07
Максим
02.04.2017 06:57:22
Информация о про создание кастомных типов свойств ИБ
Виктор, за подсвечивание отвечает компонент menu, в данном примере мы делаем компонент menu_ext - который только добавляет в меню пункты.
Степан
03.09.2017 19:44:29
Максим
26.01.2018 15:43:55
Ulugbek Pulatov
14.03.2018 10:25:25
есть раздел services в меню который тянет всю информацию с инфоблока - я его закрыл добавив в коней папки /index.php
теперь стоит задача вытащить в подпункт только нужные папки... ручная правка левого меню дает результат только с боковой позиции.. на главную не выходить...
что можно сделать пожалуйста подскажите
Николай
07.06.2018 08:06:13
Подскажите,а как можно реализовать загрузку пунктов меню только по указанному разделу инфоблока?
Желательно чтобы можно было в коде файла меню указывать раздел инфоблока, например добавив SECTION_ID:
[...Код вырезал для экономии места...]
К сожалению не очень дружу с php, если можно покажите пример кода.
Николай
07.06.2018 09:23:14
[...Много кода вырезал для экономии места...]
Максим
07.06.2018 11:28:38
1. Получаете родительский раздел по SECTION_ID, у него получаете поля LEFT_MARGIN, RIGHT_MARGIN.
2. Получаете подразделы данного раздела учитывая что LEFT_MARGIN раздела-потомка > LEFT_MARGIN раздела-родителя и RIGHT_MARGIN раздела-потомка < RIGHT_MARGIN раздела-родителя.
Вот ссылка на пример на сайте битрикса: https://dev.1c-bitrix.ru/api_help/iblock/classes/ciblocksection/getlist.php#ex4
Николай
07.06.2018 11:42:10
Вариантов фильтрации наверняка есть множество, к сожалению я не могу понять как их применить к конкретному коду компонента.
Честно говоря уже методом тыка ставил разные условия в разные места кода, но ничего не выходит, увы знаний не хватает...(((
Николай
08.06.2018 04:44:41
НО те меню в параметрах меню НЕ указан подраздел, т.к. там фильтрация по нему не нужна, не заполняются.
Как сделать, чтобы фильтр работал только когда в параметрах задан подраздел?
Сейчас код у меня выглядит так:
Максим
08.06.2018 05:50:19
Там где получаете основной фильтр $arFilter (после if($this->StartResultCache()) )
уберите из фильтра LEFT_MARGIN, RIGHT_MARGIN, а сразу ниже добавьте условие: если заполнен $arParams['SECTION_ID'], то получаем LEFT_MARGIN, RIGHT_MARGIN и добавляем в фильтр. Будет примерно так:
PS из начала убираем [ВАШ БЛОК С ПОЛУЧЕНИЕМ LEFT_MARGIN, RIGHT_MARGIN]
Николай
08.06.2018 06:23:43
if ($arParams['SECTION_ID']){
[ВАШ БЛОК С ПОЛУЧЕНИЕМ LEFT_MARGIN, RIGHT_MARGIN]
//подставляем их в фильтр
$arFilter['>LEFT_MARGIN'] = $arLM;
$arFilter['<RIGHT_MARGIN '] = $arRM;
}
тоже самое, если указан раздел первого уровня то работает, если второго и последующих тогда меню не формируется.
Максим
08.06.2018 06:28:29
вот эту строку замените:
на
Николай
08.06.2018 06:49:32
Не выводятся пункты меню на странице раздела
14.01.2019 15:20:25
Добавил меню в шаблон обеих страниц. Оба шаблона для этих страниц лежат в корне сайта, рядом с ними же лежат файлы .left.menu_ext.php и .left.menu.php. Меню нормально выводится на странице элемента, и не выводит все пункты на странице раздела...
В чем может быть причина?
Trioka
20.02.2021 20:49:48
Максим
08.04.2021 10:43:20
Евгений
11.07.2021 22:23:01
Сергей
31.08.2021 23:58:39
Не получается использовать ваш компонент.
лог ошибок:
[Error]
Undefined constant "createMenuArray" (0)
/home/c/cb54090/public_html/bitrix/components/leftmenu/menu.sections.elements/component.php:2
#0: include
/home/c/cb54090/public_html/bitrix/modules/main/classes/general/component.php:605
#1: CBitrixComponent->__includeComponent()
/home/c/cb54090/public_html/bitrix/modules/main/classes/general/component.php:682
#2: CBitrixComponent->includeComponent(string, array, boolean, boolean)
/home/c/cb54090/public_html/bitrix/modules/main/classes/general/main.php:1068
#3: CAllMain->IncludeComponent(string, string, array, boolean, array)
/home/c/cb54090/public_html/.left.menu_ext.php:33
#4: include(string)
/home/c/cb54090/public_html/bitrix/modules/main/classes/general/menu.php:115
#5: CMenu->Init(string, boolean, string)
/home/c/cb54090/public_html/bitrix/components/bitrix/menu/component.php:53
#6: include(string)
/home/c/cb54090/public_html/bitrix/modules/main/classes/general/component.php:605
#7: CBitrixComponent->__includeComponent()
/home/c/cb54090/public_html/bitrix/modules/main/classes/general/component.php:103
#8: CBitrixComponent->executeComponent()
/home/c/cb54090/public_html/bitrix/modules/main/classes/general/component.php:658
#9: CBitrixComponent->includeComponent(string, array, boolean, boolean)
/home/c/cb54090/public_html/bitrix/modules/main/classes/general/main.php:1068
#10: CAllMain->IncludeComponent(string, string, array, boolean)
/home/c/cb54090/public_html/bitrix/templates/gidrosv/header.php:141
#11: include_once(string)
/home/c/cb54090/public_html/bitrix/modules/main/include/prolog_after.php:106
#12: require(string)
/home/c/cb54090/public_html/bitrix/modules/main/include/prolog.php:11
#13: require_once(string)
/home/c/cb54090/public_html/bitrix/header.php:1
#14: require(string)
/home/c/cb54090/public_html/index.php:2
Подскажите куда копать?
Максим
01.09.2021 08:38:33
if (!function_exists('createMenuArray')){
createMenuArray возьмите в кавычки.
Сам пример исправил.
Ошибка зависит от конфигурации php, но кавычки здесь должны были быть изначально, упустил.
Андрей
25.03.2022 19:28:26
У меня получились ссылки ввида: /IDкатегории/IDвложенной категории/
Но если есть вложенная категория почему-то нет ссылки на родительскую категорию (только ее название). В чем проблема?
Здравствуйте!
12.03.2024 23:55:19
Оставить комментарий: