Массовое обновление свойства инфоблока в 1С-Битрикс через D7

Иногда в 1С-Битрикс нужно массово изменить значение свойства у множества элементов инфоблока. Например, обновить код ТН ВЭД у товаров, поменять артикул, проставить новое значение какого-либо справочного свойства.

Через админку это делать долго: открыть каждый товар → изменить свойство → сохранить. Если элементов сотни или тысячи — часы рутины.

В этой заметке — скрипт на D7 API, который делает это за секунды. Он находит все элементы с определённым значением свойства и меняет его на новое.

Задача

  • Инфоблок: ID = 51 (например, каталог товаров)
  • Свойство: TN_VED (код ТН ВЭД)
  • Старое значение: 3924900000
  • Новое значение: 3924900009

Нужно найти все элементы, у которых свойство TN_VED = 3924900000, и заменить его на 3924900009.

Скрипт

<?require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");

use Bitrix\Main\Loader;
use Bitrix\Iblock\ElementPropertyTable;
use Bitrix\Iblock\PropertyTable;

Loader::includeModule('iblock');

// ==== НАСТРОЙКИ ====
$IBLOCK_ID     = 51;              // ID инфоблока
$PROPERTY_CODE = 'TN_VED';        // Символьный код свойства
$OLD_VALUE     = '3924900000';
$NEW_VALUE     = '3924900009';
// ===================

// Получаем ID свойства
$property = PropertyTable::getList([
    'filter' => ['=IBLOCK_ID' => $IBLOCK_ID, '=CODE' => $PROPERTY_CODE],
    'select' => ['ID', 'MULTIPLE'],
])->fetch();

if (!$property) {
    die("Свойство с кодом {$PROPERTY_CODE} не найдено в инфоблоке {$IBLOCK_ID}\n");
}

$propId = (int)$property['ID'];
echo "ID свойства: {$propId}\n";

// Находим все записи со старым значением
$rows = ElementPropertyTable::getList([
    'filter' => [
        '=IBLOCK_PROPERTY_ID' => $propId,
        '=VALUE'              => $OLD_VALUE,
    ],
    'select' => ['ID', 'IBLOCK_ELEMENT_ID', 'VALUE'],
]);

$count = 0;
while ($row = $rows->fetch()) {
    $res = ElementPropertyTable::update($row['ID'], [
        'VALUE' => $NEW_VALUE,
    ]);
    if ($res->isSuccess()) {
        $count++;
        echo "Обновлён элемент ID={$row['IBLOCK_ELEMENT_ID']} (запись свойства ID={$row['ID']})\n";
    } else {
        echo "Ошибка для элемента {$row['IBLOCK_ELEMENT_ID']}: "
            . implode(', ', $res->getErrorMessages()) . "\n";
    }
}

echo "Готово. Обновлено записей: {$count}\n";

Как это работает

1. Подключение пролога

require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");

Подключает ядро Битрикс без запуска шаблона сайта. Это важно для CLI-скриптов и cron-задач — скрипт работает «в фоне», не рендерит HTML.

2. Подключение модуля iblock

Loader::includeModule('iblock');

Без этой строки классы ElementPropertyTable и PropertyTable не будут доступны.

3. Получение ID свойства по символьному коду

$property = PropertyTable::getList([
    'filter' => ['=IBLOCK_ID' => $IBLOCK_ID, '=CODE' => $PROPERTY_CODE],
    'select' => ['ID', 'MULTIPLE'],
])->fetch();

В Битриксе значения свойств хранятся не в основной таблице элементов, а в отдельной таблице b_iblock_element_property. Чтобы с ней работать через D7, нужно знать ID свойства — оно уникально для каждого инфоблока.

Мы передаём символьный код (TN_VED), а получаем числовой ID — по нему потом ищем значения.

4. Поиск всех записей со старым значением

$rows = ElementPropertyTable::getList([
    'filter' => [
        '=IBLOCK_PROPERTY_ID' => $propId,
        '=VALUE'              => $OLD_VALUE,
    ],
    'select' => ['ID', 'IBLOCK_ELEMENT_ID', 'VALUE'],
]);

ElementPropertyTable — это D7-обёртка над b_iblock_element_property. Каждая строка этой таблицы — одно значение свойства у одного элемента.

Если свойство множественное — у элемента будет несколько строк. Если одиночное — одна.

Мы фильтруем по ID свойства и по значению — это находит все нужные записи.

5. Обновление значений

while ($row = $rows->fetch()) {
    $res = ElementPropertyTable::update($row['ID'], [
        'VALUE' => $NEW_VALUE,
    ]);
    // ...
}

Обновляем каждую запись по её ID — меняем VALUE на новое.

Важно: мы обновляем не элемент, а запись свойства. Это безопаснее — не затрагивает другие поля элемента, не сбрасывает кэш страницы.

6. Подсчёт и вывод

В конце — сколько записей обновлено. Если что-то упало — видно, у какого элемента ошибка и почему.

Где запускать

Вариант 1 — разово через браузер

  1. Создайте файл update_property.php в корне сайта
  2. Откройте https://ваш-сайт.ru/update_property.php
  3. Дождитесь выполнения
  4. Удалите файл — иначе любой желающий сможет его запустить

⚠️ Для продакшена — не лучший вариант. Файл может попасть в индексы, в логи, стать дырой.

Вариант 2 — через CLI (рекомендую)

php -f /path/to/site/update_property.php

Плюсы:

  • Не доступен из браузера
  • Работает в фоне
  • Можно повесить на cron
  • Логи удобно писать в файл

Вариант 3 — через агента / cron

Оберните код в агент Битрикс и запускайте раз в сутки:

\CAgent::AddAgent(
    'updateTnVedAgent();',
    'main',
    'N',
    86400,       // раз в сутки
    '',
    'Y',
    date('d.m.Y H:i:s', strtotime('+1 day'))
);

function updateTnVedAgent() {
    // ... код скрипта ...
    return 'updateTnVedAgent();';  // перезапустить через сутки
}

Подводные камни

1. Множественные свойства

Если свойство множественное, у элемента может быть несколько записей с одинаковым значением. Скрипт обновит все — это обычно то, что нужно. Но проверяйте логику: иногда нужно менять только «первую» или «последнюю».

2. Кэш

После обновления значений через ElementPropertyTable кэш компонентов и страниц не сбрасывается. Если сайт показывает старое значение — очистите кэш:

  • В админке: Настройки → Автокеширование → Очистить весь кэш
  • Или через CLI: php -f bitrix/modules/main/tools/clear_cache.php

3. Права и роли

Скрипт работает от имени того, кто его запускает. Если запускаете через браузер — от текущего пользователя. Для CLI — от пользователя, под которым запущен PHP. Убедитесь, что у него есть права на изменение инфоблока.

4. Транзакции

Скрипт не оборачивает изменения в транзакцию. Если упадёт на середине — часть записей обновится, часть нет. Для больших объёмов лучше:

  • Разбить на батчи (по 500 элементов)
  • Обернуть в Application::getConnection()->startTransaction()
  • Добавить логирование прогресса

5. Производительность

Для больших инфоблоков (10 000+ элементов) скрипт может работать долго. ElementPropertyTable::update делает отдельный SQL-запрос на каждую запись. Если нужно ускорить — можно сгруппировать:

$connection = \Bitrix\Main\Application::getConnection();
$sql = "UPDATE b_iblock_element_property 
        SET VALUE = '{$NEW_VALUE}' 
        WHERE IBLOCK_PROPERTY_ID = {$propId} 
        AND VALUE = '{$OLD_VALUE}'";
$connection->queryExecute($sql);

Но это обходит D7 API — теряются события (OnBeforeIBlockElementUpdate и т.п.). Используйте с осторожностью.

Безопасность

Никогда не запускайте такой скрипт на продакшене без бэкапа.

Перед запуском:

  1. Сделайте резервную копию БД (или хотя бы таблиц b_iblock_element_property)
  2. Протестируйте на копии сайта
  3. Убедитесь, что знаете ID инфоблока и код свойства — ошибка в них может испортить другие данные
  4. Удалите файл после использования

Итог

D7 API в 1С-Битрикс даёт чистый способ массово обновлять значения свойств инфоблока — без ручной работы в админке. Ключевые моменты:

  • Значения свойств хранятся в b_iblock_element_property — работаем через ElementPropertyTable
  • Сначала получаем ID свойства по коду через PropertyTable
  • Фильтруем по ID свойства и старому значению
  • Обновляем каждую запись через ElementPropertyTable::update
  • Очищаем кэш после — иначе сайт покажет старое

Скрипт универсален — меняйте IBLOCK_ID, PROPERTY_CODE, OLD_VALUE, NEW_VALUE под свою задачу.