весь список раздела "Модули, компоненты, файлы"
Пользовательский тип свойства инфоблока в виде списка разделов с чекбоксами для выбора.
Код нужно разместить в "local/php_interface/init.php" или "/bitrix/php_interface/init.php".
Для свойства надо выбрать тип "Привязка к разделам (список чекбоксов)". Обязательно должна быть отметка "Множественное".
php
// Регистрация кастомного свойства
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
'iblock',
'OnIBlockPropertyBuildList',
['CUserTypeSectionCheckboxes', 'GetUserTypeDescription']
);
class CUserTypeSectionCheckboxes
{
public static function GetUserTypeDescription()
{
return [
'PROPERTY_TYPE' => 'G', // Базовый тип "Привязка к разделам"
'USER_TYPE' => 'SectionCheckboxes',
'DESCRIPTION' => 'Привязка к разделам (список чекбоксов)',
'CLASS_NAME' => __CLASS__,
// Переопределяем вывод для множественного свойства
'GetPropertyFieldHtmlMulty' => [__CLASS__, 'GetPropertyFieldHtmlMulty'],
'GetPropertyFieldHtml' => [__CLASS__, 'GetPropertyFieldHtml'],
];
}
// Этот метод вызывается, если у свойства СНЯТ флаг "Множественное"
public static function GetPropertyFieldHtml($arProperty, $arValue, $strHTMLControlName)
{
return self::renderCheckboxes($arProperty, [$arValue['VALUE']], $strHTMLControlName['VALUE']);
}
// Этот метод вызывается, если у свойства СТОИТ флаг "Множественное"
public static function GetPropertyFieldHtmlMulty($arProperty, $arValues, $strHTMLControlName)
{
$selectedValues = [];
if (is_array($arValues)) {
foreach ($arValues as $val) {
if (!empty($val['VALUE'])) {
$selectedValues[] = $val['VALUE'];
}
}
}
return self::renderCheckboxes($arProperty, $selectedValues, $strHTMLControlName['VALUE']);
}
// Общая функция отрисовки HTML
private static function renderCheckboxes($arProperty, $arSelected, $inputName)
{
// Определяем, из какого инфоблока брать разделы.
// По умолчанию берется инфоблок, указанный в настройках связи свойства (LINK_IBLOCK_ID)
// Если он пустой, берем текущий инфоблок свойства.
$iblockId = intval($arProperty['LINK_IBLOCK_ID']) > 0
? intval($arProperty['LINK_IBLOCK_ID'])
: intval($arProperty['IBLOCK_ID']);
if ($iblockId <= 0) {
return '<em>Ошибка: не задан ID инфоблока для связи.</em>';
}
// Получаем все разделы инфоблока с сохранением иерархии (сортировка по left_margin)
$dbRes = \CIBlockSection::GetList(
['left_margin' => 'asc'],
['IBLOCK_ID' => $iblockId, 'ACTIVE' => 'Y'],
false,
['ID', 'NAME', 'DEPTH_LEVEL']
);
$html = '<div style="max-height: 250px; min-width: 300px; overflow-y: auto; border: 1px solid #c8d1d6; padding: 8px; background: #fff; border-radius: 4px;">';
// Скрытый input, чтобы при снятии всех чекбоксов Битрикс понимал, что свойство нужно очистить
$html .= '<input type="hidden" name="'.$inputName.'[]" value="">';
$hasSections = false;
while ($arSection = $dbRes->Fetch()) {
$hasSections = true;
$checked = in_array($arSection['ID'], $arSelected) ? ' checked' : '';
// Визуальный отступ для вложенных разделов
$margin = ($arSection['DEPTH_LEVEL'] - 1) * 20;
$html .= '<div style="margin-left: '.$margin.'px; margin-bottom: 5px; white-space: nowrap;">';
$html .= '<label style="cursor: pointer; display: inline-flex; align-items: center; gap: 5px;">';
$html .= '<input type="checkbox" name="'.$inputName.'[]" value="'.$arSection['ID'].'"'.$checked.'>';
$html .= htmlspecialcharsbx($arSection['NAME']);
$html .= '</label>';
$html .= '</div>';
}
if (!$hasSections) {
$html .= '<span style="color: #888;">В выбранном инфоблоке нет разделов.</span>';
}
$html .= '</div>';
return $html;
}
}