В современном интернет-магазине на 1С-Битрикс нередко возникает задача массового редактирования товаров. Одна из самых востребованных операций — перенос группы товаров из одного раздела в другой. Делать это вручную через административную панель может быть утомительно, особенно если речь идет о сотнях или тысячах позиций. К счастью, в 1С-Битрикс существует удобный API для работы с элементами инфоблока, который позволяет автоматизировать процесс.

В данной статье мы разберемся, как организовать массовый перенос товаров из одного раздела в другой, используя язык PHP и классы 1С-Битрикс, а также рассмотрим несколько вариантов решения этой задачи и полезные примеры кода.
1. Общие принципы использования API инфоблоков
Модуль iblock
Все операции с элементами (товарами) и разделами в 1С-Битрикс проводятся через модуль iblock
. Прежде чем использовать классы для работы с инфоблоками, необходимо подключить этот модуль:
CModule::IncludeModule("iblock");
Классы CIBlockElement
и CIBlockSection
CIBlockElement
: отвечает за работу с элементами инфоблоков.CIBlockSection
: отвечает за работу с разделами (категориями).
Для решения задачи переноса товаров нужен именно CIBlockElement
: через его методы можно изменять данные элементов, в том числе и привязку к разделам.
2. Простой скрипт для массового переноса товаров
Ниже приведен базовый пример PHP-скрипта, который выполнит массовый перенос товаров из одного раздела в другой. Предположим, у нас есть:
- ID инфоблока:
2
(здесь хранятся товары); - ID раздела-источника:
10
(старый раздел); - ID нового раздела:
20
(куда нужно перенести).
Важный момент: В 1С-Битрикс товары — это элементы инфоблока, а разделы — это секции инфоблока.
Код скрипта
<?php
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
CModule::IncludeModule("iblock");
// ID инфоблока (где находятся товары)
$IBLOCK_ID = 2;
// Старый раздел
$OLD_SECTION_ID = 10;
// Новый раздел
$NEW_SECTION_ID = 20;
// Формируем фильтр для выбора нужных товаров
$arFilter = [
'IBLOCK_ID' => $IBLOCK_ID,
'SECTION_ID' => $OLD_SECTION_ID,
'INCLUDE_SUBSECTIONS' => 'N', // 'Y' если нужно учесть вложенные подразделы
];
$rsElements = CIBlockElement::GetList([], $arFilter, false, false, ["ID", "IBLOCK_ID"]);
$el = new CIBlockElement;
while ($arElement = $rsElements->Fetch()) {
// Способ 1. Указать один новый раздел (заменить старую привязку).
$arFields = [
"IBLOCK_SECTION_ID" => $NEW_SECTION_ID
];
$result = $el->Update($arElement["ID"], $arFields);
if ($result) {
echo "Товар c ID=" . $arElement["ID"] . " перенесен в раздел " . $NEW_SECTION_ID . "<br>";
} else {
global $APPLICATION;
echo "Ошибка при переносе товара ID=" . $arElement["ID"] . ": " . $el->LAST_ERROR . "<br>";
}
}
Пояснения:
- Подключение пролога
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
Это стандартная практика для скриптов вне административной части. Он загружает ядро Битрикс, подключает нужные классы, функции и т. д.
- Подключение модуля
CModule::IncludeModule("iblock");
Без этого модуля мы не сможем использовать классы CIBlockElement
и CIBlockSection
.
- Фильтр
$arFilter
IBLOCK_ID
— инфоблок, где хранятся товары.SECTION_ID
— конкретный раздел, из которого мы хотим забрать товары для переноса.INCLUDE_SUBSECTIONS
— указывает, нужно ли выбирать товары из вложенных подразделов. По умолчаниюN
.
- Метод
CIBlockElement::GetList
Принимает следующие параметры:
[]
— порядок сортировки (не задан, можно указать["SORT" => "ASC"]
и т. п.).$arFilter
— фильтр отбора элементов.false, false
— группировку и настройки постраничной навигации.["ID", "IBLOCK_ID"]
— список возвращаемых полей.
- Метод
Update
$el->Update($arElement["ID"], $arFields);
Позволяет изменить поля элемента. В частности, "IBLOCK_SECTION_ID" => $NEW_SECTION_ID
полностью заменяет раздел на новый, убирая привязку к старому.
- Сообщения об ошибках
$el->LAST_ERROR
содержит текст ошибки, еслиUpdate
не выполнился.
3. Привязка к нескольким разделам
Иногда бывает нужно, чтобы товар одновременно находился в нескольких разделах, а не только переместился из одного в другой. В этом случае вместо поля IBLOCK_SECTION_ID
используется метод:
CIBlockElement::SetElementSection($ID, $arrSectionIds);
Например, если нужно привязать элемент к разделам с ID = 20 и ID = 21, а также оставить его в текущем:
$arSections = [10, 20, 21]; // перечень всех разделов, где должен лежать товар
CIBlockElement::SetElementSection($arElement["ID"], $arSections);
При этом старые связи с разделами будут полностью переписаны тем списком, что вы передаете во второй параметр. Если ваша задача — лишь добавить дополнительный раздел, сначала нужно получить текущие привязки элемента (через CIBlockElement::GetElementGroups
), а затем объединить массивы, чтобы не потерять предыдущие.
4. Использование включения подразделов
Если нужно переносить не только товары из указанного раздела, но и из всех вложенных подразделов, достаточно установить:
'INCLUDE_SUBSECTIONS' => 'Y',
Пример кода
$arFilter = [
'IBLOCK_ID' => $IBLOCK_ID,
'SECTION_ID' => $OLD_SECTION_ID,
'INCLUDE_SUBSECTIONS' => 'Y',
];
В этом случае выборка получит товары как из раздела с ID = 10
, так и из всех его дочерних категорий.
5. Дополнительные рекомендации и примеры
5.1 Массовое редактирование через административную панель
Иногда не хочется прибегать к написанию кода, если количество товаров не слишком велико. Для этого можно воспользоваться стандартным массовым редактированием:
- Зайти в административную часть.
- Отфильтровать элементы по разделу.
- Отметить галочками нужные позиции.
- Внизу выбрать «Изменить» (или «Выбрать действие» → «Изменить»).
- На странице массового редактирования проставить нужный раздел и сохранить.
Однако при большом количестве товаров (сотни, тысячи) такой метод все равно не самый удобный — приходится разбивать на страницы по 50–100 элементов. А при регулярном повторении задач по переносу товаров лучше автоматизировать процесс.
5.2 CSV/XML-импорт/экспорт
- Экспорт в CSV/XML
Вы можете выгрузить список нужных товаров, внести правки в таблице (например, указать новые ID разделов) и импортировать обратно.
- Плюсы: стандартные механизмы, интерфейс, возможность правки данных «офлайн».
- Минусы: занимает больше времени, чем простой PHP-скрипт, особенно если нужно делать массовые перенесения регулярно.
5.3 Пошаговая обработка больших массивов товаров
Если у вас очень много товаров (например, десятки тысяч), в одном цикле может произойти превышение по времени выполнения (time limit) или по памяти. Тогда можно сделать пошаговую обработку:
- Выполнять выборку не всех элементов сразу, а порциями по 500 или 1000 (с помощью параметров
array("nPageSize"=>500)
в методеGetList
). - После обновления каждой порции выводить сообщение («Обработано 500 товаров») и перезагружать страницу/скрипт (или использовать
while
-цикл в консоли, если скрипт запускается командойphp myscript.php
). - Переключаться на следующий «лист» (страницу) выборки, пока не будут обработаны все товары.
6. Полноценный пример кода с несколькими сценариями
Ниже приведен более развернутый скрипт, который позволяет:
- Переносить товары из одного или нескольких разделов в новый.
- Учитывать или не учитывать вложенные подразделы.
- Привязывать к одному или нескольким разделам.
- Выводить подробные логи в процессе работы.
<?php
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
CModule::IncludeModule("iblock");
/*
* Пример универсального скрипта для переноса/дополнения привязки товаров к разделам
*/
// Данные для настройки
$IBLOCK_ID = 2; // ID инфоблока, где лежат товары
$OLD_SECTION_IDS = [10]; // Массив старых разделов (можно указать несколько)
$NEW_SECTIONS = [20]; // Список разделов, куда нужно привязать товар
$INCLUDE_SUBSECTIONS = 'N'; // Учитывать вложенные разделы или нет
// Формируем фильтр
$arFilter = [
'IBLOCK_ID' => $IBLOCK_ID,
'SECTION_ID' => $OLD_SECTION_IDS,
'INCLUDE_SUBSECTIONS' => $INCLUDE_SUBSECTIONS,
];
// Получаем список элементов
$rsElements = CIBlockElement::GetList([], $arFilter, false, false, ["ID", "IBLOCK_ID"]);
$el = new CIBlockElement;
// Счетчики
$countAll = 0;
$countSuccess = 0;
$countError = 0;
while ($arElement = $rsElements->Fetch()) {
$countAll++;
// Пример: перенос с заменой старого раздела
// $arFields = [
// "IBLOCK_SECTION_ID" => reset($NEW_SECTIONS), // берем первый из массива
// ];
// $result = $el->Update($arElement["ID"], $arFields);
// Пример: привязка к нескольким разделам (заменяет все старые привязки)
$result = CIBlockElement::SetElementSection($arElement["ID"], $NEW_SECTIONS);
if ($result) {
$countSuccess++;
echo "Товар c ID=" . $arElement["ID"] . " успешно обновлен.<br>";
} else {
$countError++;
global $APPLICATION;
// Если использовали Update()
// echo "Ошибка при переносе товара ID=" . $arElement["ID"] . ": " . $el->LAST_ERROR . "<br>";
// Если использовали SetElementSection()
// Здесь не всегда будет подробное сообщение об ошибке,
// поэтому в случае неудачи отладить можно,
// проверив логи или сделав дополнительную проверку прав etc.
echo "Ошибка при переносе товара ID=" . $arElement["ID"] . "<br>";
}
}
echo "<hr>";
echo "Всего найдено товаров: $countAll<br>";
echo "Успешно перенесено: $countSuccess<br>";
echo "Ошибок: $countError<br>";
7. Заключение
Массовый перенос товаров в 1С-Битрикс из одного раздела в другой не требует ручного редактирования каждой карточки. Достаточно написать и запустить короткий PHP-скрипт, который опирается на стандартные классы модуля iblock
.
Основные преимущества подхода через API:
- Гибкость: можно менять не только раздел, но и любые другие поля (название, цены, свойства и т. д.).
- Автоматизация: сэкономит массу времени, особенно если приходится регулярно корректировать структуру каталога.
- Контроль: вы сами определяете, какие товары переносить (через фильтры).
При правильной настройке скрипта и разумном фильтре (SECTION_ID
, INCLUDE_SUBSECTIONS
, и т. п.) можно решить большинство типовых задач по обновлению структуры каталога без больших трудозатрат. Если же объем данных огромен, возможно, потребуется дополнительная оптимизация: разбивка на порции, обновление поисковых индексов после переноса и т. д.
Используйте эти примеры кода в своих проектах и дорабатывайте их под конкретные бизнес-требования. Если что-то не работает или появляется ошибка — проверяйте логи, а также убедитесь, что у скрипта есть достаточно прав для изменения элементов (важно в случае сложной структуры групп доступа) и что нет конфликта с другими модулями или настройками сайта.
Успешной разработки!