Архитектура наследуемых свойств
Система наследования 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);
}
Обработка ошибок
Сценарии:
-
Элемент/раздел не найден
try { $elementSEO = new ElementValues($iblockId, $elementId); } catch (Bitrix\Main\ArgumentException $e) { // Логирование ошибки AddMessage2Log($e->getMessage(), 'iblock'); } -
Пустые метатеги
$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']
);