Setting up bulk editing of 1C-Bitrix products

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1212
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    815
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    565
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    980

Bulk Product Editing Setup in 1C-Bitrix

Catalog has 5000 products, 800 need one field updated — say, add "bestseller" flag. Editing one by one is a work day. Standard bulk editing in Bitrix admin covers most scenarios but has limitations you need to know.

Standard Bulk Editing Mechanism

In product list admin (/bitrix/admin/iblock_list_admin.php?type=catalog) select needed positions, then "Edit selected" action. Form opens where only changed fields specified — others remain unchanged.

Technically works via CIBlockElement::Update() called for each selected ID. Parameter $bWorkFlow = false — no draft creation. On property update, Bitrix rewrites only passed properties, not touching others.

Standard mechanism limitation: doesn't work with multiple properties (type L with multiple values) and doesn't support conditional update ("set value only if current empty").

Bulk Update via API

For updating many products via script correctly use D7 API with batch processing:

$productIds = [1001, 1002, 1003, /* ... */];
$batchSize  = 50;
$chunks     = array_chunk($productIds, $batchSize);

foreach ($chunks as $chunk) {
    foreach ($chunk as $id) {
        \CIBlockElement::Update($id, false, [
            'PROPERTY_VALUES' => [
                'IS_HIT' => 'Y',
            ],
        ]);
    }
    // Small delay between batches to not overload MySQL
    usleep(100000); // 100ms
}

For purely table data (b_catalog_product fields, not infoblock properties) direct update faster via D7:

\Bitrix\Catalog\ProductTable::updateMulti($productIds, [
    'VAT_ID'       => 3,
    'VAT_INCLUDED' => 'Y',
]);

Method updateMulti executes single SQL UPDATE with WHERE ID IN (...) instead of N separate queries.

Property Update with Indexing

On bulk property update Bitrix by default reindexes for each element — calls CSearch::Index(). Updating 1000 products creates 1000 inserts in b_search_content.

Disable reindexing on bulk update:

define('BX_SKIP_SEARCH_REINDEX', true);
// ... bulk update ...

// After — run reindexing with single agent
\Bitrix\Main\Config\Option::set('search', 'reindex_pending', 'Y');

After bulk update completion, agent CSearchReindex::AgentReindex() batch rebuilds index.

Changed Fields in Single Transaction

Updating multiple fields of one product should go in single Update() call, not multiple sequential calls. Each CIBlockElement::Update() call triggers events, updates cache, creates change log entry (if iblock.workflow module enabled). Extra calls increase operation time proportionally.

Progress Monitoring

On bulk update via web interface Bitrix uses "continuation" mechanism via sessid parameter and hidden fields — every N elements page reloads with progress. For script processing more convenient to write progress to file and read via AJAX:

file_put_contents('/tmp/update_progress.json', json_encode([
    'processed' => $processed,
    'total'     => $total,
    'percent'   => round($processed / $total * 100),
]));

When bulk updating "list" type (L) properties, first get ID of list value from b_iblock_property_enum — must pass ID, not text value.