Третий раз за неделю вы правите init.php, а поле так и не появляется в форме раздела каталога? Чаще всего проблема не в кэше, а в том, что создали свойство товара вместо пользовательского поля UF для объекта IBLOCK_7_SECTION. Ниже – когда нужен UF на CMS "1С-Битрикс: Управление сайтом", как добавить его в админке и через CUserTypeEntity::Add, заполнить список и сохранить значение без дублей при повторном деплое.
Пользовательские поля UF – универсальный механизм ядра для USER, разделов инфоблока и Highload-блоков. Код поля всегда начинается с UF_, создаётся через CUserTypeEntity::Add, а значения читают и пишут через $USER_FIELD_MANAGER. Перед Add на проде проверяйте GetList по ENTITY_ID и FIELD_NAME – так миграция не создаст дубль. Это не Bitrix24: в портале другие объекты и REST, здесь только CMS.
Если в поиске попадаются гайды про поля задач и сделок в Bitrix24 – это другой продукт. В статье разбираем только "Управление сайтом": PHP, админка и API ядра. Свойства элементов каталога – в гайде по свойствам товаров, Highload и UF в HL – в материале про Highload-блоки.
Разберите, когда нужен UF, а когда свойство инфоблока
UF (User Field) – дополнительная колонка к объекту ядра: пользователь, раздел инфоблока, Highload-запись. Свойства инфоблока живут только у элементов каталога и новостей. Путаница – типичная причина пустой формы раздела.
| Механизм | Куда вешается | Код в коде | Когда выбирать |
|---|---|---|---|
| Свойство инфоблока | Элемент (товар, новость) | PROPERTY_* |
Фильтр каталога, карточка товара |
| UF (CUserTypeEntity) | USER, IBLOCK_{ID}_SECTION, HLBLOCK_{ID} | UF_* |
Бейдж раздела, поле профиля, колонка HL |
| Колонка HL через UF | Запись Highload-блока | UF_* в ORM |
Справочники, логи – см. B26 |
Делайте: для раздела каталога берите ENTITY_ID вида IBLOCK_7_SECTION (подставьте ID инфоблока). Например, для инфоблока каталога с ID 7 это строка IBLOCK_7_SECTION. Не делайте: не создавайте "свойство раздела" через карточку элемента – у разделов свой механизм UF. Работа с разделами через CIBlockSection – в отдельном гайде.
Создайте UF в админке или в install модуля
Быстрый путь без кода: Настройки → Настройки продукта → Пользовательские поля → Добавить. Укажите объект (USER, IBLOCK_N_SECTION), тип данных, код с префиксом UF_ и подпись для формы.
- Откройте список пользовательских полей в админке CMS.
- Выберите объект: USER, IBLOCK_{ID}_SECTION или HLBLOCK_{ID}.
- Задайте USER_TYPE_ID: string, enumeration, file, iblock_element и др.
- Введите FIELD_NAME с префиксом UF_ (минимум 4 символа после префикса).
- Отметьте MULTIPLE и MANDATORY – множественность потом не сменить.
- Сохраните и откройте форму объекта – поле должно появиться.
Для переносимости между стендами поле лучше создавать в install своего модуля – см. гайд по созданию модуля. Делайте: храните UF в миграции или InstallDB. Не делайте: не правьте b_user_field вручную в phpMyAdmin.
Настройте CUserTypeEntity::Add с обязательными полями
Класс CUserTypeEntity помечен устаревшим с версии 20.0.700, но Add, Update и Delete по-прежнему только через него. D7 UserFieldTable – для чтения метаданных, не для создания поля.
use Bitrix\Main\Loader;
Loader::includeModule('main');
$entityId = 'IBLOCK_7_SECTION'; // или USER, HLBLOCK_3
$fieldName = 'UF_BADGE';
$exists = CUserTypeEntity::GetList([], [
'ENTITY_ID' => $entityId,
'FIELD_NAME' => $fieldName,
])->Fetch();
if (!$exists) {
$uf = new CUserTypeEntity();
$id = $uf->Add([
'ENTITY_ID' => $entityId,
'FIELD_NAME' => $fieldName,
'USER_TYPE_ID' => 'string',
'EDIT_FORM_LABEL' => ['ru' => 'Бейдж раздела', 'en' => 'Section badge'],
'LIST_COLUMN_LABEL' => ['ru' => 'Бейдж'],
'SETTINGS' => ['DEFAULT_VALUE' => ''],
]);
}
На практике типичная ошибка – FIELD_NAME без UF_, меньше 4 символов в имени или повторный Add без GetList: форма раздела остаётся пустой, а в D7 вы видите Unknown field definition. После создания ENTITY_ID, FIELD_NAME и USER_TYPE_ID менять нельзя – только новое поле и перенос значений.
Заполните список через CUserFieldEnum::SetEnumValues
Для типа enumeration варианты отдельно не появятся – их задают через CUserFieldEnum после Add.
$enum = new CUserFieldEnum();
$enum->SetEnumValues($ufFieldId, [
'n0' => ['VALUE' => 'Хит', 'SORT' => 100, 'DEF' => 'N'],
'n1' => ['VALUE' => 'Новинка', 'SORT' => 200, 'DEF' => 'N'],
]);
Делайте: фиксируйте enum в той же миграции, что и Add. Не делайте: не полагайтесь на ручной ввод вариантов на проде – ID enum разойдутся между стендами.
Прочитайте и запишите значение через $USER_FIELD_MANAGER
Глобальный $USER_FIELD_MANAGER – стандартный способ работы со значениями UF на CMS-объектах. Для пользователей это дополняет гайд по CUser: UF_* можно передать в CUser::Update, но универсальный API – менеджер полей.
global $USER_FIELD_MANAGER;
$entityId = 'USER';
$userId = 1;
$fields = $USER_FIELD_MANAGER->GetUserFields($entityId, $userId);
$badge = $fields['UF_BADGE']['VALUE'] ?? '';
$USER_FIELD_MANAGER->Update($entityId, $userId, [
'UF_BADGE' => 'VIP',
]);
Для раздела замените ENTITY_ID на IBLOCK_7_SECTION и передайте ID раздела. Значения одиночных полей лежат в b_uts_{entity}, множественных – в b_utm_{entity}. Делайте: проверяйте сохранение через GetUserFields сразу после Update. Не делайте: не пишите в b_uts_* напрямую.
Используйте UserFieldTable только для чтения метаданных
В D7 Bitrix\Main\UserFieldTable::getList выдаёт описание полей – код, тип, объект. Изменять через ORM нельзя: Add/Update/Delete остаются у CUserTypeEntity.
use Bitrix\Main\UserFieldTable;
$row = UserFieldTable::getList([
'filter' => [
'=ENTITY_ID' => 'IBLOCK_7_SECTION',
'=FIELD_NAME' => 'UF_BADGE',
],
'select' => ['ID', 'FIELD_NAME', 'USER_TYPE_ID'],
])->fetch();
Если в select ORM для HL видите Unknown field definition – поле ещё не создано или compileEntity вызван до регистрации UF. Сначала Add, потом ORM. Для HL-подробностей – материал B26.
Оформите идемпотентную миграцию без дублей на проде
Сценарий: на тесте install отработал, на проде после повторного деплоя – второй UF_BADGE и сломанный select. Решение – GetList перед каждым Add.
Схема безопасного деплоя:
GetList(ENTITY_ID + FIELD_NAME) → нет записи → Add → SetEnumValues → проверка формы → повторный прогон миграции → дублей нет
В Sprint Migration есть шаблон saveUserTypeEntity – подробности в гайде по миграциям B65. Делайте: версионируйте UF в репозитории. Не делайте: не вызывайте голый Add в init.php на каждый хит.
Проверьте результат: поле в форме, значение в БД, миграция без дубля
После всех шагов пройдите короткий чек-лист – он отделяет рабочий UF от "поля в коде, которого нет в админке".
- Откройте форму USER или раздела – UF видно и редактируется.
- Сохраните тестовое значение и прочитайте его через GetUserFields.
- Запустите миграцию/install второй раз – в b_user_field нет второй строки с тем же FIELD_NAME.
- Для enumeration варианты отображаются в форме и в коде по ID enum.
- В шаблоне выводите UF_* из массива полей, а не выдуманный ключ.
- Если поле не работает в шаблоне – проверьте, что ENTITY_ID в GetUserFields совпадает с объектом формы.
Если на проекте нужна настройка UF под нестандартный каталог или перенос с теста на бой – обсудим задачу. Похожие кейсы по Битрикс – в портфолио.
Автор: Максим Мольков, разработчик 1С-Битрикс.
Источники: документация UF CMS, CUserTypeEntity API, урок UF vs свойства.
Частые вопросы
Чем пользовательское поле отличается от свойства инфоблока?
Свойство привязано к элементу инфоблока (товар, статья). UF – к объекту ядра: USER, раздел IBLOCK_{ID}_SECTION или HLBLOCK_{ID}. Для бейджа раздела каталога нужен UF, для фильтра по характеристике товара – свойство из гайда B53.
Как добавить пользовательское поле программно?
Подключите main, проверьте CUserTypeEntity::GetList по ENTITY_ID и FIELD_NAME, затем Add с UF_ в имени и EDIT_FORM_LABEL. Для списка вызовите CUserFieldEnum::SetEnumValues после получения ID поля.
Какие типы пользовательских полей есть в Битрикс CMS?
Базовые: string, integer, double, boolean, date, datetime, enumeration, file, url. Для каталога часто берут iblock_element, iblock_section, hlblock. MULTIPLE и USER_TYPE_ID после создания не меняются.
Как получить значение UF_ в коде?
Через $USER_FIELD_MANAGER->GetUserFields($entityId, $recordId) или GetUserFieldValue. Для пользователей UF_* также доступны в CUser::GetList при указании в SELECT. Пишите через Update того же менеджера.
Можно ли создать UF для Highload-блока?
Да, ENTITY_ID = HLBLOCK_{ID}. Колонки HL – те же UF_ через CUserTypeEntity. Полный цикл создания HL и ORM – в статье B26, здесь только общий механизм Add и менеджера значений.
Почему Add возвращает ошибку про FIELD_NAME?
Имя должно начинаться с UF_, содержать только A-Z, цифры и подчёркивание, длина 4–50 символов. Пара (ENTITY_ID, FIELD_NAME) уникальна – при дубле сначала найдите существующее поле через GetList.