Программная работа с разделами каталога в Битрикс: от простого к сложному

Раздел: CMS -> 1С-Битрикс

Обзор методов получения разделов инфоблока в 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();
}
Раздел обновлен успешно

1С-Битрикс каталог разделов PHP - comments

En
Bitrix catalog sections php (php)