Development of a complex 1C-Bitrix component

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

Development of Complex Component for 1C-Bitrix

A complex component is a component that manages a set of child components, determining their composition based on the URL and mounting point on the page. Complex components implement catalog sections, blogs, personal accounts — when a single URL can display a list, a detail page, or a form. Without understanding complex component mechanics, it's impossible to properly implement multi-page functionality in Bitrix.

How a complex component differs from a regular one

A regular component (bitrix:news.detail) outputs a single specific block. A complex component (bitrix:news) is a mounting point for a section. It independently decides which child component to call: if URL is /news/ — show news list, if /news/title-news/ — show detail page.

The complex component connects URLs to child components through the SEF-URL mechanism (Search Engine Friendly) and the page_templates.php file.

Structure of a complex component

/local/components/custom/my.section/
├── .description.php
├── .parameters.php
├── component.php              # dispatcher: determines page type
├── page_templates.php         # URL templates to child components mapping
├── templates/
│   └── .default/
│       ├── template.php       # wrapper template (header, navigation)
│       └── page_templates/    # child component templates
│           ├── list.php
│           └── detail.php

page_templates.php: URL mapping

<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();

$arSefTemplates = [
    // list
    'list'   => '',
    // detail page
    'detail' => '#ELEMENT_CODE#/',
    // section
    'section' => '#SECTION_CODE#/',
    // search
    'search' => 'search/',
];

Bitrix matches the current URL against these templates and determines the page type ($arCurrentValues['PAGE_ELEMENT_TYPE']).

component.php of complex component: dispatcher

<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();

/** @var CBitrixComponent $this */

// Initialize SEF
$this->setFrameMode(true);

if ($arParams['SEF_MODE'] === 'Y') {
    $arSEFUrlTemplates = [];
    $arDefaultSEFUrlTemplates = [
        'list'   => '',
        'detail' => '#ELEMENT_CODE#/',
        'section' => '#SECTION_CODE#/',
    ];
    // ... parse current URL

    // Determine page type
    $page = 'list'; // default

    if (isset($arVariables['ELEMENT_CODE']) && $arVariables['ELEMENT_CODE']) {
        $page = 'detail';
    } elseif (isset($arVariables['SECTION_CODE']) && $arVariables['SECTION_CODE']) {
        $page = 'section';
    }
} else {
    // Parameter mode (not SEF)
    $page = $arParams['PAGE_ELEMENT_TYPE'];
}

// Include appropriate page template
$this->includePageTemplate($page);

Child components in template

File templates/.default/page_templates/list.php calls the child list component:

<?php
// templates/.default/page_templates/list.php
$APPLICATION->IncludeComponent('custom:my.section.list', '', [
    'IBLOCK_ID'     => $arParams['IBLOCK_ID'],
    'SECTION_ID'    => $arResult['VARIABLES']['SECTION_ID'] ?? 0,
    'SECTION_CODE'  => $arResult['VARIABLES']['SECTION_CODE'] ?? '',
    'PAGE_SIZE'     => $arParams['PAGE_SIZE'],
    'CACHE_TIME'    => $arParams['CACHE_TIME'],
    'SET_TITLE'     => 'Y',
    'SET_BROWSER_TITLE' => 'Y',
], $component);

Parameter $component (reference to parent component) is critical. Without it, the child component cache will be independent from the parent's, which breaks invalidation.

Parameters of complex component

The complex component unifies parameters of all children — pagination settings, caching, SEF templates:

// .parameters.php
$arComponentParameters = [
    'GROUPS' => [...],
    'PARAMETERS' => [
        'SEF_MODE' => [
            'NAME'    => 'SEF Mode',
            'TYPE'    => 'CHECKBOX',
            'DEFAULT' => 'Y',
        ],
        'SEF_FOLDER' => [
            'NAME'    => 'SEF Folder',
            'TYPE'    => 'STRING',
            'DEFAULT' => '/news/',
        ],
        'IBLOCK_ID' => ['...'],
        'PAGE_SIZE' => [
            'NAME'    => 'Items per page',
            'TYPE'    => 'STRING',
            'DEFAULT' => '12',
        ],
        'DETAIL_URL'  => ['DEFAULT' => '#SITE_DIR##SECTION_CODE#/#ELEMENT_CODE#/'],
        'SECTION_URL' => ['DEFAULT' => '#SITE_DIR##SECTION_CODE#/'],
        'INDEX_URL'   => ['DEFAULT' => '#SITE_DIR#'],
        // ... SEF URL templates
    ],
];

Error handling and 404

If an element or section is not found, the complex component should return a proper 404:

// In child detail component
if (!$element) {
    LocalRedirect(SITE_DIR . '404.php');
    // or:
    \Bitrix\Main\Response\HttpResponse::create()->setStatus('404 Not Found')->send();
    require(Application::getDocumentRoot() . '/404.php');
    die();
}

Access rights in complex components

If a section requires authorization (personal account, B2B), the complex component checks rights before calling children:

// In component.php
global $USER;
if (!$USER->IsAuthorized()) {
    LocalRedirect(SITE_DIR . 'login/?backurl=' . urlencode($APPLICATION->GetCurPage()));
    die();
}
// Check user group
if (!$USER->IsInGroup($arParams['ALLOWED_GROUP_ID'])) {
    $APPLICATION->SetStatus('403 Forbidden');
    $APPLICATION->RestartBuffer();
    require($_SERVER['DOCUMENT_ROOT'] . '/403.php');
    die();
}

Caching in complex components

A complex component is rarely cached itself (dispatcher logic is cheap). Children are cached. Important: the child component cache key must include URL variables (ELEMENT_CODE, SECTION_CODE), otherwise all pages will show identical cached responses.

In child component class:

$cacheId = serialize([
    $arParams['IBLOCK_ID'],
    $arParams['ELEMENT_CODE'],
    $USER->GetGroups(), // different groups see different content
    LANGUAGE_ID,
]);
if ($this->StartResultCache($arParams['CACHE_TIME'], $cacheId)) {
    // ...
}

Testing complex component

Before delivery — a checklist:

  • All pages (list, detail, section) work in SEF and parameter modes
  • 404 is returned for non-existent elements/sections
  • Cache invalidates when element is updated in admin
  • Component works on all sites in multi-site installation
  • Breadcrumbs display correctly on all page types

Timeline

Type What's included Duration
2 page types (list + detail) SEF, cache, parameters, templates 1–2 weeks
3–4 page types + section, search, rights 2–4 weeks
Full section (Personal account, catalog) + AJAX, authorization, filters 4–8 weeks

A complex component is the correct architecture for any section with multiple page types. This isn't over-engineering — it's a prerequisite for sites that plan to maintain and evolve.