Ночной импорт из 1С пишет в лог "обновлено 4000 товаров", а утром в каталоге пустые характеристики: артикул, фото, привязки. Разработчик добавил в CIBlockElement::Update три свойства из семи - и остальные исчезли. Это не "баг Битрикса", а контракт ключа PROPERTY_VALUES: если он есть в массиве, ядро считает, что вы передаёте полный набор свойств. Ниже - безопасные паттерны Update для полей, точечное обновление через SetPropertyValuesEx и чек-лист, если свойства слетают без вашего ведома.
CIBlockElement::Update меняет поля элемента (название, активность, сортировку) и при желании свойства. Без ключа PROPERTY_VALUES свойства не трогаются - меняйте NAME и ACTIVE спокойно. Если PROPERTY_VALUES передан, в массиве должны быть все свойства инфоблока, иначе остальные очистятся. Для одного-двух свойств используйте SetPropertyValuesEx. При false смотрите $el->LAST_ERROR и обработчики OnBeforeIBlockElementUpdate в init.php.
Речь про 1С-Битрикс: Управление сайтом на сервере, не про облачную CRM Bitrix24. Элемент инфоблока — запись контента: товар, новость, услуга. Если инфоблок только создаёте — начните с гайда по созданию инфоблока.
Разберите, когда нужен Update в коде, а не правка в админке
В админке удобно править одну карточку. Update нужен, когда данные приходят пакетом: обмен с 1С, cron, вебхук, импорт CSV. Тогда один PHP-скрипт проходит по сотням ID и меняет цены, остатки или флаг активности.
| Ситуация | Админка | CIBlockElement::Update / SetPropertyValuesEx |
|---|---|---|
| Одна правка текста | Быстрее и нагляднее | Избыточно |
| Импорт 5000 SKU из 1С | Нереально вручную | Обязателен; см. также интеграцию 1С с сайтом |
| Скрыть товар без остатка | Можно, но долго на каталоге | Update с ACTIVE без PROPERTY_VALUES |
| Только цена в свойстве | Риск человеческой ошибки | SetPropertyValuesEx по коду свойства |
Делайте: автоматизируйте повторяющиеся массовые правки. Не делайте: не вызывайте Update из визуального редактора - для разовых правок хватит формы элемента.
Подготовьте скрипт: модуль iblock, ID элемента и снимок свойств
Перед любым изменением зафиксируйте "как было". Иначе после отката из бэкапа вы не поймёте, какие свойства затёрлись.
- Подключите модуль:
Loader::includeModule('iblock')в начале скрипта или агента. - Запишите ELEMENT_ID и IBLOCK_ID - числа из админки или из выборки CIBlockElement::GetList.
- Соберите карту свойств: коды PRICE, ARTICLE, BRAND - как в настройках инфоблока, не произвольные имена.
- Снимок и объект: GetProperty для состояния «до»;
$el = new CIBlockElement;— через него Update и LAST_ERROR.
<?php
use Bitrix\Main\Loader;
Loader::includeModule('iblock');
$elementId = 12345;
$iblockId = 7;
$before = [];
$rs = CIBlockElement::GetProperty($iblockId, $elementId);
while ($row = $rs->Fetch()) {
$before[$row['CODE']] = $row['VALUE'];
}
$el = new CIBlockElement;
Делайте: логируйте ID и diff до/после на тестовом элементе. Не делайте: не гоняйте импорт сразу на проде - сначала один элемент в копии каталога.
Обновите NAME, ACTIVE и картинки без затрагивания свойств
Главное правило: если в массиве $arFields нет ключа PROPERTY_VALUES, свойства элемента остаются как были. Меняются только поля самого элемента.
$ok = $el->Update($elementId, [
'NAME' => 'Новое название товара',
'ACTIVE' => 'N',
'SORT' => 500,
]);
if (!$ok) {
echo $el->LAST_ERROR;
}
Так безопасно выключать товары без остатка или менять заголовок после выгрузки из 1С. Картинки — через DETAIL_PICTURE и PREVIEW_PICTURE с CFile::MakeFileArray.
Делайте: для смены только ACTIVE передавайте один ключ ACTIVE. Не делайте: не добавляйте пустой PROPERTY_VALUES = array() "на всякий случай" - это уже сигнал ядру перезаписать свойства.
Избегите ловушки PROPERTY_VALUES: полная перезапись, не "добавить три из семи"
Официальная справка CIBlockElement::Update прямо говорит: если в вызове есть PROPERTY_VALUES, в массиве должны быть все свойства инфоблока. Неуказанное свойство удаляется (кроме типа "файл" - файлы не стираются молча, их удаляют явно через del => Y).
На практике типичная ошибка после примера с Habr: разработчик передаёт PRICE и три характеристики, четыре остальных пропадают — кейс на ftask.ru. Значение false в PROPERTY_VALUES не означает «не трогать» — свойство участвует в полной перезаписи.
| Задача | Метод | Риск для остальных свойств |
|---|---|---|
| Только NAME / ACTIVE | Update без PROPERTY_VALUES | Нет - свойства не меняются |
| Одно свойство PRICE | SetPropertyValuesEx | Нет - неуказанные сохраняются |
| Полная синхронизация из файла 1С | Update с полным PROPERTY_VALUES | Да, если массив неполный |
| Список (select) | ID enum, не текст "Да" | Неверный ID - пустое значение |
Для списка найдите ID варианта через CIBlockPropertyEnum::GetList или в HTML option value в админке. Для файлового свойства удаление: ['VALUE' => ['del' => 'Y']].
// ОПАСНО: обновили 2 свойства из 5 - остальные 3 очистятся
$el->Update($elementId, [
'PROPERTY_VALUES' => [
'PRICE' => 1990,
'ARTICLE' => 'SKU-001',
],
]);
// БЕЗОПАСНО: полная выгрузка - сначала GetProperty, потом весь массив
$fullProps = /* собрать все коды из GetProperty */;
$el->Update($elementId, ['PROPERTY_VALUES' => $fullProps]);
Делайте: для частичного изменения свойств не используйте Update. Не делайте: не копируйте PROPERTY_VALUES из Habr-примера с тремя ключами на боевой каталог.
Примените SetPropertyValuesEx и отладьте сбой по LAST_ERROR
SetPropertyValuesEx - статический метод для точечного обновления: передаёте только нужные коды, остальные не трогаете.
CIBlockElement::SetPropertyValuesEx($elementId, $iblockId, [
'PRICE' => 2490,
'BRAND' => 'Acme',
]);
// Список: передаём ID варианта enum, не строку
CIBlockElement::SetPropertyValuesEx($elementId, $iblockId, [
'IN_STOCK' => 42, // ID значения "Да" из CIBlockPropertyEnum
]);
Если Update вернул false, сразу выводите $el->LAST_ERROR - там текст валидации, права или отмены через событие. В реальном проекте свойства могут исчезнуть и без PROPERTY_VALUES в вашем вызове: в init.php обработчик OnBeforeIBlockElementUpdate иногда создаёт пустой PROPERTY_VALUES без проверки isset. Попросите разработчика найти такие обработчики по проекту.
Массовый импорт: Update($id, $fields, false, false) отключает переиндексацию; после цикла переиндексируйте отдельно. После SetPropertyValuesEx сбросьте кэш — иначе на витрине старые значения, см. карточку товара.
Схема безопасного импорта:
GetProperty (снимок) → Update полей без PROPERTY_VALUES → SetPropertyValuesEx по изменившимся кодам → проверка GetProperty → лог LAST_ERROR
- При false: echo $el->LAST_ERROR и ID элемента в лог агента.
- При "пустых" свойствах: grep OnBeforeIBlockElementUpdate в local/php_interface.
- Для справочников миллионов строк смотрите Highload-блоки, не классический инфоблок.
- После правок на проде зафиксируйте задачу в регламенте поддержки сайта.
Делайте: разделяйте обновление полей и свойств на два вызова. Не делайте: не смешивайте неполный PROPERTY_VALUES с боевым каталогом без бэкапа.
Что дальше
- Прогоните сценарий на одном тестовом элементе с GetProperty до и после.
- Замените неполные Update с PROPERTY_VALUES на SetPropertyValuesEx.
- Проверьте init.php на обработчики, трогающие PROPERTY_VALUES и сверьте карту свойств с модулем обмена 1С.
- Если импорт ломает каталог регулярно - обсудите аудит обмена с разработчиком до следующей выгрузки.
Автор: Максим Мольков, разработчик 1С-Битрикс.
Источники: CIBlockElement::Update, SetPropertyValuesEx, форум dev.1c-bitrix.ru (темы про затирание свойств), практика внедрений на CMS.
Частые вопросы
Почему после Update пропали свойства элемента?
Чаще всего в массиве был ключ PROPERTY_VALUES с неполным набором кодов: ядро удаляет неуказанные свойства. Реже виноват обработчик OnBeforeIBlockElementUpdate, который подставляет пустой PROPERTY_VALUES. Проверьте вызов и init.php, затем восстановите из бэкапа или полного GetProperty.
Как обновить одно свойство, не трогая остальные?
Используйте CIBlockElement::SetPropertyValuesEx($elementId, $iblockId, ['CODE' => $value]). Не передавайте PROPERTY_VALUES в Update, если нужно изменить только одно поле свойства. После вызова сверьте результат через GetProperty.
Чем Update отличается от SetPropertyValuesEx?
Update меняет поля элемента и при наличии PROPERTY_VALUES перезаписывает все свойства целиком. SetPropertyValuesEx меняет только переданные коды свойств, остальные сохраняет. Для ACTIVE и NAME достаточно Update без PROPERTY_VALUES.
Как передать значение списка (select) в PROPERTY_VALUES?
Передавайте числовой ID варианта enum из CIBlockPropertyEnum::GetList, не текст "Да" или "Нет". Текст в админке и ID в базе - разные вещи; неверный ID даст пустое значение в карточке.
Update вернул false - где смотреть причину?
Сразу после вызова выведите $el->LAST_ERROR у объекта CIBlockElement. Там будет текст про права, валидацию списка или отмену в обработчике события. Добавьте ID элемента в лог, чтобы найти проблемную запись в массовом импорте.
Можно ли обновлять элемент без PHP, только из админки?
Да, для разовых правок форма элемента в Контент → ваш инфоблок безопаснее: свойства не затрутся из-за API-контракта. Update нужен для скриптов, cron и обмена с 1С, когда правок сотни и тысячи.