SEO-шаблоны: как это устроено внутри

Почему понадобилось отдельное хранилище

Ядро хранит шаблоны SEO и кеш вычисленных значений без измерения языка. Колонки под язык там нет, и добавить её — значит расходиться с платформой навсегда.

Поэтому базовый шаблон остаётся в ядре, а переводы живут в своём highload-блоке. Ядро продолжает работать так, как работало, и ничего не знает о переводах.

Хранилище

Highload-блок MrlexndrTranslateSeo. Одна строка — один шаблон одной сущности:

Поле Что в нём
UF_CODE уникальный ключ вида E.<id>.<КОД>, S.<id>.<КОД>, B.<инфоблок>.<КОД>
UF_ENTITY, UF_ENTITY_ID уровень и идентификатор, для фильтра
UF_IBLOCK_ID инфоблок сущности
UF_LANG_<XX> перевод на целевой язык

Коды — те же, что в ядре: ELEMENT_META_TITLE, SECTION_PAGE_TITLE, ELEMENT_PREVIEW_PICTURE_FILE_ALT и остальные.

Колонки базового языка нет намеренно: базовый шаблон живёт в ядре, и вторая его копия немедленно начала бы расходиться с первой.

Индексы — уникальный по ключу и обычные по сущности и по инфоблоку. Без них каждое удаление элемента при обмене с 1С сканировало бы таблицу целиком.

Блок переживает удаление модуля: переводы — это контент.

Чтение

Правило одно: уровень с собственным базовым шаблоном побеждает.

По каждому коду уровень-источник определяется средствами ядра. Перевод берётся только у этого уровня. Нет перевода — берётся его базовый шаблон, а не перевод родителя.

Кеш и его сброс

Кешируются собственные переводы сущности — все языки одной строкой.

Каждая запись сбрасывает три вещи: кеш сущности, рантайм-кеш репозитория и тег кеша инфоблока. Без последнего закешированные детальные страницы показывали бы старые мета-теги. В порции перевода тег сбрасывается один раз в конце, а не на каждой записи.

Сбой чтения не кешируется и пишется в журнал. Иначе одна неудачная попытка означала бы, что переводы пропали с сайта до истечения кеша — то есть на сутки.

Чистка

При удалении элемента, раздела или инфоблока соответствующие переводы удаляются по событию.

Если событие не сработало — например, элемент удалили в обход ядра, — остаются строки, чьей сущности больше нет. Они видны отдельным блоком на вкладке «Мусорщик» экрана Обслуживание и удаляются вручную, с повторной проверкой, что сущность действительно исчезла.

Проверка идёт выборками D7: у старого API есть неявные условия, из-за которых живой перевод мог бы попасть в удаление.

Почему нет обработчика эпилога

Соблазнительно было бы подменять мета-теги в самом конце сборки страницы, одним местом на всё. Но в эпилоге нечем узнать, какая сущность на странице: компонент уже отработал и данных о себе не оставил.

Поэтому подстановка делается вызовом хелпера в шаблоне компонента — там сущность известна.

Цена на промахе кеша

Несколько запросов на сущность: цепочка шаблонов, переводы, поля для макросов.

Для детальной страницы это ничто. В списках — звать только внутри кешируемого компонента, иначе цена умножается на число элементов.