Перейти к содержимому

Граф schema.org (JSON-LD)

Поисковым системам проще читать JSON-LD, когда узлы ссылаются друг на друга: Organization публикует WebSite, WebSite содержит WebPage, а WebPage посвящена Article. Именно такой результат создаёт SchemaGraph: набор узлов, связанных стабильными значениями @id, чтобы каждая страница выводила согласованный граф.

Граф страницы

php
use Rankbeam\Seo\Facades\SEO;
use Rankbeam\Seo\Services\Schema\SchemaCollection;
use Rankbeam\Seo\Services\Schema\SchemaGraph;

$seo = SEO::resolve($post);

$graph = new SchemaGraph();

$schemas = SchemaCollection::make()
    ->add($graph->organization())   // @id: {app_url}#organization
    ->add($graph->webSite())        // @id: {app_url}#website, publisher → #organization
    ->add($graph->webPage($seo));   // @id: {page_url}#webpage, isPartOf → #website

Выведите его в Blade (в head или body):

blade
{!! $schemas->toScript() !!}

Данные Organization и WebSite берутся из config/seo.php (schema.organization, schema.website); узел WebPage заполняется из полученного SEOData.

Узел WebPage получает inLanguage из итоговой локали страницы в форме BCP 47 (it_ITit-IT), ArticleSchema::fromModel() берёт его из сохранённой локали seo_meta, а узел WebSite перечисляет языки сайта из schema.website.inLanguage (один код или список). Задайте schema.in_language равным false, чтобы вообще не выводить inLanguage. См. многоязычный контент.

Типизированные построители

Для распространённых типов расширенных результатов есть готовые построители:

ПостроительПримечания
ArticleSchema::fromModel($post)Даты, автор и издатель из модели и конфигурации
ProductSchemaПредложения, цена, наличие
BreadcrumbSchema::fromArray([...])Упорядоченные пары имя/URL
BreadcrumbSchema::fromModelAncestors($page)Проходит цепочку parent (с защитой от зацикливания)
FAQSchemaПары вопрос/ответ
LocalBusinessSchemaАдрес, географические координаты, часы работы
OrganizationSchemaОтдельный узел организации

Полная страница статьи:

php
$article = ArticleSchema::fromModel($post)
    ->setPublisherOrganization(config('seo.schema.publisher.name'));

$schemas = SchemaCollection::make()
    ->add($graph->organization())
    ->add($graph->webSite())
    ->add($graph->webPage($seo))
    ->add($article->toArray())
    ->add(BreadcrumbSchema::fromArray([
        ['name' => 'Home', 'url' => '/'],
        ['name' => 'Blog', 'url' => '/blog'],
        ['name' => $post->title, 'url' => "/blog/{$post->slug}"],
    ])->toArray());

Прикреплённая разметка и @seoSchema

Разметка schema.org, сохранённая в итоговом SEOData (например, вместе с явными метаданными), выводится директивой @seoSchema или через раздел script в SEO::toArray():

blade
@seoSchema($post)

Редакторы могут заполнять seo_meta.schema_jsonld без кода через необязательный раздел Структурированные данные в пакете полей Filament: переключатель автоматических хлебных крошек и блоки FAQ / Товар, которые проверяются через SchemaValidator перед сохранением.

Экранирование

Весь вывод JSON-LD — SchemaCollection::toScript(), toJson() и остальные пути рендеринга — кодируется с JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP. Последовательность </script> в заголовках или контенте не может закрыть элемент script. Не обходите эту защиту, самостоятельно применяя json_encode к массивам schema.org.

rankbeam/laravel-seo распространяется под лицензией MIT.