Добавлена микроразметка для улучшения SEO на страницах каталога, карточки товара, о компании и контактов. Внедрены схемы Organization, Product, BreadcrumbList и LocalBusiness для соответствующих страниц. Обновлены компоненты для поддержки новых атрибутов микроразметки.

This commit is contained in:
Bivekich
2025-07-06 18:46:00 +03:00
parent 2b5f787fbe
commit 8284385e3c
9 changed files with 399 additions and 10 deletions

257
src/lib/schema.ts Normal file
View File

@ -0,0 +1,257 @@
// Утилиты для генерации микроразметки schema.org
export interface SchemaOrgProduct {
name: string;
description?: string;
brand: string;
sku: string;
image?: string;
category?: string;
offers: SchemaOrgOffer[];
}
export interface SchemaOrgOffer {
price: number;
currency: string;
availability: string;
seller: string;
deliveryTime?: string;
warehouse?: string;
}
export interface SchemaOrgBreadcrumb {
name: string;
url: string;
}
export interface SchemaOrgOrganization {
name: string;
description?: string;
url: string;
logo?: string;
contactPoint?: {
telephone: string;
email?: string;
contactType: string;
};
address?: {
streetAddress: string;
addressLocality: string;
addressRegion: string;
postalCode: string;
addressCountry: string;
};
}
export interface SchemaOrgLocalBusiness extends SchemaOrgOrganization {
openingHours?: string[];
geo?: {
latitude: number;
longitude: number;
};
}
// Генератор микроразметки для товара
export const generateProductSchema = (product: SchemaOrgProduct): object => {
return {
"@context": "https://schema.org",
"@type": "Product",
name: product.name,
description: product.description || `${product.brand} ${product.sku} - ${product.name}`,
brand: {
"@type": "Brand",
name: product.brand
},
sku: product.sku,
mpn: product.sku,
image: product.image,
category: product.category || "Автозапчасти",
offers: product.offers.map(offer => ({
"@type": "Offer",
price: offer.price,
priceCurrency: offer.currency,
availability: offer.availability,
seller: {
"@type": "Organization",
name: offer.seller
},
deliveryLeadTime: offer.deliveryTime,
availableAtOrFrom: {
"@type": "Place",
name: offer.warehouse || "Склад"
}
}))
};
};
// Генератор микроразметки для организации
export const generateOrganizationSchema = (org: SchemaOrgOrganization): object => {
const schema: any = {
"@context": "https://schema.org",
"@type": "Organization",
name: org.name,
url: org.url,
description: org.description
};
if (org.logo) {
schema.logo = org.logo;
}
if (org.contactPoint) {
schema.contactPoint = {
"@type": "ContactPoint",
telephone: org.contactPoint.telephone,
email: org.contactPoint.email,
contactType: org.contactPoint.contactType
};
}
if (org.address) {
schema.address = {
"@type": "PostalAddress",
streetAddress: org.address.streetAddress,
addressLocality: org.address.addressLocality,
addressRegion: org.address.addressRegion,
postalCode: org.address.postalCode,
addressCountry: org.address.addressCountry
};
}
return schema;
};
// Генератор микроразметки для местного бизнеса
export const generateLocalBusinessSchema = (business: SchemaOrgLocalBusiness): object => {
const schema: any = {
"@context": "https://schema.org",
"@type": "LocalBusiness",
name: business.name,
url: business.url,
description: business.description
};
if (business.contactPoint) {
schema.contactPoint = {
"@type": "ContactPoint",
telephone: business.contactPoint.telephone,
email: business.contactPoint.email,
contactType: business.contactPoint.contactType
};
}
if (business.address) {
schema.address = {
"@type": "PostalAddress",
streetAddress: business.address.streetAddress,
addressLocality: business.address.addressLocality,
addressRegion: business.address.addressRegion,
postalCode: business.address.postalCode,
addressCountry: business.address.addressCountry
};
}
if (business.openingHours) {
schema.openingHours = business.openingHours;
}
if (business.geo) {
schema.geo = {
"@type": "GeoCoordinates",
latitude: business.geo.latitude,
longitude: business.geo.longitude
};
}
return schema;
};
// Генератор микроразметки для хлебных крошек
export const generateBreadcrumbSchema = (breadcrumbs: SchemaOrgBreadcrumb[]): object => {
return {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: breadcrumbs.map((breadcrumb, index) => ({
"@type": "ListItem",
position: index + 1,
name: breadcrumb.name,
item: breadcrumb.url
}))
};
};
// Генератор микроразметки для сайта с поиском
export const generateWebSiteSchema = (name: string, url: string, searchUrl?: string): object => {
const schema: any = {
"@context": "https://schema.org",
"@type": "WebSite",
name: name,
url: url
};
if (searchUrl) {
schema.potentialAction = {
"@type": "SearchAction",
target: {
"@type": "EntryPoint",
urlTemplate: `${searchUrl}?q={search_term_string}`
},
"query-input": "required name=search_term_string"
};
}
return schema;
};
// Утилита для конвертации доступности товара в schema.org формат
export const convertAvailability = (stock: string | number): string => {
const stockNum = typeof stock === 'string' ? parseInt(stock) || 0 : stock;
if (stockNum > 0) {
return "https://schema.org/InStock";
} else {
return "https://schema.org/OutOfStock";
}
};
// Утилита для генерации JSON-LD скрипта
export const generateJsonLdScript = (schema: object): string => {
return JSON.stringify(schema, null, 2);
};
// Интерфейс для компонента JSON-LD (компонент будет в отдельном файле)
export interface JsonLdScriptProps {
schema: object;
}
// Данные организации Protek
export const PROTEK_ORGANIZATION: SchemaOrgOrganization = {
name: "Protek",
description: "Protek - широкий ассортимент автозапчастей и аксессуаров для всех марок автомобилей. Быстрая доставка по России, гарантия качества, низкие цены.",
url: "https://protek.ru",
logo: "https://protek.ru/images/logo.svg",
contactPoint: {
telephone: "+7-800-555-0123",
email: "info@protek.ru",
contactType: "customer service"
},
address: {
streetAddress: "ул. Примерная, 123",
addressLocality: "Москва",
addressRegion: "Москва",
postalCode: "123456",
addressCountry: "RU"
}
};
// Данные для LocalBusiness
export const PROTEK_LOCAL_BUSINESS: SchemaOrgLocalBusiness = {
...PROTEK_ORGANIZATION,
openingHours: [
"Mo-Fr 09:00-18:00",
"Sa 10:00-16:00"
],
geo: {
latitude: 55.7558,
longitude: 37.6176
}
};