Микроразметки

Для контактов ( Схема организации)

<div itemscope="" itemtype="http://schema.org/Organization">
 <span itemprop="name">Наименование организации</span>
 Контактная информация:
 
<div itemprop="address" itemscope="" itemtype="http://schema.org/PostalAddress">
 Почтовый адрес:
 <span itemprop="streetAddress">номер дома, улица</span>
 <span itemprop="postalCode">почтовый индекс</span>
 <span itemprop="addressLocality">город, страна</span>
 </div>
 
 Телефон:<span itemprop="telephone">контактный телефон</span>,
 Факс:<span itemprop="faxNumber">факс</span>,
 E-mail: <span itemprop="email">корпоративный e-mail</span>
</div>

 Наименование организации
 Контактная информация:


 Почтовый адрес:
 номер дома, улица
 почтовый индекс
 город, страна
 

 Телефон:контактный телефон,
 Факс:факс,
 E-mail: корпоративный e-mail


Для карточки товара

 
<DIV itemscope ItemType = "https://schema.org/Product">
<META itemprop = "name" content = "HTC Touch HD" />
<Itemproduct reference = "URL" HREF = "https://microdata.pro/demo/index.php?route=product/product&product_id=28" />
<Link itemprop = "image" HREF = "https://microdata.pro/demo/image/catalog/demo/htc_touch_hd_1.jpg" />
<META itemprop = "brand" content = "HTC" />
<META itemprop = "manufacturer" content = "HTC" />
<META itemprop = "model" content = "Product 1" />
<META itemprop = "gtin12" content = "UPC" />
<META itemprop = "gtin8" content = "EAN" />
<META itemprop = "ProductID" content = "ISBN" />
<META itemprop = "category" content = "Phones and PDAs" />
<DIV itemprop = "aggregateRating" itemscope ItemType = "https://schema.org/AggregateRating">
<META itemprop = "ratingValue" content = "4.5">
<META itemprop = "reviewCount" content = "2">
</ DIV>
<DIV itemprop = "offers" itemscope ItemType = "https://schema.org/Offer">
<META itemprop = "priceCurrency" content = "rub" />
<META itemprop = "price" content = "122.00" />
<Link itemprop = "availability" HREF = "https://schema.org/InStock" />
</ DIV>
<META itemprop = "description" content = "Product Description" />
<DIV itemprop = "Overview" itemscope ItemType = "https://schema.org/Review">
<META itemprop = "author" content = "Test 2" />
<META itemprop = "datePublished" content = "2016-06-06" />
<DIV itemprop = "reviewRating" itemscope ItemType = "https://schema.org/Rating">
<META itemprop = "worstRating" content = "1" />
<META itemprop = "ratingValue" Content = "5" />
<META itemprop = "bestRating" content = "5" />
</ DIV>
<META itemprop = "description" content = "feedback text" />
</ DIV>
<DIV itemprop = "Overview" itemscope ItemType = "https://schema.org/Review">
<META itemprop = "author" content = "Name test for recall" />
<META itemprop = "datePublished" content = "2016-06-06" />
<DIV itemprop = "reviewRating" itemscope ItemType = "https://schema.org/Rating">
<META itemprop = "worstRating" content = "1" />
<META itemprop = "ratingValue" content = "4" />
<META itemprop = "bestRating" content = "5" />
</ DIV>
<META itemprop = "description" content = "feedback text" />
</ DIV>
<DIV ID = "Product-related-1" itemprop = "isRelatedTo" itemscope ItemType = "https://schema.org/Product">
<META itemprop = "name" contents = "HTC Touch HD" />
<META itemprop = "description" content = "рус" />
<Itemproduct reference = "URL" HREF = "https://microdata.pro/demo/index.php?route=product/product&product_id=28" />
<Itemproduct reference = "image" HREF = "https://microdata.pro/demo/catalog/demo/htc_touch_hd_1.jpg" />
<DIV itemprop = "offers" itemscope ItemType = "https://schema.org/Offer">
<META itemprop = "priceCurrency" content = "rub" />
<META itemprop = "price" content = "122.00" />
</ DIV>
</ DIV>
</ DIV>

Микроразметка товаров ( https://schema.org/Product )

JSON-LD

JSON-LD – один из методов передачи данных. Работает по тому же принципу, что и вариация schema.org, интегрируемая напрямую в HTML. В освновном полезна для поисковиков, которые видя структуру страницы отображают ее в более читабельном виде. Удобен он тем, что все данные передаются в JSON, что избавляет меня от необходимости изменять шаблон сайта.

Здесь я на собственном примере расскажу о том, как использовать данный вид разметки для простейшего блога. Весь код будет подвязан на использовании в Laravel, а результат работы можно увидеть на этом сайте.

Перед началом создадим класс, методы которого будут возвращать массивы с необходимой разметкой.

<?php

namespace App\Helpers;

class JsonLd
{

}

Person

Данный тип разметки подходит для главной страницы или “Обо мне”.

 {
      "@context": "http://schema.org",
      "@type": "Person",
      "address": {
        "@type": "PostalAddress",
        "addressLocality": "Colorado Springs",
        "addressRegion": "CO",
        "postalCode": "80840",
        "streetAddress": "100 Main Street"
      },
      "colleague": [
        "http://www.example.com/JohnColleague.html",
        "http://www.example.com/JameColleague.html"
      ],
      "email": "mailto:info@example.com",
      "image": "janedoe.jpg",
      "jobTitle": "Research Assistant",
      "name": "Jane Doe",
      "alumniOf": "Dartmouth",
      "birthPlace": "Philadelphia, PA",
      "birthDate": "1979.10.12",
      "height": "72 inches",
      "gender": "female",
      "memberOf": "Republican Party",
      "nationality": "African American",
      "telephone": "(123) 456-6789",
      "url": "http://www.example.com",
      "sameAs" : [
        "https://www.facebook.com/",
        "https://www.linkedin.com/",
        "http://twitter.com/",
        "http://instagram.com/",
        "https://plus.google.com/"
      ]
}

Добавим его в наш класс.

public function about()
{
    return [
        '@context' => 'http://schema.org',
        '@type' => 'Person',
        'name' => config('app.name'),
        'url' => config('app.url'),
        'jobTitle' => 'PHP Developer',
        'gender' => 'male',
        'image' => asset('images/me.jpg'),
        'email' => 'mailto:me@gtxtymt.xyz',
        'birthDate' => '1995-07-12T00:00:00+00:00',
        'sameAs' => array_values(config('gtxtymt.social', []))
    ];
}

Небольшое отступление – Яндекс утверждает, что все даты должны отображаться в ISO 8601. Тем не менее Гугл ничего против коротких YYYY-MM-DD не имеет.

Blog

Данный тип подходит для главной страницы блога. Содержит в себе информацию об организации (см. Organization) и список записей, выводимых на странице.

{
    "@context": "http://schema.org",
    "@type": "Blog",
    "name": "Blog name",
    "url": "https://example.com",
    "description": "Same as meta description",
    "publisher": {
        // Organization
    },
    "sameAs": [
        "https://facebook.com/BlogPage",
        "https://plus.google/BlogPage"
    ],
    "potentialAction": {
        "@type": "SearchAction",
        "target": "https://example.com/search.php?q={search_term}",
        "query-input": "required name=search_term"
    },
    "blogPosts": [
        {
            // BlogPosting
        }
    ]
}
public function blog(array $items)
{
    return [
        '@context' => 'http://schema.org',
        '@type' => 'Blog',
        'publisher' => $this->publisher(),
        'blogPost' =>
            array_map([$this, 'blogPosting'], $items)
    ];
}

Содержит вызов publisher(), указанный ниже. Принимает массив $items содержащий записи модели Post с записями текущей страницы. Проходит по каждому элементу массива и возвращает структурированный список записей методом, объявленным дальше.

BlogPosting

Предназначен для описания записи в блоге. Используется как непосредственно на странице записи, так и в предыдущем методе для вывода списка записей.

{
    "@context": "http://schema.org", 
     "@type": "BlogPosting",
     "headline": "14 Ways Json Can Improve Your SEO",
     "alternativeHeadline": "and the women who love them",
     "image": "http://example.com/image.jpg",
     "award": "Best article ever written",
     "editor": "John Doe", 
     "genre": "search engine optimization", 
     "keywords": "seo sales b2b", 
     "wordcount": "1120",
     "publisher": "Book Publisher Inc",
     "url": "http://www.example.com",
     "datePublished": "2015-09-20",
     "dateCreated": "2015-09-20",
     "dateModified": "2015-09-20",
     "description": "We love to do stuff to help people and stuff",
     "articleBody": "You can paste your entire post in here, and yes it can get really really long.",
     "author": {
        // Person
     }
 }
public function blogPosting(Post $post)
{
    return [
        '@context' => 'https://schema.org',
        '@type' => 'BlogPosting',
        'headline' => $post->name,
        'description' => $post->preview_text,
        'datePublished' => $post->created_at->toIso8601String(),
        'dateModified' => $post->updated_at->toIso8601String(),
        'mainEntityOfPage' => true,
        'url' => $post->link,
        'image' => [
            '@type' => 'ImageObject',
            'url' => url(\Storage::url($post->image)),
            'width' => 1200,
            'height' => 300
        ],
        'author' => $this->about(),
        'publisher' => $this->publisher()
    ];
}

В качестве параметра ожидается модель Post, данные из которой подставляются в поля. Содержит вызовы about() и publisher() (о нем ниже).

Хлебные крошки. Совершенно ничем не отличаются по предназначению и действию от аналогов с HTML-разметкой 🙂 Могут использоваться везде.

{
    "@context": "http://schema.org",
    "@type": "BreadcrumbList",
    "itemListElement": [
        {
            // ListItem
        }
    ]
}
public function breadcrumb(array $items)
    {
        return [
            '@context' => 'http://schema.org',
            '@type' => 'BreadcrumbList',
            'itemListElement' =>
                array_merge(
                    [
                        [
                            '@type' => 'ListItem',
                            'position' => 1,
                            'item' => [
                                '@id' => route('index'),
                                'name' => config('app.name')
                            ]
                        ]
                    ],
                    array_map([$this, 'listItem'], $items)
                )
        ];
    }

Самый “кодообильный” метод. Для удобства я создал класс, с которым работаю как в контроллере, так и в шаблонах.

<?php

namespace App\Helpers;

use Illuminate\Contracts\Support\Arrayable;

class Breadcrumb implements Arrayable
{
    protected $items = [];

    public function add(string $name, string $url, bool $absolute = true)
    {
        $this->items[] = [
            'name' => $name,
            'url' => $absolute ? $url : url($url),
            'position' => count($this->items) + 1
        ];

        return $this;
    }

    public function toArray()
    {
        return (new JsonLd())->breadcrumb($this->items);
    }
}

Для удобного доступа из любого места в AppServiceProvider в методе boot привязал класс к контейнеру, а для удобной работы в контроллерах забиндил вызов класса.

$this->app->singleton('breadcrumb', function() {
    return new Breadcrumb();
});

$this->app->bind(Breadcrumb::class, function($app) {
    return $app['breadcrumb'];
});

Разберу на примере блога.

<?php

namespace App\Http\Controllers;

use App\Helpers\Breadcrumb;
use App\Helpers\JsonLd;
use App\Models\Post;
use App\Models\Tag;
use Illuminate\Http\Request;

class BlogController extends Controller
{
    public function __construct(Breadcrumb $breadcrumb)
    {
        $breadcrumb->add(__('title.blog'), route('blog.index'));
    }

    public function index(Request $request)
    {
        return view('blog.index');
    }

    public function single(Breadcrumb $breadcrumb, string $slug)
    {
        $item = Post::first();
        $breadcrumb->add($item->name, $item->link);

        return view('blog.single', compact('item'));
    }

    public function tag(Request $request, Breadcrumb $breadcrumb, string $slug)
    {
        $item = Tag::first();
        $breadcrumb->add($item->name, $item->link);

        return view('blog.index');
    }
}

Первая крошка добавления в классе JsonLd, название и адрес берутся из конфига. В __construct() определяем вторую хлебную крошку – страницу “Блог”. В методах single() и tag() отвечающих за вывод подстраниц с одной записью и записями по тегу соответственно добавляем следующую хлебную крошку с информацией о страницах – названием и ссылкой. В index() это не требуется, так как мы уже объявили данную страницу в __construct(). Для вывода крошек используeтся app('breadcrumb')->toArray().

Дополнительные методы

Organization

Используется в blogPosting(). Обязателен для некоторых методов. Я не организация, что что поделать ¯_(ツ)_/¯

{
    "@context": "http://schema.org",
    "@type": "Organization",
    "@id": "https://example.com#organization",
    "url": "https://example.com",
    "name": "Awesome Organization",
    "description": "Add a description if you want.",
    "sameAs": [
        "facebook.com/Page",
        "plus.google.com/page",
        "twitter.com/page"
    ]
}
protected function publisher()
{
    return [
        '@type' => 'Organization',
        'name' => config('app.name'),
        'logo' => [
            '@type' => 'ImageObject',
            'url' => asset('images/logo.png')
        ]
    ];
}

ListItem

Используется в breadcrumbs(). Содержит информацию об элементе хлебных крошек – позиция, название, ссылка.

{
    "@type": "ListItem",
    "position": 1,
    "item": {
        "@id": "http://example.com",
        "name": "Website Name"
    }
}
protected function listItem(array $item)
{
    return [
        '@type' => 'ListItem',
        'position' => $item['position'] + 1,
        'item' => [
            '@id' => $item['url'],
            'name' => $item['name']
        ]
    ];
}

Выводим информацию

Полученные массивы необходимо преобразовать в JSON и вывести в head страницы. У меня для этого в родительском шаблоне определена область header, куда я их и вывожу.

<html lang="{{ config('app.locale') }}">
<head>
    @stack('header')
</head>
<body>
    Hello, world!
</body>
</html>
@push('header')
    <script type="application/ld+json">@json([$about, app('breadcrumb')->toArray()])</script>
@endpush

Да, данные должны находиться в script[type="application/ld+json"]. Возможно выводить как один из методов, так и несколько – завернув их в массив.

Заключение

JSON-LD – довольно легкий в освоении метод. Вместо темной тучи правок HTML он позволил мне обернуть все в красивый JSON. Здесь описаны лишь несколько вариантов разметки, которыми воспользовался я сам и которые пригодились на данном сайте. По факту любой из методов schema.org можно использовать с JSON-LD.

Во время тестирования можно воспользоваться инструментами для отладки – Гугл Яндекс. Надеюсь, данная статья вам помогла 🙂

Добавить комментарий