BITRIX: получить свойства элементов любого инфоблока в любом месте и любом шаблоне

Главное: массив вида $arResult['PROPERTIES'] формируется компонентами Битрикс (например, news.detail, catalog.element) и доступен внутри их шаблонов. В «любом месте» сайта этого массива нет по умолчанию — нужно самостоятельно запросить элемент(ы) инфоблока через API D7 (CIBlockElement/CIBlockSection или ORM) и выбрать нужные свойства.

Ниже — проверенные способы, которые можно использовать в любом шаблоне, компоненте, include-области, result_modifier.php, header/footer, а также в произвольном PHP-файле при условии корректной инициализации пролога.

1) Базовый вариант: CIBlockElement::GetList + GetNextElement

Подходит, если нужен 1 элемент (например, «настройки сайта» в отдельном ИБ) или небольшая выборка.

PHP
<?php
use Bitrix\Main\Loader;

require($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_before.php');
Loader::includeModule('iblock');

$iblockId = 10;          // ID инфоблока
$elementId = 123;        // ID элемента
$arSelect = [
    'ID', 'IBLOCK_ID', 'NAME', 'CODE', 'ACTIVE', 'DETAIL_TEXT', 'DETAIL_PICTURE'
    // Свойства отдельно не указываются — получим их через GetProperties()
];
$arFilter = ['IBLOCK_ID' => $iblockId, 'ID' => $elementId, 'ACTIVE' => 'Y'];
$res = CIBlockElement::GetList([], $arFilter, false, ['nTopCount' => 1], $arSelect);

if ($ob = $res->GetNextElement()) {
    $fields = $ob->GetFields();          // Аналогично $arResult['FIELDS'] в компонентах
    $props  = $ob->GetProperties();      // Аналогично $arResult['PROPERTIES']

    // Пример доступа:
    // Строковое свойство
    $value = $props['MY_PROP']['VALUE'];

    // Файл в свойстве
    if (!empty($props['FILE_PROP']['VALUE'])) {
        $file = CFile::GetFileArray($props['FILE_PROP']['VALUE']);
        $src  = $file['SRC']; // /upload/iblock/...
    }

    // Множественное свойство
    $values = $props['TAGS']['VALUE']; // массив значений
}

Плюсы:

  • Почти не требует настройки.
  • Свойства приходят в удобной структуре, похожей на $arResult['PROPERTIES'].

Минусы:

  • Отдельный вызов GetNextElement и GetProperties может быть тяжелее на больших выборках. Для списков лучше использовать GetProperty.

2) Списки элементов: оптимизация по свойствам

Если нужно выбрать много элементов с конкретными свойствами, используйте выборку свойств в селекте через PROPERTY_*, чтобы снизить количество обращений:

PHP
$arSelect = [
    'ID', 'NAME', 'IBLOCK_ID',
    'PROPERTY_COLOR',        // одно значение
    'PROPERTY_SIZE',         // одно значение
    'PROPERTY_GALLERY'       // множественное (вернутся ID файлов)
];
$arFilter = ['IBLOCK_ID' => $iblockId, 'ACTIVE' => 'Y'];
$res = CIBlockElement::GetList(['SORT' => 'ASC'], $arFilter, false, ['nTopCount' => 50], $arSelect);

$items = [];
while ($ob = $res->GetNext()) {
    // Свойства будут в полях как PROPERTY_COLOR_VALUE и т.п.
    $items[] = [
        'ID' => $ob['ID'],
        'NAME' => $ob['NAME'],
        'COLOR' => $ob['PROPERTY_COLOR_VALUE'],
        'SIZE'  => $ob['PROPERTY_SIZE_VALUE'],
        'GALLERY' => (array)$ob['PROPERTY_GALLERY_VALUE'], // массив ID файлов
    ];
}

Плюс: меньше вызовов методов, быстрее на больших выборках. Минус: структура не такая «красивая», как $arResult['PROPERTIES'].

3) ORM D7: Bitrix\Iblock\Elements\ElementXxxTable

Современно и типобезопасно, но требует сгенерированного ORM-класса для ИБ (или использования универсальной ORM).

Пример с сгенерированным классом Elements\ElementCatalogTable (название зависит от кода ИБ):

PHP
<?php
use Bitrix\Main\Loader;
use Bitrix\Iblock\Elements\ElementCatalogTable;

Loader::includeModule('iblock');

// SELECT полей и свойств через runtime поля PROPERTY_*
$query = ElementCatalogTable::getList([
    'filter' => ['=ACTIVE' => 'Y', '=IBLOCK_ID' => 10],
    'select' => [
        'ID', 'NAME',
        'COLOR' => 'COLOR.VALUE',
        'SIZE'  => 'SIZE.VALUE',
        'GALLERY' => 'GALLERY.VALUE',
    ],
    'limit' => 50,
    'order' => ['SORT' => 'ASC']
]);

$rows = $query->fetchAll();
// Свойства сразу доступны как COLOR, SIZE, GALLERY

Плюсы:

  • Удобно для сложных запросов, joins, строгих выборок.
  • Хорошо сочетается с кэшированием D7.

Минусы:

  • Нужно подготовить класс, свойства мапятся в runtime поля.

4) Получить только свойства элемента: CIBlockElement::GetProperty

Если поля не нужны, а нужна только конкретная подборка свойств:

PHP
$props = [];
$propRes = CIBlockElement::GetProperty($iblockId, $elementId, ['sort' => 'asc'], ['ACTIVE' => 'Y']);
while ($p = $propRes->Fetch()) {
    // $p['CODE'], $p['VALUE'], $p['DESCRIPTION'], $p['VALUE_ENUM'], $p['VALUE_XML_ID'] и др.
    $code = $p['CODE'] ?: $p['ID']; // у некоторых свойств может не быть кода
    if ($p['MULTIPLE'] == 'Y') {
        $props[$code]['VALUES'][] = $p;
    } else {
        $props[$code] = $p;
    }
}

Плюсы:

  • Гибко и быстро, если нужно узкое подмножество.
  • Можно фильтровать по коду свойства в 4-м параметре.

5) Кэширование результата (важно для «в любом месте»)

Если этот код будет вызываться на каждом хите (например, в header.php), обязательно добавить кэш:

PHP
<?php
use Bitrix\Main\Data\Cache;
use Bitrix\Main\Loader;

Loader::includeModule('iblock');

$cache = Cache::createInstance();
$cacheTtl = 3600;
$cacheId = 'site_settings_'.$iblockId.'_'.$elementId;
$cacheDir = '/my/site_settings';

if ($cache->initCache($cacheTtl, $cacheId, $cacheDir)) {
    $data = $cache->getVars();
} elseif ($cache->startDataCache()) {
    // получить поля/свойства
    $res = CIBlockElement::GetList([], ['IBLOCK_ID'=>$iblockId, 'ID'=>$elementId, 'ACTIVE'=>'Y'], false, ['nTopCount'=>1], ['ID','NAME']);
    $data = [];
    if ($ob = $res->GetNextElement()) {
        $data['FIELDS'] = $ob->GetFields();
        $data['PROPERTIES'] = $ob->GetProperties();
    }

    // Тегированное кэширование — чтобы инвалидация происходила при изменении ИБ
    if (defined('BX_COMP_MANAGED_CACHE')) {
        global $CACHE_MANAGER;
        $CACHE_MANAGER->StartTagCache($cacheDir);
        $CACHE_MANAGER->RegisterTag('iblock_id_'.$iblockId);
        $CACHE_MANAGER->EndTagCache();
    }

    $cache->endDataCache($data);
}

// Теперь аналог $arResult['PROPERTIES']:
$props = $data['PROPERTIES'] ?? [];

6) Универсальная вспомогательная функция (можно поместить в local/php_interface/init.php или модуль)

Создает привычную структуру с FIELDS и PROPERTIES, похожую на $arResult:

PHP
function bxGetIblockElementWithProps(int $iblockId, int $elementId, int $ttl = 3600): array
{
    static $prepared = [];

    $key = $iblockId.'_'.$elementId.'_'.$ttl;
    if (isset($prepared[$key])) {
        return $prepared[$key];
    }

    $data = [];
    $cache = Bitrix\Main\Data\Cache::createInstance();
    $cacheId = 'bxGetIblockElementWithProps_'.$key;
    $cacheDir = '/bx/iblock_element_props';

    if ($cache->initCache($ttl, $cacheId, $cacheDir)) {
        $data = $cache->getVars();
    } elseif ($cache->startDataCache()) {
        if (!Bitrix\Main\Loader::includeModule('iblock')) {
            $cache->abortDataCache();
            return [];
        }

        $res = CIBlockElement::GetList([], ['IBLOCK_ID'=>$iblockId, 'ID'=>$elementId, 'ACTIVE'=>'Y'], false, ['nTopCount'=>1], ['ID','IBLOCK_ID','NAME','CODE','XML_ID','ACTIVE','SORT','PREVIEW_TEXT','DETAIL_TEXT','PREVIEW_PICTURE','DETAIL_PICTURE']);
        if ($ob = $res->GetNextElement()) {
            $fields = $ob->GetFields();
            $props  = $ob->GetProperties();

            // Нормализуем множественные свойства: всегда массив
            foreach ($props as $code => &$prop) {
                if ($prop['MULTIPLE'] === 'Y') {
                    $prop['VALUE'] = is_array($prop['VALUE']) ? $prop['VALUE'] : (strlen($prop['VALUE']) ? [$prop['VALUE']] : []);
                }
            }
            unset($prop);

            $data = [
                'FIELDS' => $fields,
                'PROPERTIES' => $props,
            ];

            if (defined('BX_COMP_MANAGED_CACHE')) {
                global $CACHE_MANAGER;
                $CACHE_MANAGER->StartTagCache($cacheDir);
                $CACHE_MANAGER->RegisterTag('iblock_id_'.$iblockId);
                $CACHE_MANAGER->EndTagCache();
            }

            $cache->endDataCache($data);
        } else {
            $cache->abortDataCache();
        }
    }

    return $prepared[$key] = $data;
}

Использование в любом месте:

PHP
$el = bxGetIblockElementWithProps(10, 123, 1800);
$props = $el['PROPERTIES'];
echo htmlspecialcharsbx($props['MY_PROP']['VALUE']);

7) Получить свойства по коду инфоблока и символьному коду элемента

Чтобы не хардкодить ID:

PHP
use Bitrix\Iblock\IblockTable;
use Bitrix\Main\Loader;

Loader::includeModule('iblock');

$iblock = IblockTable::getRow(['filter' => ['=CODE' => 'site_settings'], 'select' => ['ID']]);
if ($iblock) {
    $iblockId = (int)$iblock['ID'];
    $res = CIBlockElement::GetList([], ['IBLOCK_ID' => $iblockId, '=CODE' => 'main'], false, ['nTopCount' => 1], ['ID']);
    if ($el = $res->Fetch()) {
        $data = bxGetIblockElementWithProps($iblockId, (int)$el['ID']);
        $props = $data['PROPERTIES'];
    }
}

8) Где именно появится $arResult[‘PROPERTIES’] «как в компонентах»

Если нужно именно внутри любого шаблона «как у стандартных компонентов», есть два пути:

  • Подключить стандартный компонент с нужными параметрами (например, bitrix:news.detail) и получить $arResult['PROPERTIES'] в его шаблоне. Это нативный способ.
  • В собственном компоненте в result_modifier.php сформировать $arResult['PROPERTIES'] через GetProperties(), как показано выше, и использовать в template.php.

Пример в result_modifier.php пользовательского компонента:

PHP
if (!empty($arResult['ID']) && Bitrix\Main\Loader::includeModule('iblock')) {
    $res = CIBlockElement::GetList([], ['ID' => $arResult['ID']], false, ['nTopCount'=>1], ['ID','IBLOCK_ID']);
    if ($ob = $res->GetNextElement()) {
        $arResult['FIELDS'] = $ob->GetFields();
        $arResult['PROPERTIES'] = $ob->GetProperties();
    }
}

9) Безопасность и производительность

  • Всегда добавляйте кэш для часто читаемых данных (хедер, футер, сайдбары).
  • Используйте тегированный кэш с меткой iblock_id_X для автоматической инвалидации при изменениях.
  • Ограничивайте выборку через nTopCount и точные фильтры.
  • Для файловых свойств используйте CFile::GetFileArray один раз и кладите в кэш.
  • Экранируйте вывод в шаблонах: htmlspecialcharsbx, \Bitrix\Main\Text\Converter.

10) Диагностика

  • Включайте Debug/SQL монитор (performance panel) на деве, чтобы видеть лишние запросы.
  • Логируйте кэш-промахи и хиты.
  • Для ORM — смотрите $query->getTrackerQuery() (в режиме Debug) для анализа SQL.

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