Программная работа с разделами каталога в Битрикс: от простого к сложному
Обзор методов получения разделов инфоблока в 1С-Битрикс
Как получить список разделов инфоблока с минимальными затратами?
Наиболее эффективное решение – использование метода CIBlockSection::GetList с правильной фильтрацией и сортировкой. Оно позволяет гибко выбирать поля, применять условия по коду, ID, активности и управлять порядком вывода.
// Пример получения активных разделов каталога ID=2, отсортированных по сортировке
$arFilter = array(
'IBLOCK_ID' => 2,
'ACTIVE' => 'Y'
);
$arSelect = array(
'ID',
'NAME',
'CODE',
'SORT',
'DEPTH_LEVEL',
'IBLOCK_SECTION_ID',
'SECTION_PAGE_URL'
);
$arOrder = array('SORT' => 'ASC', 'NAME' => 'ASC');
$rsSections = CIBlockSection::GetList($arOrder, $arFilter, false, $arSelect);
while ($arSection = $rsSections->Fetch())
{
echo '<li>' . $arSection['NAME'] . ' (ID: ' . $arSection['ID'] . ')</li>';
}
Bitrix catalog sections php (1с-битрикс каталог разделов php)
Типичная ошибка: забыли указать третий параметр (false) – подсчёт количества элементов, из-за чего метод ведёт себя иначе. Вместо выборки возвращается количество элементов. Также часто путают порядок параметров – первым идёт сортировка, вторым фильтр.
Как исправить: всегда явно передавать false в третьем параметре, если подсчёт не нужен. Проверять последовательность аргументов по документации.
Как вывести дерево разделов с учётом вложенности?
Для построения иерархического дерева удобно использовать параметр 'DEPTH_LEVEL' в фильтре или обрабатывать все разделы одного уровня и рекурсивно собирать подразделы. Альтернатива – компонент bitrix:catalog.section.list, который отдаёт готовое дерево.
// Рекурсивный сбор разделов (без использования компонента)
function getSectionsTree($iblockId, $parentId = false, $depth = 1) {
$arFilter = array(
'IBLOCK_ID' => $iblockId,
'ACTIVE' => 'Y',
'DEPTH_LEVEL' => $depth
);
if ($parentId !== false) {
$arFilter['SECTION_ID'] = $parentId;
$arFilter['INCLUDE_SUBSECTIONS'] = 'N';
}
$arOrder = array('SORT' => 'ASC');
$arSelect = array('ID', 'NAME', 'DEPTH_LEVEL', 'IBLOCK_SECTION_ID');
$rs = CIBlockSection::GetList($arOrder, $arFilter, false, $arSelect);
$tree = array();
while ($section = $rs->Fetch()) {
$section['CHILDREN'] = getSectionsTree($iblockId, $section['ID'], $depth + 1);
$tree[] = $section;
}
return $tree;
}
$sections = getSectionsTree(2);
foreach ($sections as $s) { echo '<li>' . $s['NAME'] . ' (' . count($s['CHILDREN']) . ' подраздела)</li>'; }
битрикс php скриптов (php скрипты для 1с-битрикс)
Проблема: рекурсивный вызов может создать много запросов к БД, особенно при большом количестве уровней. Это снижает производительность.
Решение: использовать кэширование результата (в памяти или файловое) или получить одним запросом все разделы инфоблока и построить дерево на PHP.
Как получить разделы каталога через ORM (Bitrix\Iblock\SectionTable)?
С версии 15.0.0 доступна работа с таблицей разделов через ORM. Метод SectionTable::getList позволяет использовать D7-подобный синтаксис, включая фильтры, выборку и связи.
use Bitrix\Iblock\SectionTable;
$sections = SectionTable::getList(array(
'select' => array('ID', 'NAME', 'CODE', 'IBLOCK_SECTION_ID', 'DEPTH_LEVEL'),
'filter' => array('IBLOCK_ID' => 2, 'ACTIVE' => 'Y'),
'order' => array('SORT' => 'ASC', 'NAME' => 'ASC'),
'cache' => array('ttl' => 3600)
))->fetchAll();
foreach ($sections as $s) { echo $s['NAME'] . '<br>'; }
Bitrix section php (1с-битрикс раздел php)
Сложность: при использовании ORM требуется подключение пространства имён, новички часто забывают объявить use. Также ORM возвращает объекты, и при неправильной конфигурации может потребоваться дополнительная обработка.
Подсказка: всегда проверяйте наличие модуля и версию ядра – ORM доступна в редакциях «Старт» и выше.
Как вывести разделы с постраничной навигацией?
Для разбивки списка на страницы используйте CIBlockSection::GetList в сочетании с CDBResult::NavPageCount и NavStart.
$arFilter = array('IBLOCK_ID' => 2, 'ACTIVE' => 'Y');
$arSelect = array('ID', 'NAME');
$arOrder = array('SORT' => 'ASC');
$rsSections = CIBlockSection::GetList($arOrder, $arFilter, false, $arSelect);
$rsSections->NavStart(10); // 10 разделов на страницу
echo $rsSections->NavPrint('Разделы');
while ($arSection = $rsSections->NavNext(true, "s_")) {
echo $arSection['NAME'] . '<br>';
}
echo $rsSections->NavPrint('Разделы');
Ошибка: после вызова NavStart необходимо использовать NavNext для корректного извлечения данных, иначе постраничная навигация не сработает или будет дублироваться.
Как получить количество элементов в каждом разделе без лишних запросов?
Метод CIBlockSection::GetList позволяет передать true в третьем параметре – подсчёт элементов. Так сразу в выборку добавляется поле ELEMENT_CNT.
$arFilter = array('IBLOCK_ID' => 2, 'ACTIVE' => 'Y');
$arSelect = array('ID', 'NAME', 'ELEMENT_CNT');
$rsSections = CIBlockSection::GetList(array('SORT' => 'ASC'), $arFilter, true, $arSelect);
while ($arSection = $rsSections->Fetch()) {
echo $arSection['NAME'] . ' - ' . $arSection['ELEMENT_CNT'] . ' товаров<br>';
}
Внимание: подсчёт элементов (третий параметр = true) замедляет запрос, так как выполняется вложенный SQL-запрос. Используйте только когда это действительно необходимо.
Дополнительные советы:
- Всегда используйте кэширование (например, CPHPCache), особенно при построении дерева разделов.
- Для фильтрации по URL кода используйте '=CODE' в фильтре.
- Не забывайте указывать 'IBLOCK_ID', чтобы не получить разделы из других инфоблоков.
- При работе с большим количеством разделов (более 500) рассмотрите использование пакетной обработки (CDBResult::NavNext в цикле).
Расширенные примеры работы с разделами
Пример 1: Вывод разделов с полной иерархией за один SQL-запрос и построение дерева на PHP.
$iblockId = 2;
$rs = CIBlockSection::GetList(
array('LEFT_MARGIN' => 'ASC'),
array('IBLOCK_ID' => $iblockId, 'ACTIVE' => 'Y'),
false,
array('ID', 'NAME', 'DEPTH_LEVEL', 'LEFT_MARGIN', 'RIGHT_MARGIN', 'IBLOCK_SECTION_ID')
);
$sections = array();
while ($ar = $rs->Fetch()) {
$ar['CHILDREN'] = array();
$sections[$ar['ID']] = $ar;
}
// Построение дерева по ссылкам
$tree = array();
foreach ($sections as $id => &$section) {
if ($section['IBLOCK_SECTION_ID'] > 0) {
$sections[$section['IBLOCK_SECTION_ID']]['CHILDREN'][] = &$section;
} else {
$tree[] = &$section;
}
}
unset($section);
print_r($tree);
Array
(
[0] => Array
(
[ID] => 10
[NAME] => Одежда
[DEPTH_LEVEL] => 1
[IBLOCK_SECTION_ID] => 0
[CHILDREN] => Array
(
[0] => Array
(
[ID] => 15
[NAME] => Платья
[DEPTH_LEVEL] => 2
[IBLOCK_SECTION_ID] => 10
[CHILDREN] => Array()
)
)
)
)
Пример 2: Использование SectionTable::getList с фильтром по коду и пагинацией.
use Bitrix\Main\Entity\Query;
use Bitrix\Iblock\SectionTable;
$query = new Query(SectionTable::getEntity());
$query->setSelect(array('ID', 'NAME', 'CODE'));
$query->setFilter(array('IBLOCK_ID' => 2, '=CODE' => 'odezhda'));
$query->setLimit(5);
$result = $query->exec();
while ($row = $result->fetch()) {
echo 'Код: ' . $row['CODE'] . ' - ' . $row['NAME'] . '<br>';
}
Код: odezhda - Одежда
Пример 3: Получение раздела по символьному коду и вывод его полного пути.
// Функция для получения цепочки родителей
function getSectionChain($iblockId, $sectionCode) {
$rs = CIBlockSection::GetList(
array(),
array('IBLOCK_ID' => $iblockId, '=CODE' => $sectionCode, 'ACTIVE' => 'Y'),
false,
array('ID', 'IBLOCK_SECTION_ID', 'NAME', 'CODE')
);
if ($section = $rs->Fetch()) {
$chain = array($section);
// Получаем родителей рекурсивно
$parentId = $section['IBLOCK_SECTION_ID'];
while ($parentId > 0) {
$rsParent = CIBlockSection::GetByID($parentId);
if ($parent = $rsParent->Fetch()) {
$chain[] = $parent;
$parentId = $parent['IBLOCK_SECTION_ID'];
} else {
break;
}
}
return array_reverse($chain);
}
return array();
}
$chain = getSectionChain(2, 'platya');
foreach ($chain as $s) {
echo $s['NAME'] . ' > ';
}
Одежда > Платья >
Пример 4: Применение кэширования при получении списка разделов.
$cache = new CPHPCache();
$cacheTime = 3600;
$cacheId = 'sections_iblock_2';
$cacheDir = '/sections/';
if ($cache->InitCache($cacheTime, $cacheId, $cacheDir)) {
$vars = $cache->GetVars();
$arSections = $vars['SECTIONS'];
} else {
$arSections = array();
$rs = CIBlockSection::GetList(
array('SORT' => 'ASC'),
array('IBLOCK_ID' => 2, 'ACTIVE' => 'Y'),
false,
array('ID', 'NAME', 'CODE', 'IBLOCK_SECTION_ID', 'DEPTH_LEVEL')
);
while ($ar = $rs->Fetch()) {
$arSections[] = $ar;
}
$cache->StartDataCache($cacheTime, $cacheId, $cacheDir);
$cache->EndDataCache(array('SECTIONS' => $arSections));
}
// Далее работаем с $arSections
print_r($arSections);
Array
(
[0] => Array
(
[ID] => 10
[NAME] => Одежда
[CODE] => odezhda
[IBLOCK_SECTION_ID] => 0
[DEPTH_LEVEL] => 1
)
[1] => Array
(
[ID] => 15
[NAME] => Платья
[CODE] => platya
[IBLOCK_SECTION_ID] => 10
[DEPTH_LEVEL] => 2
)
)
Пример 5: Фильтрация разделов по пользовательскому свойству (UFL) с помощью CIBlockSection::GetList.
$arFilter = array(
'IBLOCK_ID' => 2,
'ACTIVE' => 'Y',
'PROPERTY_SPECIAL_OFFER' => 'Y' // предположим, есть свойство SPECIAL_OFFER типа "Да/Нет"
);
$rs = CIBlockSection::GetList(array('SORT' => 'ASC'), $arFilter, false, array('ID', 'NAME'));
while ($ar = $rs->Fetch()) {
echo $ar['NAME'] . '<br>';
}
Распродажа
Пример 6: Обновление раздела через CIBlockSection::Update с проверкой ошибок.
$fields = array(
'NAME' => 'Новое название раздела',
'SORT' => 500
);
$res = CIBlockSection::Update(10, $fields); // ID раздела = 10
if ($res) {
echo 'Раздел обновлен успешно';
} else {
global $APPLICATION;
$strError = $APPLICATION->GetException();
echo 'Ошибка: ' . $strError->GetString();
}
Раздел обновлен успешно