Доработка стандартных компонентов через component_epilog 1С-Битрикс
component_epilog.php — файл в папке шаблона компонента, который выполняется после полного завершения работы компонента, включая рендер шаблона. В отличие от result_modifier.php, здесь уже нельзя повлиять на вывод HTML текущего компонента — зато можно выполнить код с побочными эффектами, не нарушая логику кэширования.
Место в последовательности выполнения
1. component.php (логика, заполняет $arResult)
2. result_modifier.php (модификация $arResult, до рендера)
3. template.php (рендер HTML)
4. component_epilog.php (после рендера — действия, JS, аналитика)
Файл находится в папке шаблона компонента:
/local/templates/{site_template}/components/bitrix/catalog.element/default/component_epilog.php
Чем component_epilog отличается от result_modifier
| result_modifier | component_epilog | |
|---|---|---|
| Когда выполняется | До рендера шаблона | После рендера шаблона |
Доступен $arResult |
Да, для изменения | Да, только для чтения |
| Влияет на HTML компонента | Да (через $arResult) |
Нет |
| Выполняется при кэше | Нет (данные берутся из кэша) | Да, всегда |
| Для JS и аналитики | Нет | Да |
| Для побочных эффектов | Нет | Да |
Ключевое отличие: component_epilog.php выполняется всегда, даже когда компонент отдаёт результат из кэша. Это делает его идеальным местом для кода, который должен работать при каждом запросе — независимо от состояния кэша.
Практические применения
Вывод JS-данных для аналитики (GA4 / Яндекс.Метрика):
Данные товара для аналитики нужны при каждом просмотре страницы, даже если компонент закэширован:
// component_epilog.php для bitrix:catalog.element
if (!empty($arResult['ID'])) {
$price = $arResult['CATALOG_PRICE_1'] ?? 0;
$name = $arResult['NAME'] ?? '';
$category = $arResult['SECTION']['NAME'] ?? '';
$productJson = json_encode([
'id' => $arResult['ID'],
'name' => $name,
'price' => $price,
'category' => $category,
], JSON_UNESCAPED_UNICODE);
// Выводим JS прямо из epilog — или добавляем в <head>
global $APPLICATION;
$APPLICATION->AddHeadScript('');
?>
<script>
window.pageProduct = <?= $productJson ?>;
gtag('event', 'view_item', {
currency: 'RUB',
value: <?= $price ?>,
items: [{ item_id: '<?= $arResult['ID'] ?>', item_name: <?= json_encode($name) ?>, price: <?= $price ?> }]
});
ym(METRIKA_ID, 'reachGoal', 'product_view', { product_id: <?= $arResult['ID'] ?> });
</script>
<?php
}
Регистрация просмотра товара в системе аналитики:
Обновить счётчик просмотров в кастомной таблице при каждом просмотре — не нарушая кэш компонента:
// component_epilog.php для bitrix:catalog.element
if (!empty($arResult['ID'])) {
// Не выполняем для ботов
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
if (preg_match('/bot|crawler|spider|crawling/i', $userAgent)) return;
// Инкрементируем счётчик (без блокирующих запросов — через очередь)
ViewCounterQueue::increment($arResult['ID']);
}
ViewCounterQueue::increment() записывает в Redis или кастомную таблицу — агент периодически сбрасывает накопленные просмотры в основную таблицу пакетным UPDATE.
Связанные товары: дополнение после рендера основного контента:
Если блок «похожие товары» тяжёлый и не должен включаться в кэш основного компонента:
// component_epilog.php для bitrix:catalog.element
if (!empty($arResult['ID'])) {
// Компонент с отдельным кэшом — не зависит от кэша родительского
$APPLICATION->IncludeComponent(
'bitrix:catalog.section',
'related_products',
[
'IBLOCK_ID' => $arResult['IBLOCK_ID'],
'FILTER_IDS' => getRelatedProductIds($arResult['ID']),
'CACHE_TYPE' => 'A',
'CACHE_TIME' => 3600,
]
);
}
Логирование событий без блокировки основного запроса:
// component_epilog.php для bitrix:sale.basket.basket
if (!empty($arResult['ITEMS'])) {
$basketValue = array_sum(array_column($arResult['ITEMS'], 'PRICE'));
// Пишем в лог без ожидания
register_shutdown_function(function() use ($basketValue) {
BasketAnalyticsLog::record([
'fuser_id' => \Bitrix\Sale\Fuser::getId(),
'basket_value' => $basketValue,
'items_count' => count($arResult['ITEMS']),
'timestamp' => time(),
]);
});
}
component_epilog и Ajax-компоненты
Стандартный компонент sale.order.ajax использует AJAX для обновления шагов оформления. В этом случае component_epilog.php выполняется при каждом AJAX-запросе, что может привести к дублированию JS-кода на странице.
Проверяйте, что запрос не AJAX:
// component_epilog.php
if (\Bitrix\Main\Context::getCurrent()->getRequest()->isAjaxRequest()) {
return; // не выводим JS при AJAX-запросах
}
// Основной код epilog здесь
Работа с $arResult в epilog
В component_epilog.php $arResult — это тот же массив, что был в result_modifier.php и template.php. Он доступен для чтения, но изменения в нём не влияют на уже выведенный HTML. Изменения в $arResult в epilog влияют только на код, который вы сами выполняете внутри epilog.
// component_epilog.php
// Это НЕ повлияет на уже выведенный template.php:
$arResult['NAME'] = 'Новое название'; // бесполезно
// Но вы можете использовать $arResult для формирования JS или API-запросов:
$analyticsData = [
'product_id' => $arResult['ID'],
'in_stock' => ($arResult['CATALOG_QUANTITY'] ?? 0) > 0,
];
Структура папки шаблона с обоими файлами
/local/templates/main/components/bitrix/catalog.element/default/
template.php — HTML-шаблон
result_modifier.php — модификация $arResult до рендера
component_epilog.php — JS, аналитика, побочные эффекты после рендера
.description.php — метаданные шаблона (опционально)
style.css — стили (опционально)
script.js — скрипты (опционально)
Оба файла — дополняющие инструменты: result_modifier.php для данных, component_epilog.php для действий. Вместе они позволяют полностью кастомизировать поведение стандартного компонента без касания его исходного кода.
Состав работ: написание component_epilog.php для конкретного компонента с аналитикой и побочными эффектами — 4–8 часов. С очередью просмотров и агентом — ещё 1–2 дня.







