В современном интернет-магазине на 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, и т. п.) можно решить большинство типовых задач по обновлению структуры каталога без больших трудозатрат. Если же объем данных огромен, возможно, потребуется дополнительная оптимизация: разбивка на порции, обновление поисковых индексов после переноса и т. д.
Используйте эти примеры кода в своих проектах и дорабатывайте их под конкретные бизнес-требования. Если что-то не работает или появляется ошибка — проверяйте логи, а также убедитесь, что у скрипта есть достаточно прав для изменения элементов (важно в случае сложной структуры групп доступа) и что нет конфликта с другими модулями или настройками сайта.
Успешной разработки!