Developing a content distribution system on 1C-Bitrix

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
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • 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
    564
  • 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
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Content Distribution System Development for 1C-Bitrix

Managing content on a single website is straightforward. The problem starts when you have multiple sites: a network of regional portals, a group of thematic resources, a multilingual project, or a marketplace with storefronts for different channels. Replicating changes manually is labor-intensive and unreliable. A content distribution system automates the propagation of materials from a source to consumers with flexible control: what, where, when, and with what transformations.

Architecture: Master and Child Sites

The typical scheme — one master site (content source) and several children (consumers). On Bitrix, this is solved in several ways depending on the infrastructure:

Bitrix multisite — if all sites share one installation. Iblock elements are linked to sites via b_iblock_site. One element can be active on multiple sites simultaneously. Managed via the IBLOCK_ELEMENT.ACTIVE field and site relationships.

Distributed scheme — separate Bitrix installations. An API layer is needed: the master publishes content via REST API or a message queue, child sites subscribe and receive updates.

Hybrid — CDN for media files, API for structured content, direct DB replication for urgent updates.

Distribution Iblock: Tables and Logic

To track what has been distributed where, a custom table is needed:

CREATE TABLE content_distribution (
    ID INT AUTO_INCREMENT PRIMARY KEY,
    SOURCE_ELEMENT_ID INT NOT NULL,    -- element ID on master
    SOURCE_IBLOCK_ID INT NOT NULL,
    TARGET_SITE_ID VARCHAR(8) NOT NULL, -- recipient site ID
    TARGET_ELEMENT_ID INT,             -- ID on child site (NULL before publishing)
    STATUS ENUM('pending','published','failed','excluded') DEFAULT 'pending',
    PUBLISHED_AT DATETIME,
    ERROR TEXT,
    INDEX (SOURCE_ELEMENT_ID),
    INDEX (TARGET_SITE_ID, STATUS)
);

When an element is published on the master — the OnAfterIBlockElementAdd/Update event triggers distribution. The handler checks rules: which child sites should receive this content type, and writes tasks to the table.

Distribution Rules

A flexible rules system determines what content goes where:

// Distribution rules configuration
$distributionRules = [
    [
        'source_iblock_id' => 5,          // "News" iblock
        'target_sites' => ['s2', 's3', 's4'], // All regional sites
        'filter' => [                      // Only specific categories
            'PROPERTY_CATEGORY' => [1, 2], // IDs of "Federal news" sections
        ],
        'transform' => 'NewsTransformer',  // Transformation class
        'delay' => 0,                     // Immediately
    ],
    [
        'source_iblock_id' => 8,          // "Promotions"
        'target_sites' => ['s2'],         // Only for one region
        'filter' => ['PROPERTY_REGION' => 'msk'],
        'transform' => null,              // No transformation
        'delay' => 3600,                  // 1 hour after publishing on master
    ],
];

Content Transformation During Distribution

Content is rarely distributed as-is. Typical transformations:

Link adaptation — absolute internal links must be replaced with links for the child site:

$content = preg_replace(
    '|https://master-site\.ru/([^"\']+)|',
    'https://regional-site.ru/$1',
    $sourceContent
);

Translation — for multilingual projects. Integration with Google Translate API or DeepL for automatic translation, followed by manual proofreading:

$translated = $translationService->translate(
    $element['DETAIL_TEXT'],
    from: 'ru',
    to: $targetSite['LANGUAGE']
);

Regional adaptation — replacing contact details, phone numbers, addresses with regional ones. Implemented via templates with placeholders {{PHONE}}, {{ADDRESS}}, which are substituted during distribution.

Image substitution — different channels may require different formats or sizes. The distribution service resizes on delivery or stores versions.

Handling Edit Conflicts

If manual editing is allowed on a child site — merge logic is needed when updating from the master:

  • "Always overwrite" policy — simplest, but loses local edits
  • "Don't touch manually edited" policyLOCALLY_MODIFIED flag on the element, master doesn't update such items
  • "Field-level merge" policy — some fields always sync (title, main text), others can be local (meta tags, regional data)

Flag implementation via a custom iblock element field:

// When manually saving on the child site
CIBlockElement::SetPropertyValues($elementId, IBLOCK_ID, 'Y', 'LOCALLY_MODIFIED');

// During distribution from master
$locallyModified = CIBlockElement::GetProperty(IBLOCK_ID, $elementId, [], ['CODE' => 'LOCALLY_MODIFIED'])->Fetch();
if ($locallyModified['VALUE'] === 'Y' && $rule['respect_local_edits']) {
    // Skip update
    continue;
}

Queue and Asynchronous Processing

With a large number of sites or elements, synchronous distribution inside an event handler is a bad idea: the user will wait several seconds for the save to complete.

The correct approach: the event handler only creates tasks in the queue, actual distribution is performed by a worker asynchronously.

// Event handler (fast)
public static function onAfterElementUpdate(array $fields): void
{
    if ($fields['IBLOCK_ID'] === MASTER_IBLOCK_ID) {
        DistributionQueue::add($fields['ID'], $fields['IBLOCK_ID']);
    }
}

// Worker (Cron every minute)
// php /var/www/bitrix/local/console/distribute_content.php
$pending = DistributionQueue::getPending(limit: 50);
foreach ($pending as $task) {
    $distributor->distribute($task);
}

Distribution Monitoring

Metric How to track
Distribution lag Difference between CREATED_AT and PUBLISHED_AT in the table
Failed distributions STATUS='failed' in the last hour
Record count discrepancy Compare count on master vs children
Queue Size of STATUS='pending' older than N minutes

Development Stages

Stage Contents Timeline
Design Distribution scheme, rules, policies 3–5 days
System core Queue, worker, status table 1 week
Child site connectors API client or direct DB access 1 week
Transformations Link adaptation, translation, regionalization 1–2 weeks
Admin interface Monitoring, manual trigger, logs 1 week
Testing Integration tests, conflict tests 1 week

Total: 6–10 weeks depending on the number of sites and transformation complexity.