[{"data":1,"prerenderedAt":36},["ShallowReactive",2],{"article:bitrix-deferred-functions":3},{"html":4,"toc":5},"\u003Cp>Шаблон сайта выводит H1 раньше, чем компонент получает название товара. Хлебные крошки находятся над содержимым, а последний пункт цепочки становится известен внутри компонента. В обоих случаях место вывода уже пройдено, но данные ещё можно подставить — через отложенные функции Битрикс.\u003C\u002Fp>\n\u003Cp>Механизм оставляет место в буфере страницы и вычисляет его содержимое при сборке HTML. Для заголовков и метатегов есть штатные методы, для готового HTML — именованные области, для собственного вычисления — \u003Ccode>AddBufferContent()\u003C\u002Fcode>. Кеш компонента влияет на то, какой код выполнится повторно, поэтому для шаблона и эпилога приёмы различаются.\u003C\u002Fp>\n\u003Ch2 id=\"section-1\">Вывести поздний заголовок: ShowTitle() вместо GetTitle()\u003C\u002Fh2>\n\u003Cp>Если H1 расположен в \u003Ccode>header.php\u003C\u002Fcode> шаблона сайта, обычное получение заголовка может сработать слишком рано:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">&lt;h1&gt;\u003Cspan class=\"hljs-meta\">&lt;?=\u003C\u002Fspan> \u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">GetTitle\u003C\u002Fspan>() \u003Cspan class=\"hljs-meta\">?&gt;\u003C\u002Fspan>&lt;\u002Fh1&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>GetTitle()\u003C\u002Fcode> возвращает текущее значение. Последующий \u003Ccode>SetTitle()\u003C\u002Fcode> не изменит уже выведенную строку. Замените этот фрагмент отложенным выводом:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">&lt;h1&gt;\u003Cspan class=\"hljs-meta\">&lt;?php\u003C\u002Fspan> \u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">ShowTitle\u003C\u002Fspan>(\u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>); \u003Cspan class=\"hljs-meta\">?&gt;\u003C\u002Fspan>&lt;\u002Fh1&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>В коде страницы после подключения \u003Ccode>\u002Fbitrix\u002Fheader.php\u003C\u002Fcode> задайте заголовок:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">SetTitle\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'Доставка'\u003C\u002Fspan>);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Когда Битрикс соберёт буфер, H1 получит «Доставка». \u003Ccode>ShowTitle()\u003C\u002Fcode> регистрирует получение значения через \u003Ccode>AddBufferContent()\u003C\u002Fcode>: функция читает заголовок позднее, а её результат вставляется на место вызова в шаблоне.\u003C\u002Fp>\n\u003Cp>Это работа в пределах текущего серверного запроса. Отложенная функция не создаёт фоновую задачу и не запускает JavaScript. Сам \u003Ccode>ShowTitle()\u003C\u002Fcode> не нужно оборачивать в \u003Ccode>echo\u003C\u002Fcode> или ещё один \u003Ccode>AddBufferContent()\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"section-2\">Задать разные H1 и title, вывести description\u003C\u002Fh2>\n\u003Cp>Название в тексте страницы и заголовок вкладки браузера часто различаются. Например, H1 должен быть коротким, а \u003Ccode>&lt;title&gt;\u003C\u002Fcode> — уточнять тему. В коде страницы после подключения шапки задайте оба значения и описание:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">SetTitle\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'Доставка'\u003C\u002Fspan>);\n\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">SetPageProperty\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'title'\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">'Условия доставки заказов'\u003C\u002Fspan>);\n\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">SetPageProperty\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'description'\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">'Сроки и способы получения заказа.'\u003C\u002Fspan>);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Внутри \u003Ccode>&lt;head&gt;\u003C\u002Fcode> файла \u003Ccode>header.php\u003C\u002Fcode> шаблона сайта:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">&lt;title&gt;\u003Cspan class=\"hljs-meta\">&lt;?php\u003C\u002Fspan> \u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">ShowTitle\u003C\u002Fspan>(); \u003Cspan class=\"hljs-meta\">?&gt;\u003C\u002Fspan>&lt;\u002Ftitle&gt;\n\u003Cspan class=\"hljs-meta\">&lt;?php\u003C\u002Fspan> \u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">ShowHead\u003C\u002Fspan>(); \u003Cspan class=\"hljs-meta\">?&gt;\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Для H1 внутри \u003Ccode>&lt;body&gt;\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">&lt;h1&gt;\u003Cspan class=\"hljs-meta\">&lt;?php\u003C\u002Fspan> \u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">ShowTitle\u003C\u002Fspan>(\u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>); \u003Cspan class=\"hljs-meta\">?&gt;\u003C\u002Fspan>&lt;\u002Fh1&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>ShowTitle()\u003C\u002Fcode> без параметра сначала ищет свойство \u003Ccode>title\u003C\u002Fcode>, затем использует значение из \u003Ccode>SetTitle()\u003C\u002Fcode>. Параметр \u003Ccode>false\u003C\u002Fcode> отключает поиск свойства: H1 получит «Доставка», а \u003Ccode>&lt;title&gt;\u003C\u002Fcode> — «Условия доставки заказов».\u003C\u002Fp>\n\u003Cp>\u003Ccode>ShowHead()\u003C\u002Fcode> уже выводит стандартные метатеги и ресурсы страницы. Не добавляйте рядом отдельный \u003Ccode>ShowMeta('description')\u003C\u002Fcode>, иначе описание может продублироваться. \u003Ccode>ShowMeta()\u003C\u002Fcode> нужен при самостоятельной сборке метатегов, а \u003Ccode>ShowProperty()\u003C\u002Fcode> выводит значение свойства без разметки метатега. Он не экранирует произвольный HTML автоматически.\u003C\u002Fp>\n\u003Cp>Для ресурсов также существуют \u003Ccode>ShowHeadStrings()\u003C\u002Fcode>, \u003Ccode>ShowHeadScripts()\u003C\u002Fcode> и \u003Ccode>ShowCSS()\u003C\u002Fcode>; обычно достаточно штатного \u003Ccode>ShowHead()\u003C\u002Fcode>. \u003Ccode>ShowTitle()\u003C\u002Fcode> удаляет теги, но не является универсальным экранированием для любого HTML-контекста. Пользовательский текст внутри собственного HTML-фрагмента нужно экранировать при формировании этого фрагмента.\u003C\u002Fp>\n\u003Ch2 id=\"section-3\">Добавить пункт хлебных крошек ниже места их вывода\u003C\u002Fh2>\n\u003Cp>Хлебные крошки обычно размещают в начале рабочей области шаблона, а данные текущего объекта получает компонент ниже. Стандартный компонент \u003Ccode>bitrix:breadcrumb\u003C\u002Fcode> использует отложенное получение цепочки, поэтому позднее добавленный пункт попадёт на своё место.\u003C\u002Fp>\n\u003Cp>В \u003Ccode>header.php\u003C\u002Fcode> шаблона, внутри \u003Ccode>&lt;body&gt;\u003C\u002Fcode>, подключите цепочку:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">IncludeComponent\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'bitrix:breadcrumb'\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">''\u003C\u002Fspan>, [\n    \u003Cspan class=\"hljs-string\">'START_FROM'\u003C\u002Fspan> =&gt; \u003Cspan class=\"hljs-string\">'0'\u003C\u002Fspan>,\n    \u003Cspan class=\"hljs-string\">'PATH'\u003C\u002Fspan> =&gt; \u003Cspan class=\"hljs-string\">''\u003C\u002Fspan>,\n    \u003Cspan class=\"hljs-string\">'SITE_ID'\u003C\u002Fspan> =&gt; SITE_ID,\n]);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>В коде страницы после подключения шапки добавьте пункт:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">AddChainItem\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'Доставка'\u003C\u002Fspan>);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Компонент регистрирует вызов \u003Ccode>GetNavChain()\u003C\u002Fcode> через \u003Ccode>AddBufferContent()\u003C\u002Fcode>. Цепочка собирается после того, как страница добавила свои пункты. Если компонент контента уже добавляет этот пункт сам, повторный \u003Ccode>AddChainItem()\u003C\u002Fcode> не нужен: отложенный вывод не удаляет дубли.\u003C\u002Fp>\n\u003Cp>Для цепочки есть и штатный \u003Ccode>ShowNavChain()\u003C\u002Fcode>. Другой пример встроенного отложенного вывода — \u003Ccode>ShowPanel()\u003C\u002Fcode>, который размещает административную панель на публичной странице. Писать собственный callback для этих задач обычно не требуется.\u003C\u002Fp>\n\u003Ch2 id=\"section-4\">Вывести готовый HTML выше по странице: ShowViewContent() и AddViewContent()\u003C\u002Fh2>\n\u003Cp>Именованная область подходит для сообщения, баннера или дополнительного блока, который должен появиться раньше кода, формирующего его содержимое. В шаблоне сайта обозначьте место:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">ShowViewContent\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'catalog_notice'\u003C\u002Fspan>);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Позднее, например в коде страницы после подключения шапки, добавьте HTML:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">AddViewContent\u003C\u002Fspan>(\n    \u003Cspan class=\"hljs-string\">'catalog_notice'\u003C\u002Fspan>,\n    \u003Cspan class=\"hljs-string\">'&lt;p&gt;Наличие товара уточняется при подтверждении заказа.&lt;\u002Fp&gt;'\u003C\u002Fspan>,\n    \u003Cspan class=\"hljs-number\">100\u003C\u002Fspan>\n);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>ShowViewContent()\u003C\u002Fcode> откладывает чтение области, а \u003Ccode>AddViewContent()\u003C\u002Fcode> добавляет готовую строку. Третий аргумент задаёт позицию: фрагмент с позицией \u003Ccode>100\u003C\u002Fcode> появится раньше фрагмента с позицией \u003Ccode>200\u003C\u002Fcode>, независимо от порядка добавления.\u003C\u002Fp>\n\u003Cp>Несколько добавлений объединяются. Два вызова \u003Ccode>ShowViewContent()\u003C\u002Fcode> покажут область в двух местах, а пустая область ничего не выведет. При необходимости очистить её используйте \u003Ccode>$APPLICATION-&gt;clearViewContent('catalog_notice')\u003C\u002Fcode>. Имя должно отличаться от имён областей других компонентов.\u003C\u002Fp>\n\u003Cp>Так удобно добавлять HTML из кода страницы или эпилога компонента. Для кешируемого \u003Ccode>template.php\u003C\u002Fcode> нужен следующий приём: обычный \u003Ccode>AddViewContent()\u003C\u002Fcode> не сохраняет область в данных кеша шаблона.\u003C\u002Fp>\n\u003Ch2 id=\"section-5\">Вывести анонс news.detail над компонентом и сохранить его в кеше\u003C\u002Fh2>\n\u003Cp>Допустим, \u003Ccode>bitrix:news.detail\u003C\u002Fcode> выводит подробный текст новости, а её анонс должен находиться выше — в шаблоне сайта. Если добавить область обычным \u003Ccode>AddViewContent()\u003C\u002Fcode> из \u003Ccode>template.php\u003C\u002Fcode>, она может исчезнуть при попадании в кеш. Пара \u003Ccode>SetViewTarget()\u003C\u002Fcode> \u002F \u003Ccode>EndViewTarget()\u003C\u002Fcode> сохраняет захваченный HTML вместе с данными компонента.\u003C\u002Fp>\n\u003Cp>В \u003Ccode>header.php\u003C\u002Fcode> шаблона сайта, внутри \u003Ccode>&lt;body&gt;\u003C\u002Fcode> перед содержимым страницы, задайте место анонса:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">ShowViewContent\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'news_announcement'\u003C\u002Fspan>);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>В \u003Ccode>template.php\u003C\u002Fcode> компонента \u003Ccode>news.detail\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-meta\">&lt;?php\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!\u003Cspan class=\"hljs-title function_\">defined\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'B_PROLOG_INCLUDED'\u003C\u002Fspan>) || B_PROLOG_INCLUDED !== \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>) { \u003Cspan class=\"hljs-keyword\">die\u003C\u002Fspan>(); }\n\u003Cspan class=\"hljs-comment\">\u002F** \u003Cspan class=\"hljs-doctag\">@var\u003C\u002Fspan> CBitrixComponentTemplate $this *\u002F\u003C\u002Fspan>\n\u003Cspan class=\"hljs-variable\">$announcement\u003C\u002Fspan> = (\u003Cspan class=\"hljs-keyword\">string\u003C\u002Fspan>)(\u003Cspan class=\"hljs-variable\">$arResult\u003C\u002Fspan>[\u003Cspan class=\"hljs-string\">'~PREVIEW_TEXT'\u003C\u002Fspan>] ?? \u003Cspan class=\"hljs-string\">''\u003C\u002Fspan>);\n\u003Cspan class=\"hljs-meta\">?&gt;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-meta\">&lt;?php\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (\u003Cspan class=\"hljs-variable\">$announcement\u003C\u002Fspan> !== \u003Cspan class=\"hljs-string\">''\u003C\u002Fspan>): \u003Cspan class=\"hljs-meta\">?&gt;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-meta\">&lt;?php\u003C\u002Fspan> \u003Cspan class=\"hljs-variable\">$this\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">SetViewTarget\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'news_announcement'\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">100\u003C\u002Fspan>); \u003Cspan class=\"hljs-meta\">?&gt;\u003C\u002Fspan>\n    &lt;aside \u003Cspan class=\"hljs-class\">\u003Cspan class=\"hljs-keyword\">class\u003C\u002Fspan>=\"\u003Cspan class=\"hljs-title\">news\u003C\u002Fspan>-\u003Cspan class=\"hljs-title\">announcement\u003C\u002Fspan>\"&gt;\n        &lt;?= \u003Cspan class=\"hljs-title\">htmlspecialchars\u003C\u002Fspan>(\u003Cspan class=\"hljs-title\">strip_tags\u003C\u002Fspan>($\u003Cspan class=\"hljs-title\">announcement\u003C\u002Fspan>), \u003Cspan class=\"hljs-title\">ENT_QUOTES\u003C\u002Fspan> | \u003Cspan class=\"hljs-title\">ENT_SUBSTITUTE\u003C\u002Fspan>, '\u003Cspan class=\"hljs-title\">UTF\u003C\u002Fspan>-8') ?&gt;\n    &lt;\u002F\u003Cspan class=\"hljs-title\">aside\u003C\u002Fspan>&gt;\n    &lt;?\u003Cspan class=\"hljs-title\">php\u003C\u002Fspan> $\u003Cspan class=\"hljs-title\">this\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title\">EndViewTarget\u003C\u002Fspan>(); ?&gt;\n&lt;?\u003Cspan class=\"hljs-title\">php\u003C\u002Fspan> \u003Cspan class=\"hljs-title\">endif\u003C\u002Fspan>; ?&gt;\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>news.detail\u003C\u002Fcode> уже получает анонс элемента. \u003Ccode>~PREVIEW_TEXT\u003C\u002Fcode> содержит исходное значение до HTML-экранирования; пример удаляет разметку и выводит анонс обычным текстом. Если шаблон уже показывает этот анонс рядом с подробным текстом, уберите прежний вывод, чтобы не получить повтор.\u003C\u002Fp>\n\u003Cp>Здесь \u003Ccode>$this\u003C\u002Fcode> — объект шаблона компонента. \u003Ccode>SetViewTarget()\u003C\u002Fcode> начинает захват, а \u003Ccode>EndViewTarget()\u003C\u002Fcode> передаёт HTML в область и регистрирует его у компонента. При попадании в кеш Битрикс восстановит область без повторного выполнения \u003Ccode>template.php\u003C\u002Fcode>. \u003Ccode>SetResultCacheKeys()\u003C\u002Fcode> для анонса не нужен: сохраняется уже сформированный HTML. Если анонс не заполнен, пример не создаёт пустой \u003Ccode>&lt;aside&gt;\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Закрывайте захват явно. Начало другой области завершает предыдущую, поэтому эти вызовы не стоит использовать как вложенные контейнеры. Внутри захвата формируйте обычный HTML, без новых отложенных функций и ручного завершения буферов.\u003C\u002Fp>\n\u003Ch2 id=\"section-6\">Передать данные из шаблона news.detail в component_epilog.php\u003C\u002Fh2>\n\u003Cp>Эпилог нужен для действий, которые должны повторяться и при попадании в кеш компонента. Например, над новостью нужно вывести подпись «Материал: название новости» через отдельное свойство страницы. Подготовим значение в \u003Ccode>result_modifier.php\u003C\u002Fcode> шаблона \u003Ccode>bitrix:news.detail\u003C\u002Fcode>, сохраним его в результате и установим свойство в \u003Ccode>component_epilog.php\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>В \u003Ccode>result_modifier.php\u003C\u002Fcode> рядом с \u003Ccode>template.php\u003C\u002Fcode> добавьте:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-meta\">&lt;?php\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!\u003Cspan class=\"hljs-title function_\">defined\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'B_PROLOG_INCLUDED'\u003C\u002Fspan>) || B_PROLOG_INCLUDED !== \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>) { \u003Cspan class=\"hljs-keyword\">die\u003C\u002Fspan>(); }\n\u003Cspan class=\"hljs-comment\">\u002F** \u003Cspan class=\"hljs-doctag\">@var\u003C\u002Fspan> CBitrixComponentTemplate $this *\u002F\u003C\u002Fspan>\n\n\u003Cspan class=\"hljs-variable\">$name\u003C\u002Fspan> = \u003Cspan class=\"hljs-title function_\">trim\u003C\u002Fspan>((\u003Cspan class=\"hljs-keyword\">string\u003C\u002Fspan>)(\u003Cspan class=\"hljs-variable\">$arResult\u003C\u002Fspan>[\u003Cspan class=\"hljs-string\">'~NAME'\u003C\u002Fspan>] ?? \u003Cspan class=\"hljs-string\">''\u003C\u002Fspan>));\n\u003Cspan class=\"hljs-variable\">$arResult\u003C\u002Fspan>[\u003Cspan class=\"hljs-string\">'ARTICLE_LABEL'\u003C\u002Fspan>] = \u003Cspan class=\"hljs-variable\">$name\u003C\u002Fspan> !== \u003Cspan class=\"hljs-string\">''\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">'Материал: '\u003C\u002Fspan> . \u003Cspan class=\"hljs-variable\">$name\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">''\u003C\u002Fspan>;\n\u003Cspan class=\"hljs-variable\">$this\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">getComponent\u003C\u002Fspan>()-&gt;\u003Cspan class=\"hljs-title function_\">SetResultCacheKeys\u003C\u002Fspan>([\u003Cspan class=\"hljs-string\">'ARTICLE_LABEL'\u003C\u002Fspan>]);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>result_modifier.php\u003C\u002Fcode> получает результат штатного компонента до вывода шаблона. Через \u003Ccode>getComponent()\u003C\u002Fcode> он обращается к компоненту и добавляет \u003Ccode>ARTICLE_LABEL\u003C\u002Fcode> к сохраняемым ключам. Переписывать \u003Ccode>component.php\u003C\u002Fcode> или добавлять свой \u003Ccode>StartResultCache()\u003C\u002Fcode> не нужно.\u003C\u002Fp>\n\u003Cp>В \u003Ccode>component_epilog.php\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-meta\">&lt;?php\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!\u003Cspan class=\"hljs-title function_\">defined\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'B_PROLOG_INCLUDED'\u003C\u002Fspan>) || B_PROLOG_INCLUDED !== \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>) { \u003Cspan class=\"hljs-keyword\">die\u003C\u002Fspan>(); }\n\n\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">SetPageProperty\u003C\u002Fspan>(\n    \u003Cspan class=\"hljs-string\">'article_label'\u003C\u002Fspan>,\n    \u003Cspan class=\"hljs-title function_\">htmlspecialchars\u003C\u002Fspan>((\u003Cspan class=\"hljs-keyword\">string\u003C\u002Fspan>)(\u003Cspan class=\"hljs-variable\">$arResult\u003C\u002Fspan>[\u003Cspan class=\"hljs-string\">'ARTICLE_LABEL'\u003C\u002Fspan>] ?? \u003Cspan class=\"hljs-string\">''\u003C\u002Fspan>), ENT_QUOTES | ENT_SUBSTITUTE, \u003Cspan class=\"hljs-string\">'UTF-8'\u003C\u002Fspan>)\n);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>В \u003Ccode>header.php\u003C\u002Fcode> шаблона сайта, внутри \u003Ccode>&lt;body&gt;\u003C\u002Fcode>, разместите вывод свойства:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">ShowProperty\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'article_label'\u003C\u002Fspan>);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>ShowProperty()\u003C\u002Fcode> прочитает значение при сборке страницы. Он сам не экранирует HTML, поэтому эпилог сохраняет в свойство уже экранированный текст. Например, для новости «Открытие магазина» на месте вызова появится «Материал: Открытие магазина».\u003C\u002Fp>\n\u003Cp>При первом построении кеша выполняется \u003Ccode>result_modifier.php\u003C\u002Fcode>, а \u003Ccode>ARTICLE_LABEL\u003C\u002Fcode> сохраняется в \u003Ccode>$arResult\u003C\u002Fcode>. На повторном запросе Битрикс берёт сохранённое значение и снова вызывает эпилог. После добавления нового ключа очистите кеш компонента: прежняя запись его не содержит.\u003C\u002Fp>\n\u003Cp>Для стандартных H1 и метатегов сначала используйте параметры самого \u003Ccode>news.detail\u003C\u002Fcode>: компонент умеет устанавливать их и после получения результата из кеша. Этот пример использует отдельное свойство \u003Ccode>article_label\u003C\u002Fcode>, чтобы не конкурировать со штатной установкой заголовков.\u003C\u002Fp>\n\u003Cp>\u003Ccode>component_epilog.php\u003C\u002Fcode> — эпилог конкретного шаблона компонента, а не событие \u003Ccode>OnEpilog\u003C\u002Fcode> всей страницы. Здесь доступны \u003Ccode>$arResult\u003C\u002Fcode>, \u003Ccode>$arParams\u003C\u002Fcode> и \u003Ccode>$component\u003C\u002Fcode>, но \u003Ccode>$this\u003C\u002Fcode> уже не объект \u003Ccode>CBitrixComponentTemplate\u003C\u002Fcode>: переносить сюда \u003Ccode>$this-&gt;SetViewTarget()\u003C\u002Fcode> нельзя. Если из эпилога нужен готовый HTML в области, используйте \u003Ccode>$APPLICATION-&gt;AddViewContent()\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"section-7\">Вычислить свой HTML при сборке страницы: AddBufferContent()\u003C\u002Fh2>\n\u003Cp>Именованная область хранит готовые строки. Собственный callback нужен, если значение надо прочитать именно при сборке буфера. Например, шаблон заранее оставляет место для плашки, а текст плашки задаётся позднее через свойство страницы.\u003C\u002Fp>\n\u003Cp>В \u003Ccode>\u002Flocal\u002Fphp_interface\u002Finit.php\u003C\u002Fcode> определите callback:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-meta\">&lt;?php\u003C\u002Fspan>\n\u003Cspan class=\"hljs-function\">\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title\">projectPageBadge\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-keyword\">string\u003C\u002Fspan> \u003Cspan class=\"hljs-variable\">$property\u003C\u002Fspan>\u003C\u002Fspan>): \u003Cspan class=\"hljs-title\">string\u003C\u002Fspan>\n\u003C\u002Fspan>{\n    \u003Cspan class=\"hljs-variable\">$text\u003C\u002Fspan> = (\u003Cspan class=\"hljs-keyword\">string\u003C\u002Fspan>)\u003Cspan class=\"hljs-variable\">$GLOBALS\u003C\u002Fspan>[\u003Cspan class=\"hljs-string\">'APPLICATION'\u003C\u002Fspan>]-&gt;\u003Cspan class=\"hljs-title function_\">GetPageProperty\u003C\u002Fspan>(\u003Cspan class=\"hljs-variable\">$property\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">''\u003C\u002Fspan>);\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (\u003Cspan class=\"hljs-variable\">$text\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">''\u003C\u002Fspan>) { \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">''\u003C\u002Fspan>; }\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">'&lt;span class=\"page-badge\"&gt;'\u003C\u002Fspan>\n        . \u003Cspan class=\"hljs-title function_\">htmlspecialchars\u003C\u002Fspan>(\u003Cspan class=\"hljs-variable\">$text\u003C\u002Fspan>, ENT_QUOTES | ENT_SUBSTITUTE, \u003Cspan class=\"hljs-string\">'UTF-8'\u003C\u002Fspan>)\n        . \u003Cspan class=\"hljs-string\">'&lt;\u002Fspan&gt;'\u003C\u002Fspan>;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>В \u003Ccode>header.php\u003C\u002Fcode> шаблона, внутри \u003Ccode>&lt;body&gt;\u003C\u002Fcode>, зарегистрируйте вывод:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">AddBufferContent\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'projectPageBadge'\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">'page_badge'\u003C\u002Fspan>);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>В коде страницы после подключения шапки задайте значение:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">SetPageProperty\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'page_badge'\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">'Информация для покупателя'\u003C\u002Fspan>);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>На месте регистрации появится \u003Ccode>&lt;span&gt;\u003C\u002Fcode> с заданным текстом. Callback получает имя свойства и читает его значение позднее. Он должен \u003Cstrong>вернуть строку\u003C\u002Fstrong>: \u003Ccode>echo\u003C\u002Fcode> внутри функции не заменяет \u003Ccode>return\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Не передавайте позднее значение уже вычисленным аргументом:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-comment\">\u002F\u002F Этот вызов запомнит текущее значение свойства.\u003C\u002Fspan>\n\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">AddBufferContent\u003C\u002Fspan>(\n    \u003Cspan class=\"hljs-string\">'htmlspecialchars'\u003C\u002Fspan>,\n    (\u003Cspan class=\"hljs-keyword\">string\u003C\u002Fspan>)\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">GetPageProperty\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'page_badge'\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">''\u003C\u002Fspan>),\n    ENT_QUOTES | ENT_SUBSTITUTE,\n    \u003Cspan class=\"hljs-string\">'UTF-8'\u003C\u002Fspan>\n);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>PHP вычисляет аргументы при регистрации. Если свойство ещё пустое, callback получит пустую строку даже после её изменения. Передача ключа \u003Ccode>page_badge\u003C\u002Fcode> позволяет прочитать актуальные данные внутри функции.\u003C\u002Fp>\n\u003Cp>Именованная функция также позволяет избежать документированного ограничения анонимных callbacks при \u003Ccode>AJAX_MODE = Y\u003C\u002Fcode> у компонентов. Сам режим AJAX всё равно требует отдельной проверки. На этапе сборки HTML лучше читать уже подготовленные данные, а не выполнять сетевые запросы или повторные выборки из базы.\u003C\u002Fp>\n\u003Ch2 id=\"section-8\">Выбрать событие по этапу: OnEpilog и завершение буфера\u003C\u002Fh2>\n\u003Cp>События нужны, когда действие относится к завершению страницы целиком, а не к одному шаблону компонента. В обычном завершении публичной страницы \u003Ccode>OnEpilog\u003C\u002Fcode> вызывается до сборки основного буфера: в нём можно установить свойства, которые отложенные функции ещё не прочитали. Готовый HTML это событие не получает.\u003C\u002Fp>\n\u003Cp>Порядок внутри завершения буфера:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Ccode>OnBeforeEndBufferContent\u003C\u002Fcode> — перед вычислением отложенных участков; без HTML-параметра.\u003C\u002Fli>\n\u003Cli>Вызовы зарегистрированных отложенных функций.\u003C\u002Fli>\n\u003Cli>Объединение их результатов с остальными частями страницы.\u003C\u002Fli>\n\u003Cli>\u003Ccode>OnEndBufferContent\u003C\u002Fcode> — обработчики получают собранную строку HTML по ссылке.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>Если задача — задать заголовок, используйте свойства страницы. Если нужно изменить уже собранную разметку, подходит \u003Ccode>OnEndBufferContent\u003C\u002Fcode>. Ядро может продолжить обработку ресурсов и композита после этого события, поэтому оно не означает окончание любой обработки ответа.\u003C\u002Fp>\n\u003Ch2 id=\"section-9\">Заменить фрагмент готового HTML: OnEndBufferContent\u003C\u002Fh2>\n\u003Cp>Обработку буфера используйте, когда нет подходящей точки для изменения исходного вывода. Например, собственный шаблон оставляет маркер, который нужно заменить при сборке страницы. В \u003Ccode>\u002Flocal\u002Fphp_interface\u002Finit.php\u003C\u002Fcode> добавьте обработчик:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-meta\">&lt;?php\u003C\u002Fspan>\n\u003Cspan class=\"hljs-title function_\">AddEventHandler\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'main'\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">'OnEndBufferContent'\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">'projectReplacePageMarker'\u003C\u002Fspan>);\n\u003Cspan class=\"hljs-function\">\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title\">projectReplacePageMarker\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">&amp;\u003Cspan class=\"hljs-variable\">$html\u003C\u002Fspan>\u003C\u002Fspan>): \u003Cspan class=\"hljs-title\">void\u003C\u002Fspan>\n\u003C\u002Fspan>{\n    \u003Cspan class=\"hljs-keyword\">global\u003C\u002Fspan> \u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>;\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (\u003Cspan class=\"hljs-variable\">$APPLICATION\u003C\u002Fspan>-&gt;\u003Cspan class=\"hljs-title function_\">GetCurPage\u003C\u002Fspan>() !== \u003Cspan class=\"hljs-string\">'\u002Fdelivery\u002Findex.php'\u003C\u002Fspan>\n        || (\u003Cspan class=\"hljs-variable\">$_SERVER\u003C\u002Fspan>[\u003Cspan class=\"hljs-string\">'REQUEST_METHOD'\u003C\u002Fspan>] ?? \u003Cspan class=\"hljs-string\">''\u003C\u002Fspan>) !== \u003Cspan class=\"hljs-string\">'GET'\u003C\u002Fspan>\n        || \u003Cspan class=\"hljs-title function_\">stripos\u003C\u002Fspan>(\u003Cspan class=\"hljs-variable\">$html\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">'&lt;\u002Fhtml&gt;'\u003C\u002Fspan>) === \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>) {\n        \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>;\n    }\n    \u003Cspan class=\"hljs-variable\">$html\u003C\u002Fspan> = \u003Cspan class=\"hljs-title function_\">str_replace\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">'&lt;!--PAGE_NOTICE--&gt;'\u003C\u002Fspan>,\n        \u003Cspan class=\"hljs-string\">'&lt;p&gt;Наличие товара уточняется при подтверждении заказа.&lt;\u002Fp&gt;'\u003C\u002Fspan>, \u003Cspan class=\"hljs-variable\">$html\u003C\u002Fspan>);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>В \u003Ccode>\u002Fdelivery\u002Findex.php\u003C\u002Fcode>, между подключениями \u003Ccode>\u002Fbitrix\u002Fheader.php\u003C\u002Fcode> и \u003Ccode>\u002Fbitrix\u002Ffooter.php\u003C\u002Fcode>, выведите маркер:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: php\">\u003Ccode class=\"hljs language-php\">\u003Cspan class=\"hljs-keyword\">echo\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">'&lt;!--PAGE_NOTICE--&gt;'\u003C\u002Fspan>;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>На его месте появится абзац. Условие ограничивает обработчик выбранной страницей и полным HTML-ответом на GET-запрос. Если путь другой, замените его в проверке. При отсутствии маркера строка не изменится.\u003C\u002Fp>\n\u003Cp>Композитная обработка может вызвать \u003Ccode>OnEndBufferContent\u003C\u002Fcode> повторно для другой версии буфера. Замена маркера переносит повторный вызов безопасно: она не дописывает второй абзац к уже обработанной строке. Не используйте такое событие для отправки уведомлений или увеличения счётчиков, которые должны срабатывать ровно один раз.\u003C\u002Fp>\n\u003Ch2 id=\"section-10\">Найти причину ошибки: позднее значение, кеш или сброшенный буфер\u003C\u002Fh2>\n\u003Cp>Если заголовок остаётся старым, проверьте ранний \u003Ccode>GetTitle()\u003C\u002Fcode> и последующие вызовы \u003Ccode>SetTitle()\u003C\u002Fcode>. Для различающихся H1 и \u003Ccode>&lt;title&gt;\u003C\u002Fcode> проверьте параметр \u003Ccode>ShowTitle()\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Если область появляется только после очистки кеша, найдите \u003Ccode>AddViewContent()\u003C\u002Fcode> в кешируемом шаблоне. Для захвата HTML используйте \u003Ccode>SetViewTarget()\u003C\u002Fcode>, а установку свойств страницы перенесите в \u003Ccode>component_epilog.php\u003C\u002Fcode>. Когда в эпилоге отсутствует поле, проверьте \u003Ccode>SetResultCacheKeys()\u003C\u002Fcode> и очистите старую запись кеша.\u003C\u002Fp>\n\u003Cp>Если блок повторяется, проверьте количество вызовов \u003Ccode>ShowViewContent()\u003C\u002Fcode> и добавлений в область. \u003Ccode>AddViewContent()\u003C\u002Fcode> дополняет содержимое, а не заменяет предыдущую строку.\u003C\u002Fp>\n\u003Cp>Если callback выполняется сразу, проверьте жизненный цикл страницы. Без \u003Ccode>BX_BUFFER_USED === true\u003C\u002Fcode> \u003Ccode>AddBufferContent()\u003C\u002Fcode> немедленно вызывает функцию и выводит результат. Не определяйте эту константу вручную: нужны штатные пролог, эпилог и управление буфером.\u003C\u002Fp>\n\u003Cp>Если обычная страница работает, а AJAX-ответ — нет, проверьте наличие полного цикла страницы и вызовы \u003Ccode>RestartBuffer()\u003C\u002Fcode>. Этот метод сбрасывает накопленные части буфера и регистрации отложенного вывода; он не запускает их повторно. Лишние \u003Ccode>ob_end_clean()\u003C\u002Fcode>, \u003Ccode>ob_end_flush()\u003C\u002Fcode> и незакрытый \u003Ccode>SetViewTarget()\u003C\u002Fcode> также нарушают ожидаемую последовательность.\u003C\u002Fp>\n\u003Cp>Кеш компонента и композит — разные уровни. \u003Ccode>SetViewTarget()\u003C\u002Fcode> сохраняет HTML области вместе с компонентом, но не делает её персональной. Имя пользователя, корзина и персональная цена требуют соответствующего разделения кеша, а при композите — динамических областей. Сам \u003Ccode>AddBufferContent()\u003C\u002Fcode> не гарантирует выполнение PHP при выдаче сохранённой композитной страницы.\u003C\u002Fp>\n\u003Cp>После подключения выбранного приёма сравните исходный HTML первого ответа после очистки кеша и повторного ответа без очистки. Нужный заголовок или блок должен присутствовать в обоих. Для своего HTML проверьте текст с кавычками, \u003Ccode>&lt;\u003C\u002Fcode>, \u003Ccode>&gt;\u003C\u002Fcode> и \u003Ccode>&amp;\u003C\u002Fcode>: символы должны оставаться текстом. AJAX и композит проверяйте отдельно, если проект их использует.\u003C\u002Fp>\n",[6,9,12,15,18,21,24,27,30,33],{"id":7,"title":8},"section-1","Вывести поздний заголовок: ShowTitle() вместо GetTitle()",{"id":10,"title":11},"section-2","Задать разные H1 и title, вывести description",{"id":13,"title":14},"section-3","Добавить пункт хлебных крошек ниже места их вывода",{"id":16,"title":17},"section-4","Вывести готовый HTML выше по странице: ShowViewContent() и AddViewContent()",{"id":19,"title":20},"section-5","Вывести анонс news.detail над компонентом и сохранить его в кеше",{"id":22,"title":23},"section-6","Передать данные из шаблона news.detail в component_epilog.php",{"id":25,"title":26},"section-7","Вычислить свой HTML при сборке страницы: AddBufferContent()",{"id":28,"title":29},"section-8","Выбрать событие по этапу: OnEpilog и завершение буфера",{"id":31,"title":32},"section-9","Заменить фрагмент готового HTML: OnEndBufferContent",{"id":34,"title":35},"section-10","Найти причину ошибки: позднее значение, кеш или сброшенный буфер",1790082845805]