Framer рендерит быстрые и красивые сайты, но structured data для поисковиков не отдаёт: ни Product, ни FAQPage, ни LocalBusiness. Для магазина или сервиса это потерянные rich-сниппеты в выдаче. Ниже code component, который закрывает дыру, и живая проверка прямо на этой странице.
Боль
Живой артефакт
Инжектор, идентичный по логике code component ниже, при загрузке добавил в документ два блока JSON-LD: Product и FAQPage. Кнопка запускает встроенный чекер: он читает документ и проверяет обязательные поля так же, как это делает валидатор Google.
Решение
Компонент кладётся на канвас, все поля редактируются в правой панели через addPropertyControls: маркетолог меняет цену и валюту без разработчика. На опубликованном сайте компонент невидим, в документ попадает только script с разметкой.
import { addPropertyControls, ControlType } from "framer"
import { useEffect } from "react"
export default function SchemaProduct(props) {
useEffect(() => {
const data = {
"@context": "https://schema.org",
"@type": "Product",
name: props.name,
description: props.description,
offers: {
"@type": "Offer",
price: String(props.price),
priceCurrency: props.currency,
availability: props.inStock
? "https://schema.org/InStock"
: "https://schema.org/OutOfStock",
},
}
const tag = document.createElement("script")
tag.type = "application/ld+json"
tag.textContent = JSON.stringify(data)
document.head.appendChild(tag)
return () => tag.remove()
}, [props])
return null
}
addPropertyControls(SchemaProduct, {
name: { type: ControlType.String, title: "Товар" },
description: { type: ControlType.String, title: "Описание" },
price: { type: ControlType.Number, title: "Цена" },
currency: { type: ControlType.String, title: "Валюта", defaultValue: "UAH" },
inStock: { type: ControlType.Boolean, title: "В наличии", defaultValue: true },
})
Важная деталь: cleanup в useEffect возвращает функцию удаления тега. Частая ошибка в чужих Framer-проектах, когда из useEffect возвращают что-то другое, даёт «We detected a problem in one of your code components». Для FAQPage компонент отличается только сборкой объекта data из списка вопросов.
Как проверить