Понедельник, 28 Январь 2013 18:31

Битрикс. Делаем полноценное меню из компонента «Структура разделов»

Оцените материал
(6 голосов)

Что-то давно я сюда не писал. Сегодня мы будем превращать стандартный компонент «Структура разделов» (bitrix:catalog.section.list) в полноценное многоуровневое меню. И отдельно поговорим о том, как из него же сделать аккордеон с определением вложенности пункта (если есть вложенные уровни, ссылка будет href="#" — для того, чтобы ваш аккордеон можно было раскрыть не уходя на другую страницу), а так же залипанием текущего пункта. Такой в точности аккордеон можно увидеть на скриншоте ниже:

Структура разделов - меню

Собственно, этот вопрос передо мной встал совсем недавно, и когда я не нашел ни одного решения на просторах рунета, решил стать первым. Ну, может быть, одним из первых, кто написал про это.

Итак, что нам надо:

  1. Скачанный архив с выпадающим меню или написанный скрипт собственноручно.
  2. Битрикс любой редакции.
  3. Инфоблок с разделами, жеательно с деревом разделов типа:
    -Раздел
    --Подраздел
    --Подраздел
    -Раздел
    -Раздел
  4. Вставленный в шаблон или контентную часть компонент «Структура разделов» (catalog.section.list) с новым шаблоном скопированным с дефолтного шаблона .default (Настройки > Структура разделов (bitrix:catalog.section.list) > Копировать шаблон компонента)
  5. IQ >= 50 :)

Итак, для начала нам нужно понять как работает и что выдает нетронутый catalog.section.list, какая структура у многоуровневого меню, то есть, к какому html-виду на выходе нужно привести нашу структуру разделов.

Вот конструкция, котрую нам выдает компонент Битрикса:

Показать/скрыть html4strict код

Посмотреть код
  1. <ul>
  2. <li>Родительский раздел</li>
  3. <ul>
  4. <li>Субсекция</li>
  5. <li>Субсекция</li>
  6. </ul>
  7. <li>Родительский раздел</li>
  8. <li>Текущий раздел</li>
  9. </ul>

А нам нужна несколько иная конструкция:

Показать/скрыть html4strict код

Посмотреть код
  1. <ul>
  2. <li>Родительский раздел
  3. <ul>
  4. <li>Субсекция</li>
  5. <li>Субсекция</li>
  6. </ul></li>
  7. <li>Родительский раздел</li>
  8. <li class="active">Текущий раздел</li>
  9. </ul>

Вывод: нам не хватает во-первых вложения ul-списка субсекций перед закрываюим тегом </li> родительского раздела. Во-вторых, не хватает добавления класса active к текщему пункту меню (структуры разделов каталога).

Теперь давайте разбираться как нам реализовать все это дело.

Начнем со сложного и несколько неудобного способа.

Казалось бы, зачем? А затем, что с этим способом можно вывести много больше фишек, чем описанным во второй части статьи (без гемора картинки категории, анонс описания и многое другое).

Если мы заглянем в массив, дабы увидеть название ячейки, в которой было бы указано какой тут раздел родительский, а какой детский (ну, или как он там правильно у контент-менеджеров называется), то дико обломаемся. Ничего такого вы там не увидите. Только уровень вложенности и никаких привязок друг к другу. Знаете как заглядывать в массив? Нет? Попробуйте в шаблоне, сразу после <?if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>  вставить это:

Показать/скрыть php код

Посмотреть код
<pre>
<?php
print_r ($arResult);
?>
</pre>

После чего, откройте сайт и посмотрите что получилось, и сразу же запишитесь на курсы php Подмигиваю

У меня было очень мало времени на разборки, поэтому был выбран такой путь: заходим в редактирование разделать щелкаем по вкладке «Доп. свойства», нажимаем на ссылку «Добавить пользовательское свойство», добавляем свойство типа «Список», в настройках ставим «Флажки», называем его «Есть ли вложенные секции?», код пусть будет UF_CHECK и присваиваем значение одному единственному флажку «да» (вкладка «Список» сверху). Умолчание оставляем как есть.

Далее, когда будем заполнять — если у категории есть субсекции, ставим «Да», если нет — не трогаем.

Теперь будем внедрять.

Ищем строку:

Показать/скрыть php код

Посмотреть код
echo str_repeat("</ul>", $CURRENT_DEPTH — $arSection["DEPTH_LEVEL"]);

и дополняем ее закрывающим </li>:

Показать/скрыть php код

Посмотреть код
echo str_repeat("</ul></li>", $CURRENT_DEPTH — $arSection["DEPTH_LEVEL"]);

Далее заменим строку

Показать/скрыть php код

Посмотреть код
<li id="<?=$this->GetEditAreaId($arSection[’ID’]);?>"><a href="<?=$arSection["SECTION_PAGE_URL"]?>"><?=$arSection["NAME"]?><?if($arParams["COUNT_ELEMENTS"]):?>&nbsp;(<?=$arSection["ELEMENT_CNT"]?>)<?endif;?></a></li>

если у вас подключается аккордеон, в котором ссылка раскрывающегося пункта должна быть #, то на вот такую:

Показать/скрыть php код

Посмотреть код
<li<? if(strstr($_SERVER["REQUEST_URI"],$arSection["CODE"])): ?> class="active"<? endif ?> id="<?=$this->GetEditAreaId($arSection[’ID’]);?>"><a href="<?if($arSection["UF_CHECK"]):?>#<?else:?><?=$arSection["SECTION_PAGE_URL"]?><?endif?>"><?=$arSection["NAME"]?></a><?if(!$arSection["UF_CHECK"]):?></li><?endif?>

если решетка не нужна или это будет просто выпадающее меню, то пишем вот так:

Показать/скрыть php код

Посмотреть код
<li<? if(strstr($_SERVER["REQUEST_URI"],$arSection["CODE"])): ?> class="active"<? endif ?> id="<?=$this->GetEditAreaId($arSection[’ID’]);?>"><a href="<?=$arSection["SECTION_PAGE_URL"]?>"><?=$arSection["NAME"]?></a><?if(!$arSection["UF_CHECK"]):?></li><?endif?>

Далее подключите к шаблону сайта css и js-скрипты, при необходимости допишите нужные дивы в шаблон компонента (например, если будете использовать приложенный к статье аккордеон, вам нужно будет заменить <div class="catalog-section-list"> на <div class="topnav">). Все должно работать как надо. Текущий пункт залипает, список формируется как нам надо. Недостатки — сортировка пунктов по алфавиту. Чтобы этого избежать, просто расствьте как вам надо индекс сортировки при заполнении разделов, а так же доп. свойство, которое прийдется иногда проставлять. Но на самом деле это не так уж и страшно. Доп свойство заполняется менее секунды, к тому же, если используете эксель для формирования импорта, проставление значений для UF_CHECK можно автоматизировать при помощи банальных формул.

Продолжим более легким, без изменения шаблона и использования компонента bitrix:catalog.section.list.

Мы делаем полноценное меню? Нам не нужен геморрой? Давайте и сделаем меню, используя компонент меню (кэп, спасибо за подсказку)!

Если посмотреть настройки bitrix:menu, то можно увидеть интересную галочку Подключать файлы с именами вида .тип_меню.menu_ext.php. Это и есть наш ключ к успеху. Запомните его и идите в Настройки -> Настройки продукта -> Настройки модулей -> Управление структурой, создавайте новый тип меню, специально для каталога, например, тип — cat, название — Разделы каталога. 

Далее создайте файлик в корне сайта (или в папку, если меню вывдоить будем не во всех разделах) и создайте там файлы .cat.menu.php и .cat.menu_ext.php, опосля чего в нужное место шаблона сайта вонзите сам компонент меню и укажите в настройках тип для первого уровня Разделы каталога. Поставьте нужное количество уровней меню, тип меню для остальных уровней оставьте таким же, как и для первого. Не забудьте про Подключать файлы с именами вида .тип_меню.menu_ext.php.

Справились? Молодцы. Открываем тот самый .cat.menu_ext.php в любимом php-редакторе и запиливаем в него такой хитрый, на первый взгляд, код:

Показать/скрыть php код

Посмотреть код
  1. <?php
  2. if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
  3.  
  4. global $APPLICATION;
  5.  
  6. $aMenuLinksExt = $APPLICATION->IncludeComponent(
  7. "bitrix:menu.sections",
  8. "",
  9. Array(
  10. "IS_SEF" => "N",
  11. "ID" => $_REQUEST["ID"],
  12. "IBLOCK_TYPE" => "catalog", // Введите сюда символьный код или ИД типа ИБ, в котором лежит инфоблок каталога
  13. "IBLOCK_ID" => "1", // Укажите тут реальный ID инфоблока, с которым вы связываете меню, то бишь, каталога
  14. "SECTION_URL" => "/catalog/#SECTION_ID#/", //Обратите внимание на то, что если у вас чпу направлены на код, то ставьте SECTION_CODE
  15. "DEPTH_LEVEL" => "2", // Сколько надо уровней меню, такую цифру и пишите
  16. "CACHE_TYPE" => "N", // Кэш. Надо или не надо? Думайте сами, решайте сами!
  17. "CACHE_TIME" => "36000000" // Сколько секунд будет жить кэш. В данном случае немногим меньше, чем полтора года
  18. ),
  19. false
  20. );
  21. $aMenuLinks = array_merge($aMenuLinks, $aMenuLinksExt);
  22. ?>

И это не все еще, хотя, проверить работу уже можно. Давайте заморочимся с шаблоном. Нам-то нужно чтобы в верхних уровнях меню стола решетка (это для тех, кому нужна решетка).

Долго расписывать не буду. Для корректной работы скачанного в начале статьи аккордеона, она нужна, и вам подойдет вот такой код шаблона компонента меню:

Показать/скрыть php код

Посмотреть код
  1. <?if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>
  2. <div class="sections">
  3. <ul>
  4. <?
  5. $previousLevel = 0;
  6. foreach($arResult as $arItem):
  7. ?>
  8.     <? if ($previousLevel && $arItem["DEPTH_LEVEL"] < $previousLevel): ?>
  9.         <?=str_repeat("</ul></li>", ($previousLevel - $arItem["DEPTH_LEVEL"]));?>
  10.     <? endif ?>
  11.     <? if ($arItem["IS_PARENT"]): ?>
  12.             <li<? if($arItem["SELECTED"]): ?> class="active"<? endif ?>><a href="#"><?=$arItem["TEXT"]?></a>//Вот, попалась решетка в первом уровне. Если она не нужна вам тут, на этом месте вместо диеза в хрефе ставьте <?=$arItem["LINK"]?>
  13.                 <ul>
  14.     <? else: ?>
  15.                 <li<? if($arItem["SELECTED"]): ?> class="active"<? endif ?>><a href="<?=$arItem["LINK"]?>"><?=$arItem["TEXT"]?></a></li>
  16.     <? endif ?>
  17.     <? $previousLevel = $arItem["DEPTH_LEVEL"] ?>
  18. <? endforeach ?>
  19. <? if ($previousLevel > 1):?>
  20.     <?=str_repeat("</ul></li>", ($previousLevel-1) );?>
  21. <? endif ?>
  22. </ul>
  23. </div>

На этом все. Надеюсь, эта статья поможет вам. Приветствуются альтернативные способы реализации в комментариях.

Прочитано 13595 раз
Твитнуть
Другие материалы в этой категории: « Простая многосайтовость Битрикса

Комментарии   

 
Сергей С
0 #11 Сергей С 07.11.2014 20:20
Разобрался. Ответ нашел тут: http://bx-qa.com/?qa=38878/количество-элементов-в-разделе
Цитировать
 
 
Сергей С
0 #10 Сергей С 07.11.2014 19:44
Огромное спасибо за статью! Очень помогло! Подскажите, как добавить количество элементов инфоблока рядом с пунктами меню? Во втором способе это не предусмотрено.
Цитировать
 
 
nix
-1 #9 nix 24.05.2014 18:02
Можно использовать конструкцию:
class = "active" не переделывая шаблон.
Цитировать
 
 
pechatny
0 #8 pechatny 06.09.2013 15:45
Спасибо
Цитировать
 
 
СветеКа
+3 #7 СветеКа 26.06.2013 02:49
li id=""

a href="/" class="active""

но класс active в ссылку не передается. Подскажите, пожалуйста, что не так? Спасибо!
Цитировать
 
 
СветеКа
0 #6 СветеКа 26.06.2013 02:48
Артем, здравствуйте!

Пытаюсь воспользоваться Вашим кодом, но класс active у меня должен присваиваться к ссылке. Поэтому я записала:
Цитировать
 
 
Артем
0 #5 Артем 07.05.2013 12:51
Девятый дизайнер, спасибо! Внимания не обращал. Буду писать третий способ, когда найду время :)
Цитировать
 
 
девятый дизайнер
0 #4 девятый дизайнер 06.05.2013 19:47
хм... немного не так (часть кода что-ли не пропускает)
if($activeitemidRIGHT =$arSection["LE FT_MARGIN"])
Цитировать
 
 
девятый дизайнер
0 #3 девятый дизайнер 06.05.2013 19:44
Ну а дальше скажем так... Автор статьи думаю поправит если что не так.

Узнаем параметры текущего раздела:

foreach($arResult["SECTIONS"] as $arSection)
{
if($_REQUEST["SECTION_ID"]==$arSection["ID"])
{
$activeitemidRIGHT = $arSection["RIGHT_MARGIN"];
$activeitemidLEFT = $arSection["LEFT_MARGIN"];
}
}

Сравниваем, и выводим нужный класс всем родителям оп текущей ветке:

foreach($arResult["SECTIONS"] as $arSection)
{
if($activeitemidRIGHT =$arSection["LEFT_MARGIN"])
{
$classactiveite m = " ItemsACT";
}
else
{
$classactiveite m = "";
}
}
Цитировать
 
 
девятый дизайнер
0 #2 девятый дизайнер 06.05.2013 19:43
За статью спасибо, помогло. Только немного хочу дополнить тем, что сам раскопал.

- "Только уровень вложенности и никаких привязок друг к другу...."

Ну тут можно обратить внимание на два параметра из массива:
$arSection["RIGHT_MARGIN"]
$arSection["LEFT_MARGIN"]

Помогает отследить самого верхнего родителя.

например с лева в скобках LEFT_MARGIN с права RIGHT_MARGIN:

(1) item-111 (8)

(2) item-111111 (3)

(4) item-111222 (7)

(5) item-111222333 (6)

(9) item-222 (12)

(10) item-222111 (11)
Цитировать
 
 
Shiki
0 #1 Shiki 14.04.2013 21:04
Огромное спасибо за статью) очень помогла)
Могли бы вы чуть подробнее рассказать про индекс сортировки?
Цитировать
 

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

Защитный код
Обновить

joomla 1.7

Не получаются доработки?

Становитесь партнером студии Millor! Быстро и недорого эти ребята помогут решить практически любую проблему.

Хотите подзаработать?

Если да, то вам сюда! Партнерская программа студии MyWebSite. Получи 20% за каждого клиента! Работаем по всей России и СНГ!

Рекламное место свободно.