Работа с наследуемыми SEO свойствами инфоблоков в Bitrix. Получить SEO элементов и разделов Битрикс API

Архитектура наследуемых свойств

Система наследования SEO-данных в Bitrix реализует иерархический приоритет:

Элемент → Раздел → Инфоблок → Настройки сайта

Классы InheritedProperty\ElementValues и InheritedProperty\SectionValues предоставляют программный интерфейс для доступа к вычисленным значениям метаданных с учетом этой иерархии.


API для элементов инфоблока

1. Инициализация объекта

use Bitrix\Iblock\InheritedProperty\ElementValues;

$elementSEO = new ElementValues(
    int $iblockId,     // ID инфоблока
    int $elementId     // ID элемента
);

2. Получение данных

Метод getValues() возвращает ассоциативный массив:

[
    'ELEMENT_PAGE_TITLE' => string,     // Заголовок страницы (тег <h1>)
    'ELEMENT_META_TITLE' => string,     // Метатег title
    'ELEMENT_META_DESCRIPTION' => string, // Метатег description
    'ELEMENT_META_KEYWORDS' => string   // Метатег keywords
]

3. Интеграция в шаблон

global $APPLICATION;

$values = $elementSEO->getValues();

// Установка метатегов через API CMain
$APPLICATION->SetTitle($values['ELEMENT_PAGE_TITLE']);
$APPLICATION->SetPageProperty('title', $values['ELEMENT_META_TITLE']);
$APPLICATION->SetPageProperty('description', $values['ELEMENT_META_DESCRIPTION']);

API для разделов инфоблока

1. Инициализация объекта

use Bitrix\Iblock\InheritedProperty\SectionValues;

$sectionSEO = new SectionValues(
    int $iblockId,     // ID инфоблока
    int $sectionId     // ID раздела
);

2. Особенности работы

  • Значения разделов наследуют данные инфоблока, но не влияют на элементы.
  • Поддерживаются динамические шаблоны с макросами (например, #SECTION_NAME#).

Паттерн «Резервное значение»

Пример использования SEO-описания раздела как fallback для контента:

// В компоненте bitrix:catalog.section
$sectionId = CIBlockFindTools::GetSectionID(
    $arResult['VARIABLES']['SECTION_ID'],
    $arResult['VARIABLES']['SECTION_CODE'],
    ['IBLOCK_ID' => $arParams['IBLOCK_ID']]
);

$sectionSEO = new SectionValues(
    $arParams['IBLOCK_ID'], 
    $sectionId
);
$seoData = $sectionSEO->getValues();

// Получение описания через CIBlockSection
$dbSection = CIBlockSection::GetList(
    [],
    [
        'IBLOCK_ID' => $arParams['IBLOCK_ID'],
        'ID' => $sectionId
    ],
    false,
    ['DESCRIPTION']
);

if ($section = $dbSection->Fetch()) {
    $description = $section['DESCRIPTION'] 
        ?: $seoData['SECTION_META_DESCRIPTION'];
}

echo htmlspecialchars_decode($description);

Оптимизация запросов

Проблема:

Прямое использование getValues() в шаблоне вызывает множественные SQL-запросы при каждом рендеринге.

Решение:

Кеширование через тег CIBlock::GetAdminSectionIDList():

// Получение ID разделов, влияющих на SEO
$adminSections = CIBlock::GetAdminSectionIDList($iblockId);

// Генерация уникального тега кеша
$cacheId = 'seo_section_' . $sectionId . '_' . md5(implode(',', $adminSections));
$cache = Bitrix\Main\Data\Cache::createInstance();

if ($cache->initCache(3600, $cacheId)) {
    $seoData = $cache->getVars();
} elseif ($cache->startDataCache()) {
    $seoData = $sectionSEO->getValues();
    $cache->endDataCache($seoData);
}

Обработка ошибок

Сценарии:

  1. Элемент/раздел не найден

    try {
       $elementSEO = new ElementValues($iblockId, $elementId);
    } catch (Bitrix\Main\ArgumentException $e) {
       // Логирование ошибки
       AddMessage2Log($e->getMessage(), 'iblock');
    }
  2. Пустые метатеги

    $title = !empty($values['ELEMENT_META_TITLE']) 
       ? $values['ELEMENT_META_TITLE']
       : $defaultTitle;

Производительность

Метрика для анализа (через `Bitrix\Main\Diag\Debug):

Bitrix\Main\Diag\Debug::startTimeLabel('seo_data_fetch');
$values = $elementSEO->getValues();
Bitrix\Main\Diag\Debug::endTimeLabel('seo_data_fetch');

// Результат в debug.log:
// seo_data_fetch: 0.0123 sec

Интеграция с ЧПУ

Для генерации SEO-полей с учетом URL:

$element = CIBlockElement::GetList(
    [],
    ['ID' => $elementId],
    false,
    false,
    ['DETAIL_PAGE_URL']
)->Fetch();

$seoData['ELEMENT_META_TITLE'] = str_replace(
    '#SECTION_URL#', 
    $element['DETAIL_PAGE_URL'], 
    $seoData['ELEMENT_META_TITLE']
);