1С Битрикс · 7 мин чтения

UF поля пользователя Битрикс: создание, вывод и работа из кода

UF поля пользователя Битрикс, если коротко, это способ прикрутить к стандартной сущности (пользователь, раздел инфоблока, элемент, компания в CRM) свои данные без правки ядра. Работаю с ними на каждом втором проекте на Битриксе: то нужно хранить ID клиента во внешней CRM, то пункт выдачи СДЭК, то согласие на обработку персональных данных с датой подписания. Ниже - как я создаю такие поля через админку, как читаю и пишу их из кода, и какие грабли реально всплывают на практике.

Что такое UF-поля и зачем их вообще заводить

UF расшифровывается как User Field, но по факту это универсальный механизм пользовательских свойств для любой сущности, у которой в модуле есть таблица ENTITY_ID + FIELD_ID. Пользователи (b_user), разделы инфоблоков (iblock_section), элементы (iblock_element), компании и сделки в CRM - везде работает один и тот же движок highloadblock/userfield, только меняется идентификатор сущности вроде USER, IBLOCK_SECTION, CRM_COMPANY.

Плюс такого подхода в том, что поле создаётся один раз в админке или кодом, и сразу появляется в формах редактирования, в фильтрах, в экспорте, в API. Не нужно лезть в таблицу b_user и добавлять туда столбец руками - это сломает обновления модуля и потеряется при следующем major-апдейте.

На практике UF-поля пользователя чаще всего заводят под:

  • дополнительные контактные данные (второй телефон, telegram, WhatsApp);
  • привязку к внешним системам (ID в 1С, ID в CRM, ID пункта выдачи СДЭК);
  • служебные флаги (согласие на рассылку, дата последнего входа в личный кабинет, реферальный код);
  • данные для персонализации (город, сегмент, дата рождения для промо-рассылок).

Создание UF-поля пользователя через админку

Самый быстрый способ - раздел Настройки > Пользователи > Поля пользователей в админке. Там задаётся:

  • символьный код поля (обязательно с префиксом UF_, например UF_CDEK_PVZ);
  • тип данных: строка, число, дата, файл, привязка к элементу или разделу инфоблока, список (enum), HTML/текст;
  • множественность (одно значение или массив);
  • обязательность заполнения и значение по умолчанию;
  • видимость в разных местах (список пользователей, форма редактирования, публичная часть).

Для типа «Список» отдельно заполняются варианты значений (enum) - каждый вариант хранится в таблице b_user_field_enum со своим XML_ID, и именно по XML_ID, а не по тексту, я потом обращаюсь к значению из кода, потому что текст менеджер может переименовать в любой момент.

Важный момент, о который спотыкаются новички: если поле создано с настройкой «Множественное», в коде оно всегда возвращается массивом, даже если в нём одно значение. Забыть об этом в условии if ($arUser['UF_PHONE_2'] == '...') - типичная причина «поле не работает», хотя на деле сравнивается строка с массивом.

Работа с UF-полями пользователя из кода

Через админку поле можно создать один раз руками, но когда доработка ставится на поток или переносится между окружениями (dev/staging/prod), поле нужно создавать кодом - иначе на каждом окружении придётся руками кликать одно и то же.

Создание поля через CUserTypeEntity:

$obUserField = new CUserTypeEntity();
$fieldId = $obUserField->Add([
    'ENTITY_ID' => 'USER',
    'FIELD_NAME' => 'UF_CDEK_PVZ',
    'USER_TYPE_ID' => 'string',
    'XML_ID' => 'CDEK_PVZ',
    'SORT' => 500,
    'MULTIPLE' => 'N',
    'MANDATORY' => 'N',
    'EDIT_FORM_LABEL' => ['ru' => 'Пункт выдачи СДЭК'],
    'LIST_COLUMN_LABEL' => ['ru' => 'ПВЗ СДЭК'],
]);

Чтение значения UF-поля у текущего пользователя:

global $USER;
$rsUser = CUser::GetByID($USER->GetID());
$arUser = $rsUser->Fetch();
echo $arUser['UF_CDEK_PVZ'];

Обновление значения:

$user = new CUser();
$user->Update($userId, [
    'UF_CDEK_PVZ' => 'MSK123',
]);

Для выборки пользователей по значению UF-поля использую GetList с фильтром прямо по коду поля - Битрикс сам достроит JOIN к таблице значений:

$rsUsers = CUser::GetList(
    $by = 'ID', $order = 'ASC',
    ['UF_CDEK_PVZ' => 'MSK123'],
    ['SELECT' => ['UF_CDEK_PVZ']]
);
while ($arUser = $rsUsers->Fetch()) {
    echo $arUser['LOGIN'] . ' - ' . $arUser['UF_CDEK_PVZ'] . PHP_EOL;
}

Если поле типа «Список», значение хранится как ID записи в enum-таблице, а не как текст. Чтобы получить читаемое значение, нужен CUserFieldEnum:

$enum = new CUserFieldEnum();
$rsEnum = $enum->GetList([], ['XML_ID' => 'SEGMENT_VIP']);
$arEnum = $rsEnum->Fetch();
echo $arEnum['VALUE'];

Эту связку я обычно оборачиваю в отдельный класс-хелпер, если полей-списков в проекте больше двух-трёх - иначе в контроллерах расползаются одинаковые куски с CUserFieldEnum.

Бесплатный материал

🎁 Полезный скрипт в подарок

Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.

Без спама. Отписка в 1 клик.

UF-поля в разделах и элементах инфоблоков: чем отличаются от полей пользователя

Механизм тот же самый, но ENTITY_ID другой: для разделов инфоблока это IBLOCK_ID_1_SECTION (где 1 - ID инфоблока), для элементов - IBLOCK_1. Из-за этого поле, созданное для одного инфоблока, не появится в другом - привязка жёсткая, и если в проекте десять инфоблоков с одинаковой структурой (например, каталог товаров с несколькими брендами на разных ID), поле придётся создавать под каждый ID отдельно, либо один раз - если инфоблоки объединены общими типами свойств через настройки типа.

На практике для товарных каталогов чаще заводят не UF-поля, а обычные свойства инфоблока (props) - они гибче в плане множественности и наследования по группам. UF-поля для разделов инфоблока я использую точечно: например, привязать к разделу каталога ответственного менеджера (поле типа «Пользователь») или SEO-шаблон, специфичный для этого раздела и не подходящий под общую схему свойств.

Сравнение, где какой механизм уместнее:

Сценарий Что использовать Почему
Доп. поля у пользователя (телефон, ID в CRM) UF-поле сущности USER Единственный штатный механизм для b_user
Характеристики товара (цвет, размер) Свойство инфоблока Гибкое наследование по разделам и фильтрация в каталоге
Служебные данные раздела (ответственный, шаблон) UF-поле сущности IBLOCK_ID_SECTION Не нужно городить отдельный инфоблок-справочник
Доп. поля в CRM-сделке или компании UF-поле CRM-сущности Штатно интегрируется с полями сделки в интерфейсе CRM

Вывод и редактирование UF-полей в компонентах и на фронте

В компонентах bitrix:main.register и bitrix:main.profile UF-поля пользователя подхватываются автоматически, если они помечены как видимые в форме регистрации или профиля - шаблон компонента сам построит нужный input по типу поля. Проблема в том, что штатная вёрстка этих полей редко подходит под дизайн, и её обычно приходится переопределять в шаблоне компонента вручную под каждый тип поля (строка, список, файл, дата - у каждого своя разметка в result_modifier.php и template.php).

Если поле нужно вывести вне штатных компонентов - на любой произвольной странице личного кабинета, - проще всего собрать форму самому и обработать сохранение через тот же CUser::Update. Я так делаю почти всегда, когда личный кабинет кастомный: меньше зависимости от структуры чужого компонента, легче стилизовать под макет.

Отдельно стоит сказать про мультисайтовость: у UF-полей есть настройка привязки к языковым версиям (для лейблов), но сами значения общие для всех сайтов, если это одна сущность USER. Если нужно разное поведение поля на разных сайтах в рамках одного ядра, логику ветвления придётся писать в коде, само поле останется одно.

Частые ошибки при работе с UF-полями пользователя

  • Забыли префикс UF_. Без него поле не будет считаться пользовательским и просто не сохранится через штатный механизм.
  • Сравнение множественного поля со строкой. Множественное поле всегда массив, даже с одним значением - сравнивать нужно через in_array или брать первый элемент явно.
  • Хранение читаемого текста вместо XML_ID для списков. Менеджер переименует пункт списка в админке - и весь код, завязанный на текст, перестанет работать. Завязывайтесь только на XML_ID.
  • Изменение типа поля на боевом проекте без миграции данных. Смена типа (например, строка на список) не конвертирует уже сохранённые значения, они просто перестают быть видны в новой форме.
  • Создание одинаковых по смыслу полей под разными кодами в разных модулях. Встречал на аудитах инфраструктуру, где ID клиента в 1С хранился в трёх разных UF-полях с разными кодами - в CRM, в профиле пользователя и в отдельной таблице. Синхронизация между ними держалась на честном слове.

Если нужно навести порядок в существующей структуре полей или спроектировать её с нуля под интеграцию с 1С, CRM или внешним сервисом рассылок, обычно проще один раз заказать поддержку и сопровождение сайтов, чем распутывать задвоенные поля постфактум на живом проекте.

Частые вопросы

Можно ли переименовать код UF-поля после того, как оно уже используется в коде?

Напрямую нет - Битрикс не даёт штатного инструмента переименования FIELD_NAME. Технически можно создать новое поле с нужным кодом, перенести значения скриптом через CUserTypeEntity и CUser::Update, а старое удалить. Делать это стоит только в тестовом окружении с бэкапом базы под рукой.

Почему UF-поле не отображается в форме редактирования пользователя в админке?

Чаще всего причина в настройке SHOW_IN_LIST/EDIT_IN_LIST при создании поля - она отдельная от видимости на публичной части. Проверяю через Настройки > Пользователи > Поля пользователей, открываю поле и смотрю галочки «Показывать в списке» и «Показывать в форме».

Как быстро проверить, что вообще за UF-поля есть у сущности USER в проекте?

Запросом к таблице b_user_field: SELECT FIELD_NAME, USER_TYPE_ID FROM b_user_field WHERE ENTITY_ID = 'USER'. Это быстрее, чем листать админку, особенно на проекте, который достался по наследству без документации.

Работают ли UF-поля пользователя с highload-блоками и REST API Битрикса?

Да, highload-блоки используют тот же движок userfield, что и остальные сущности, поэтому UF-поля можно добавлять и к строкам highload-блока. В REST API (rest_marketplace, стандартные методы user.*) кастомные UF-поля пользователя отдаются вместе со стандартными, если явно не отфильтрованы в SELECT.

Есть задача?

Обсудим в мессенджере

Расскажите, что нужно сделать — отвечу в течение 4 часов в рабочее время. Первая консультация бесплатно.

Продолжая пользование настоящим сайтом Вы выражаете своё согласие на обработку Ваших персональных данных (файлов куки) с использованием Yandex.Metrika.
Понятно