Разработка системы управления SEO-данными (meta, OG) сайта
Система управления SEO-данными позволяет редакторам задавать мета-теги для каждой страницы сайта — title, description, Open Graph, Twitter Card — без правок в коде. Критична для новостных сайтов, интернет-магазинов и корпоративных порталов.
Модель данных
seo_metas (
id, seo_type, seo_id, -- полиморфная связь: Article, Product, Category, Page
title, description, keywords,
og_title, og_description, og_image_url,
twitter_title, twitter_description, twitter_image_url, twitter_card,
robots, -- 'index,follow' | 'noindex,nofollow' | custom
canonical_url, -- override автоматического canonical
schema_type, -- тип для JSON-LD
schema_data (jsonb),
created_at, updated_at
)
Трейт для моделей
trait HasSeoMeta
{
public function seoMeta(): MorphOne
{
return $this->morphOne(SeoMeta::class, 'seo');
}
public function getEffectiveSeoTitle(): string
{
return $this->seoMeta?->title
?? $this->getDefaultSeoTitle()
?? config('seo.site_name');
}
public function getEffectiveSeoDescription(): string
{
return $this->seoMeta?->description
?? $this->getDefaultSeoDescription()
?? '';
}
}
Компонент мета-тегов (Blade/React)
// Blade: layout.blade.php
<title>{{ $seo->title ?? config('seo.default_title') }}</title>
<meta name="description" content="{{ $seo->description ?? '' }}">
<meta name="robots" content="{{ $seo->robots ?? 'index,follow' }}">
@if($seo->canonical_url)
<link rel="canonical" href="{{ $seo->canonical_url }}">
@endif
<meta property="og:title" content="{{ $seo->og_title ?? $seo->title }}">
<meta property="og:description" content="{{ $seo->og_description ?? $seo->description }}">
<meta property="og:image" content="{{ $seo->og_image_url ?? config('seo.default_og_image') }}">
<meta property="og:type" content="website">
<meta property="og:url" content="{{ request()->url() }}">
<meta name="twitter:card" content="{{ $seo->twitter_card ?? 'summary_large_image' }}">
<meta name="twitter:title" content="{{ $seo->twitter_title ?? $seo->og_title ?? $seo->title }}">
<meta name="twitter:description" content="{{ $seo->twitter_description ?? $seo->og_description }}">
<meta name="twitter:image" content="{{ $seo->twitter_image_url ?? $seo->og_image_url }}">
Шаблоны мета-тегов
Для страниц без ручных настроек — автоматическая генерация из шаблона:
// Для товаров
'{name} — купить за {price} ₽ | {site_name}'
'{description} Доставка по всей России.'
// Подстановка
$title = Str::of(config('seo.product_title_template'))
->replace('{name}', $product->name)
->replace('{price}', number_format($product->price / 100, 0, '.', ' '))
->replace('{site_name}', config('seo.site_name'))
->limit(60);
Форма редактирования в CMS
SEO-раздел в форме редактирования любой сущности — вкладка или accordion:
function SeoMetaForm({ data, onChange }) {
return (
<Accordion type="single" collapsible>
<AccordionItem value="seo">
<AccordionTrigger>SEO-настройки</AccordionTrigger>
<AccordionContent>
<div className="space-y-4">
<div>
<Label>Title (рекомендуется 50-60 символов)</Label>
<Input value={data.title} onChange={e => onChange({ title: e.target.value })} />
<CharCounter current={data.title?.length} max={60} />
</div>
<div>
<Label>Description (рекомендуется 150-160 символов)</Label>
<Textarea value={data.description} onChange={e => onChange({ description: e.target.value })} />
<CharCounter current={data.description?.length} max={160} />
</div>
<SeoPreview title={data.title} description={data.description} />
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
);
}
Компонент SeoPreview показывает, как страница будет выглядеть в результатах поиска Google.
Срок разработки: 2–3 дня для полной системы с полиморфными связями, шаблонами и формой редактирования.







