Блог разработчика 1С-Битрикс

CBitrixComponentTemplate: практическое руководство с примерами

Класс CBitrixComponentTemplate — «оболочка» шаблона компонента. На каждый подключаемый шаблон создаётся свой экземпляр класса, который живёт от инициализации шаблона до завершения работы компонента. Ниже — понятное описание жизненного цикла, обзор ключевых методов и много рабочих примеров.

CBitrixComponentTemplate: практическое руководство

Важно: объект шаблона (&$this->GetTemplate()) доступен только после подключения шаблона методом $this->IncludeComponentTemplate(). До этого момента GetTemplate() вернёт null.


Когда и где доступен объект шаблона

Неправильно (объекта ещё нет):

<?php
// .class.php или .component.php (раньше времени)
$template = &$this->GetTemplate(); // null, шаблон ещё не инициализирован
?>

Правильно:

<?php
// .class.php или .component.php
$this->IncludeComponentTemplate(); // <- подключили шаблон
// ...любой ваш код после подключения шаблона
$template = &$this->GetTemplate();              // объект CBitrixComponentTemplate
$templateFile = $template->GetFile();           // путь к template.php
$templateFolder = $template->GetFolder();       // путь к папке шаблона
?>

Внутри template.php переменная $this — это сам CBitrixComponentTemplate, а не компонент. Компонент доступен как $component.


Быстрый справочник по часто используемым методам

  • GetSiteTemplate() — имя шаблона сайта, где лежит шаблон компонента; системным шаблонам вернёт пустую строку.
  • GetName() — имя шаблона компонента.
  • GetFolder() — путь к папке шаблона относительно корня сайта (или пустая строка, если шаблон — одиночный файл).
  • GetFile() — путь к файлу шаблона относительно корня сайта.
  • getComponent() — вернёт экземпляр CBitrixComponent (с версии 15.5.10).
  • addExternalCss() — подключает внешний CSS (с версии 15.5.1).
  • addExternalJs() — подключает внешний JS (с версии 15.5.1).

Дополнительно (очень полезно):

  • SetViewTarget()/EndViewTarget() — врезки в layout через ShowViewContent.
  • setFrameMode()/createFrame() — композит.
  • AddEditAction()/AddDeleteAction()/GetEditAreaId() — области редактирования.
  • IncludeLangFile() — загрузка языковых файлов шаблона.
  • GetPageName() — возвращает имя страницы шаблона (например, template).
  • hasTemplate(), hasTemplatePage() — проверки наличия шаблона/страницы (актуально для поздних версий ядра).

Мини-компонент: структура и базовый пример

Файл .class.php (класс компонента)

<?php
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
class DemoTemplateAwareComponent extends CBitrixComponent
{
    protected function prepareResult(): void
    {
        $this->arResult['ITEMS'] = [
            ['ID' => 1, 'TITLE' => 'Первый'],
            ['ID' => 2, 'TITLE' => 'Второй'],
            ['ID' => 3, 'TITLE' => 'Третий'],
        ];
    }
    public function executeComponent(): void
    {
        $this->prepareResult();
        // Подключаем шаблон
        $this->IncludeComponentTemplate();
        // После подключения шаблона доступен объект CBitrixComponentTemplate:
        $template = &$this->GetTemplate();
        if ($template)
        {
            // Пример: получим пути
            $file   = $template->GetFile();   // /local/templates/..../components/.../template.php
            $folder = $template->GetFolder(); // /local/templates/..../components/.../
            // Здесь можно писать логику, опираясь на сведения о шаблоне
            // file_put_contents($_SERVER['DOCUMENT_ROOT'].'/local/log.txt', $file.PHP_EOL, FILE_APPEND);
        }
    }
}
?>

Файл templates/.default/template.php

<?php if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
/** @var CBitrixComponentTemplate $this */
/** @var CBitrixComponent $component */
/** @var array $arParams */
/** @var array $arResult */
// С версии 15.5.1 можно подключать внешние файлы:
$this->addExternalCss("/local/assets/css/common.css");
$this->addExternalJs("/local/assets/js/common.js");
// Композитный режим — указываем, что шаблон дружит с композитом
$this->setFrameMode(true);
// Языковые файлы шаблона (если нужны):
$this->IncludeLangFile(); // загрузит lang/<LANG>/template.php для этого template.php
// Пример врезки в layout (sidebar/footer/и т.п.)
$this->SetViewTarget('sidebar', 100);
?>
    <div class="widget">
        <div class="widget__title"><?=GetMessage('WIDGET_TITLE', ['#CNT#' => count($arResult['ITEMS'])]);?></div>
        <div class="widget__body">Любой HTML для сайдбара</div>
    </div>
<?php
$this->EndViewTarget();
// Список с областями редактирования
?>
<div class="list">
<?php foreach ($arResult['ITEMS'] as $item): ?>
    <?php
    // Области редактирования (появятся иконки в публичной части)
    $this->AddEditAction(
        'ITEM'.$item['ID'],
        '/bitrix/admin/iblock_element_edit.php?ID='.$item['ID'],
        GetMessage('EDIT_ITEM')
    );
    $this->AddDeleteAction(
        'ITEM'.$item['ID'],
        '/?action=delete&id='.$item['ID'],
        GetMessage('DELETE_ITEM'),
        ['CONFIRM' => GetMessage('CONFIRM_DELETE')]
    );
    ?>
    <div id="<?=$this->GetEditAreaId('ITEM'.$item['ID']);?>" class="list__item">
        <span class="list__title"><?=htmlspecialcharsbx($item['TITLE']);?></span>
        <?php
        // Пример частично динамического фрагмента в композите
        $frame = $this->createFrame('time_'.$item['ID'])->begin();
            echo '<small class="list__time">'.date('H:i:s').'</small>';
        $frame->end();
        ?>
    </div>
<?php endforeach; ?>
</div>

Файл templates/.default/lang/ru/template.php

<?php
$MESS['WIDGET_TITLE'] = 'Виджет (элементов: #CNT#)';
$MESS['EDIT_ITEM'] = 'Редактировать элемент';
$MESS['DELETE_ITEM'] = 'Удалить элемент';
$MESS['CONFIRM_DELETE'] = 'Удалить безвозвратно?';
?>

result_modifier.php (опционально)

<?php if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
// Здесь вы можете обогатить $arResult перед выводом шаблона
foreach ($arResult['ITEMS'] as &$item) {
    $item['URL'] = '/catalog/'.$item['ID'].'/';
}
unset($item);
?>

component_epilog.php (опционально)

<?php if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
/** @var array $templateData */   // можно передать из template.php
/** @var string $templateFile */
/** @var string $templateFolder */
// Например, подключим ещё один JS уже после основного контента
global $APPLICATION;
$APPLICATION->AddHeadScript($templateFolder.'/late.js');
?>

Как передать $templateData в component_epilog.php:

Внутри template.php просто установите $templateData = ['foo' => 'bar']; — ядро само передаст массив.


Подключение внешних файлов (CSS, JS) из шаблона

С версии 15.5.1:

// Внутри template.php
$this->addExternalCss("/local/styles.css");
$this->addExternalJs("/local/lib.js"); // <-- верное имя метода (не addExternalJS)

Преимущества:

  • файлы учитываются в кэше шаблона (ядро запоминает их и подключает на кэш-хитах);
  • корректная агрегация через родительские компоненты при вложенных шаблонах.

Полезные приёмы

1) Быстрая диагностика путей шаблона (в коде компонента)

$this->IncludeComponentTemplate();
$template = &$this->GetTemplate();
if ($template)
{
    $info = [
        'SITE_TEMPLATE'  => $template->GetSiteTemplate(),
        'NAME'           => $template->GetName(),
        'PAGE'           => method_exists($template, 'GetPageName') ? $template->GetPageName() : null,
        'FOLDER'         => $template->GetFolder(),
        'FILE'           => $template->GetFile(),
        'IN_THEME'       => method_exists($template, 'IsInTheme') ? $template->IsInTheme() : null,
    ];
    // dump($info); // выведите в лог/панель разработчика
}

2) Доступ к самому компоненту из шаблона

// template.php
$component = $this->getComponent(); // CBitrixComponent
$params    = $component->arParams;
$relPath   = $component->GetRelativePath();

3) Врезки в layout через view targets

// template.php
$this->SetViewTarget('after_breadcrumbs', 200);
?>
    <div class="promo">Промоблок после хлебных крошек</div>
<?php
$this->EndViewTarget();
// В header.php или другом layout:
$APPLICATION->ShowViewContent('after_breadcrumbs');

4) Композит: динамические куски

// template.php
$this->setFrameMode(true);
$frame = $this->createFrame()->begin();
// ... динамический HTML (например, время, счётчик, статус корзины)
echo '<span class="status">'.date('H:i:s').'</span>';
$frame->end();

5) Языковые файлы для разных частей шаблона

// В template.php, если нужен другой lang-файл:
$this->IncludeLangFile('partial.php'); // загрузит lang/<LANG>/partial.php
echo GetMessage('PARTIAL_TITLE');

6) Проверка наличия шаблона/страницы (актуально для современных версий)

$this->IncludeComponentTemplate();
$template = &$this->GetTemplate();
if (method_exists($template, 'hasTemplate') && !$template->hasTemplate()) {
    // fallback, если каталог шаблона отсутствует
}
if (method_exists($template, 'hasTemplatePage') && !$template->hasTemplatePage('template')) {
    // обработайте отсутствие файла страницы, если нужно
}

Кэш и «автоматические» файлы шаблона

Если в папке шаблона лежат style.css и/или script.js, ядро подключит их автоматически при IncludeTemplate. Это же учитывается в кэше (см. внутренние методы GetCachedData() / ApplyCachedData()), а также внешние файлы, добавленные через addExternalCss()/addExternalJs().


Частые ошибки и как их исправить

  1. Ранний вызов GetTemplate()
    Решение: вызывайте только после $this->IncludeComponentTemplate().
  2. Неверный регистр метода подключения JS
    Было: $this->addExternalJS('/path.js');
    Правильно: $this->addExternalJs('/path.js');
  3. Забыли EndViewTarget()
    Решение: всегда закрывайте SetViewTarget() парой EndViewTarget(); удобно оборачивать в try/finally, если внутри есть логика.
  4. Вывод динамики без композит-рамки
    Решение: setFrameMode(true) + createFrame()->begin(); ... ->end();.
  5. Неправильная экранизация
    Любые пользовательские данные выводим через htmlspecialcharsbx().

Расширенный пример (полезный каркас шаблона)

<?php if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
/** @var CBitrixComponentTemplate $this */
/** @var CBitrixComponent $component */
/** @var array $arParams */
/** @var array $arResult */
// 1) Композит
$this->setFrameMode(true);
// 2) CSS/JS
$this->addExternalCss($this->GetFolder()."/assets/template.css");
$this->addExternalJs($this->GetFolder()."/assets/template.js");
// 3) Язык
$this->IncludeLangFile(); // lang/<LANG>/template.php
// 4) Врезка в шапку/сайдбар
$this->SetViewTarget('sidebar', 150);
?>
    <aside class="box box--sticky">
        <h3><?=GetMessage('SIDEBAR_TITLE');?></h3>
        <p><?=GetMessage('SIDEBAR_TEXT');?></p>
    </aside>
<?php
$this->EndViewTarget();
// 5) Контент
?>
<section class="cards">
<?php foreach ($arResult['ITEMS'] as $item): ?>
    <?php
    $id = (int)$item['ID'];
    $safeTitle = htmlspecialcharsbx($item['TITLE']);
    $this->AddEditAction(
        'ITEM'.$id,
        '/bitrix/admin/iblock_element_edit.php?ID='.$id,
        GetMessage('EDIT_ITEM')
    );
    $this->AddDeleteAction(
        'ITEM'.$id,
        '/?action=delete&id='.$id,
        GetMessage('DELETE_ITEM'),
        ['CONFIRM' => GetMessage('CONFIRM_DELETE')]
    );
    ?>
    <article id="<?=$this->GetEditAreaId('ITEM'.$id);?>" class="card">
        <h4 class="card__title"><?=$safeTitle;?></h4>
        <?php $frame = $this->createFrame('dyn_'.$id, true)->begin(); ?>
            <div class="card__meta"><?=GetMessage('NOW_TIME')?>: <?=date('H:i:s');?></div>
        <?php $frame->end(); ?>
        <?php if (!empty($item['URL'])): ?>
            <a class="card__link" href="<?=htmlspecialcharsbx($item['URL']);?>"><?=GetMessage('OPEN');?></a>
        <?php endif; ?>
    </article>
<?php endforeach; ?>
</section>
<?php
// 6) Передать данные в component_epilog.php
$templateData = [
    'TIMESTAMP' => time(),
];
?>

lang/ru/template.php для этого примера:

<?php
$MESS['SIDEBAR_TITLE'] = 'Боковая панель';
$MESS['SIDEBAR_TEXT']  = 'Любой текст виджета.';
$MESS['EDIT_ITEM']     = 'Редактировать';
$MESS['DELETE_ITEM']   = 'Удалить';
$MESS['CONFIRM_DELETE']= 'Вы уверены?';
$MESS['NOW_TIME']      = 'Время';
$MESS['OPEN']          = 'Открыть';
?>

Вопросы навигации и поиска шаблонов

Ядро ищет шаблоны по множеству путей (локальные/стандартные, в контексте родительского шаблона и сайта). В современных версиях доступны вспомогательные методы:

$this->IncludeComponentTemplate();
$template = &$this->GetTemplate();
// Есть ли папка шаблона?
if (method_exists($template, 'hasTemplate') && $template->hasTemplate()) {
    // ...
}
// Есть ли конкретная страница внутри шаблона?
if (method_exists($template, 'hasTemplatePage') && $template->hasTemplatePage('template')) {
    // ...
}
// Получить список возможных путей (для отладки/диагностики)
if (method_exists($template, 'generatePossibleTemplatePath')) {
    $paths = $template->generatePossibleTemplatePath();
    // print_r($paths);
}

Заключение

CBitrixComponentTemplate — это не только «обёртка», но и мощный инструмент интеграции шаблона с ядром: подключение ресурсов, композит, локализация, врезки в layout, области редактирования, post-epilog и многое другое. Пользуйтесь им по назначению:

  • получайте объект шаблона после IncludeComponentTemplate();
  • подключайте CSS/JS через addExternalCss()/addExternalJs();
  • используйте setFrameMode()/createFrame() для композита;
  • применяйте SetViewTarget() для гибкого layout;
  • помните про локализацию и экранирование.

Этот набор приёмов покрывает 99% практических задач при работе с шаблонами компонентов в 1С-Битрикс.

Теги: CBitrixComponentTemplate, шаблоны компонентов, разработка на Битрикс


Валерий Макеев
07.09.2025 13:22
Активируем композит, подключаем внешние CSS/JS, выводим список элементов с имитацией динамического счётчика просмотров и добавляем в футер врезку со статистикой через SetViewTarget.
Код
<?php if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();

// Подключает стили и скрипты шаблона, активирует композит, выводит список элементов с динамическим счётчиком просмотров и добавляет врезку в футер с общей статистикой
$this->setFrameMode(true);
$this->addExternalCss($this->GetFolder() . '/assets/style.css');
$this->addExternalJs($this->GetFolder() . '/assets/stats.js');

$this->SetViewTarget('footer_stats');
?>
<div class="footer-stats">
    <?= GetMessage('TOTAL_ITEMS') ?>: <strong><?= count($arResult['ITEMS']) ?></strong>,
    <?= GetMessage('UPDATED_AT') ?>: <time><?= date('H:i') ?></time>
</div>
<?php
$this->EndViewTarget();
?>

<div class="items-list">
    <?php foreach ($arResult['ITEMS'] as $item): ?>
        <div class="item">
            <h3><?= htmlspecialcharsbx($item['TITLE']) ?></h3>
            <?php $frame = $this->createFrame('views_' . $item['ID'])->begin(); ?>
                <small><?= GetMessage('VIEWS') ?>: <?= rand(10, 999) ?></small>
            <?php $frame->end(); ?>
        </div>
    <?php endforeach; ?>
</div>

<?php
$templateData = ['component_used' => true];

Стоимость услуг по разработке и сопровождению сайтов на 1C-Битрикс

Интернет-магазин на готовом решении

от 7 дней

от 40 000 рублей
запуск сайта в максимально короткие сроки

* указана минимальная стоимость. Стоимость выбранной лицензии «1С-Битрикс» оплачивается отдельно.

Участие в проекте

привлечение в проект на part-time основе

от 30 000 рублей / неделя

Возможно участие в проекте на ежедневной основе, как разработчика. Занятость - до 20 часов в неделю
Минимальный срок - одна неделя.

* сумма фиксированная

Разработка интернет-магазина с готовой версткой

от 4 недель

от 90 000 рублей

* указана минимальная стоимость. Стоимость выбранной лицензии «1С-Битрикс» оплачивается отдельно.