JSON-LD-инъекция витрины InSales (InSales Storefront JSON-LD Injection)
1. Архитектура и принцип работы
В InSales шаблон витрины рендерится движком Liquid: товар доступен как объект product с полями price, old_price, variants, availability, images. Инъекция строится так: в layout или сниппет product.liquid добавляется блок script type=application/ld+json, внутри которого через Liquid-теги подставляются значения. Динамические поля (цена, наличие, рейтинг) оборачиваются в условия: если variants.size > 1 — выводится Product с offers-массивом AggregateOffer или ItemList, иначе — единичный Offer. Хлебные крошки и Organization выводятся в общем layout один раз, чтобы не дублировать граф. Критично экранировать кавычки и апострофы в названиях через escape, иначе JSON ломается. Валидация — через Rich Results Test и проверку в Яндекс.Вебмастере. Для категорий используется CollectionPage с ItemList, для статей — Article. Инъекция в шаблон, а не через JS-вставку, гарантирует, что разметка присутствует в исходном HTML и видна краулерам без выполнения скриптов.
2. Математическая механика и триггеры ранжирования
Ключевая сложность — согласование жизненного цикла данных. InSales кэширует витрину, поэтому при массовом обновлении цен через API разметка может отставать от факта: нужно либо сбрасывать кэш товара при изменении цены, либо использовать webhook на событие product update для триггера purge. Второй слой — варианты: если товар имеет размеры/цвета, корректный граф требует Product с offers как массив Offer, каждый со своим sku, price, availability и url с параметром варианта. Ошибка — схлопывать всё в один Offer, из-за чего Google теряет варианты в Merchant и товарных сниппетах. Третий слой — согласованность с YML-фидом: цены и availability в JSON-LD и в фиде для Яндекса должны совпадать, иначе Яндекс.Маркет и поиск по товарам получают противоречивые сигналы. Четвёртый — Organization и WebSite с potentialAction SearchAction выводятся один раз в layout, а не в каждой карточке, чтобы не плодить дубли сущностей. Пятый — пагинация категорий: ItemList должен содержать позиции текущей страницы, а сама CollectionPage — ссылки rel next/prev в HTML. Шестой — кодировка: Liquid может возвращать HTML-сущности в названиях, их нужно декодировать до подстановки в JSON.
3. Специфика в Яндекс (YATI) vs Google
Google опирается на JSON-LD как приоритетный формат и строит из него граф сущностей для расширенных сниппетов, Merchant Center и AI Overviews. Требует строгого соответствия обязательным полям Product (name, image, offers.price, priceCurrency, availability) и наказывает за несоответствие видимому контенту. Яндекс поддерживает Schema.org частично: товарные сниппеты формируются в основном из YML-фида и страницы, а JSON-LD учитывается как дополнительный сигнал, особенно для Organization, BreadcrumbList и Article. Яндекс.Вебмастер валидирует разметку отдельно и показывает ошибки в разделе структурированных данных, но вес JSON-LD в ранжировании ниже, чем у Google. Для InSales-магазинов практический вывод: один и тот же JSON-LD-блок должен одновременно удовлетворять Google Rich Results Test и не противоречить YML-фиду Яндекса — расхождение цен между ними даёт худший эффект, чем отсутствие разметки.
4. Нормативы SLA и диагностическая матрица
| Параметр / Метрика | Эталон по SLA | Критическая ошибка |
|---|---|---|
| Доля карточек с валидным Product JSON-LD | > 95% | < 80% |
| Расхождение цены JSON-LD vs YML-фид | 0% | > 2% SKU |
| Ошибки в Rich Results Test на шаблон | 0 | > 5 типов ошибок |
5. Пошаговый инженерный протокол внедрения
- Выносить Organization, WebSite и BreadcrumbList в общий layout один раз, а Product/Offer — в шаблон карточки товара, чтобы не дублировать сущности на каждой странице.
- Для товаров с вариантами генерировать массив offers с отдельными sku, url и availability, а не один агрегированный Offer — это сохраняет варианты в товарных сниппетах.
- Синхронизировать price и availability в JSON-LD с YML-фидом через webhook на изменение товара и сброс кэша витрины, чтобы сигналы Google и Яндекса не расходились.
- Валидировать вывод через Rich Results Test и Яндекс.Вебмастер после каждого изменения шаблона, отдельно проверяя экранирование кавычек в названиях товаров.
{%- assign p = product -%}
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"Product",
"name":{{ p.title | json }},
"image":[{% for i in p.images %}{{ i.url | json }}{% unless forloop.last %},{% endunless %}{% endfor %}],
"sku":{{ p.id | json }},
"offers":{"@type":"Offer","price":{{ p.price | divided_by: 100.0 | json }},
"priceCurrency":"RUB","availability":"https://schema.org/{% if p.available %}InStock{% else %}OutOfStock{% endif %}",
"url":{{ p.url | absolute_url | json }}}}
</script>
6. Типичные ошибки при оптимизации
- Вставка JSON-LD через JavaScript после загрузки страницы — краулеры без рендеринга и Яндекс могут не увидеть разметку, а кэш витрины отдаёт HTML без неё.
- Дублирование Organization и WebSite в каждой карточке товара — граф сущностей раздувается, появляются конфликтующие узлы и предупреждения валидаторов.
- Расхождение цены и наличия между JSON-LD, видимым контентом и YML-фидом — Google и Яндекс получают противоречивые сигналы, товар теряет сниппет и позиции в поиске по товарам.
