Almost Over

Микроразметка Schema.org для поисковых сниппетов

Микроразметка Schema.org для поисковых сниппетов

Прежде всего хочу один немаловажный момент: микроразметка не улучшает ранжирование сайта в поисковиках напрямую, хотя и делает это косвенно. Добавив и настроив её, мы улучшим отображение того или иного материала в поисковиках, что, в свою очередь, повысит кликабельность наших ссылок. Например, если в выдаче гугла будет не просто ссылка на материал, а ссылка с именем и изображением автора, человек скоре кликнет именно по такой ссылке, нежели, чем по ссылке “безымянной”.
Иными словами, микроразметка — это, своего рода, удобные для визуального вида сниппеты в поисковиках, которые как минимум подсознательно привлекают внимание людей.
Понятно в чём приемущество? Сниппет = CTR = Траффик. wink
Подробнее о микроразметке можно почитать здесь.

В данном руководстве я приведу конкретные примеры настройки микроразметки Schema.org под тему Next Hexo движка, хотя аналогичным способом её можно настроить под любой статический сайт.

А в качестве бонуса будут приведены примеры ошибок и их исправления в W3C валидаторе, который также связан со структурой сайта в общем и c синтаксисом микроразметки в частности.

Микроразметка Schema.org

Для проверки структурированных данных используем следующие сервисы:

  1. Google Structured Data Tool.
  2. Яндекс Вебмастер Валидатор.

Настройка под «Яндекс Вебмастер Валидатор» требует больше базово заполненных полей и больше корректировки, в отличии от Гугла. Имеет смысл настраивать микроразметку под него в случае, если Ваш сайт имеет русскоязычную целевую аудиторию.

Просканировав через Гугл, у меня образовалась следующая картина.

Ошибки в «Google Structured Data Tool»

В нашем случае все ошибки происходят в контексте Article. Соответственно, все добавления нужно производить внутри поля itemtype="http://schema.org/Article".

Итак, приступим.

mainEntityOfPage

Рекомендуется заполнять поле mainEntityOfPage. Укажите значение, если оно известно.

Примерно переводится, как «Главный объект страницы» По-сути, является некой альтернативой “canonical url“ и не совсем понятно, для чего конкретно было введено это поле. Но раз рекомендуют заполнить — заполним.

В связи с изменениями микродаты в HTML5, текущее поле нужно заполнять не через meta, а через link.

If a meta element

  • has an itemprop attribute and a content attribute, and
  • has no name attribute, no http-equiv attribute, and no charset attribute,
    then it’s valid to have this meta in the body. (If the value is a URL, you must use link instead.)

Why? Because the Microdata specification changes HTML5.

(Note that RDFa also changes HTML5 by allowing meta in the body in some cases.)

Подробнее об этом можно почитать здесь и здесь.

$ nano themes/next/layout/_macro/post.swig
1
2
<article class="{{ post_class }}" itemscope itemtype="http://schema.org/Article">
+<link itemprop="mainEntityOfPage" href="{{ config.url }}{{ url_for(post.path) }}">

author & publisher

Необходимо указать значение для поля author.
Необходимо указать значение для поля publisher.

$ nano themes/next/layout/_macro/post.swig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<article class="{{ post_class }}" itemscope itemtype="http://schema.org/Article">
<link itemprop="mainEntityOfPage" href="{{ config.url }}{{ url_for(post.path) }}">

+ <span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
+ <meta itemprop="name" content="{{ theme.author }}">
+ <meta itemprop="description" content="{{ theme.signature }}">
+ <meta itemprop="image" content="{{ url_for( theme.avatar | default(theme.images + '/avatar.gif') ) }}">
+ </span>

+ <span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
+ <meta itemprop="name" content="{{ config.title }}">
+ <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
+ <img style="display:none;" itemprop="url image" alt="{{ config.title }}" src="{{ theme.custom_logo.image }}">
+ </span>
+ </span>

image

Необходимо указать значение для поля image.

$ nano themes/next/scripts/tags/full-image.js
1
2
3
4
5
6
- var image = ['<img src="' + src + '" class="full-image"'];
+ var image = ['<span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="' + src + '" class="full-image"'];
alt.length > 0 && image.push('alt="' + alt + '"');
title.length > 0 && image.push('title="' + title + '"');
- image.push('/>');
+ image.push('/><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span>');

datePublished

Необходимо указать значение для поля datePublished.

Решение предоставлено ниже.

dateModified

Рекомендуется заполнять поле dateModified. Укажите значение, если оно известно.

Решение предоставлено ниже.

W3C валидатор

Тестируем на ошибки синтаксис сайта через сервис W3 Html Checker.

Attribute content not allowed on element time at this point.

$ nano themes/next/layout/_macro/post.swig
1
2
3
4
5
6
7
8
9
10
11
12
13
-	<time itemprop="dateCreated" datetime="{{ moment(post.date).format() }}" content="{{ date(post.date, config.date_format) }}">
+ <time title="{{ __('post.created') }}" itemprop="dateCreated datePublished" datetime="{{ moment(post.date).format() }}">
{{ date(post.date, config.date_format) }}
</time>

+&nbsp;|&nbsp;

+ <span class="post-meta-item-icon">
+ <i class="fa fa-calendar-check-o"></i>
+ </span>
+ <time title="{{ __('post.modified') }}" itemprop="dateModified" datetime="{{ moment(post.updated).format() }}">
+ {{ date(post.updated, config.date_format) }}
+ </time>

Bad value Cache-Control for attribute http-equiv on element meta.

$ nano themes/next/layout/_partials/head.swig
1
2
3
4
5
-<meta http-equiv="Cache-Control" content="no-transform" />
-<meta http-equiv="Cache-Control" content="no-siteapp" />

-<meta charset="UTF-8"/>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>

A meta element with an http-equiv attribute whose value is X-UA-Compatible must have a content attribute with the value IE=edge.

$ nano themes/next/layout/_partials/head.swig
1
2
-<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
$ nano themes/next/layout/_partials/head/external-fonts.swig

И заменяем всё символы | на %7C.

$ nano themes/next/_config.yml

Спускаемся до “Font Settings” и заменяем пробелы в шрифтах на %20.

This document appears to be written in Russian. Consider adding lang="ru" (or variant) to the html start tag.

$ nano themes/next/layout/_layout.swig
1
2
-<html class="{{ html_class | lower }}">
+<html class="{{ html_class | lower }}" lang="{{ config.language }}">

Section lacks heading. Consider using h2-h6 elements to add identifying headings to all sections.

$ nano themes/next/layout/_macro/sidebar.swig
$ nano themes.next/layout/archive.swig
$ nano themes/next/layout/category.swig
$ nano themes/next/layout/index.swig

Заменяем все section на div.

Чистый результат

Результат «Google Structured Data Tool» после всех изменений Результат «W3 валидатора» после всех изменений

Яндекс Вебмастер Валидатор

Ну и напоследок, пробежимся по валидатору от Яши. Но как уже говорилось в самом начале — затачивать под валидатор Яндекса нет особой нужды, если, конечно, Вы не перфекционист. relieved

Поле commentsCount не определено в спецификации http://schema.org/Article

Ошибка в поле: не commentsCount, а commentCount.

$ nano themes/next/layout/_macro/post.swig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
          {% if post.comments %}
{% if (theme.duoshuo and theme.duoshuo.shortname) or theme.duoshuo_shortname %}
<span class="post-comments-count">
&nbsp;|&nbsp;
<a href="{{ url_for(post.path) }}#comments" itemprop="discussionUrl">
- <span class="post-comments-count ds-thread-count" data-thread-key="{{ post.path }}" itemprop="commentsCount"></span>
+ <span class="post-comments-count ds-thread-count" data-thread-key="{{ post.path }}" itemprop="commentCount"></span>
</a>
</span>

{% elseif theme.disqus_shortname %}
<!--noindex-->
<span class="post-comments-count">
&nbsp;|&nbsp;
<a href="{{ url_for(post.path) }}#comments" itemprop="discussionUrl">
- <span class="post-comments-count disqus-comment-count" data-disqus-identifier="{{ post.path }}" itemprop="commentsCount"></span>
+ <span class="post-comments-count disqus-comment-count" data-disqus-identifier="{{ post.path }}" itemprop="commentCount"></span>
</a>
</span>
<!--/noindex-->

{% elseif theme.hypercomments_id %}
<!--noindex-->
<span class="post-comments-count">
&nbsp;|&nbsp;
<span class="post-meta-item-icon">
<i class="fa fa-comment-o"></i>
<a href="{{ url_for(post.path) }}#comments" itemprop="discussionUrl">
- <span class="post-comments-count hc-comment-count" data-xid="{{ post.path }}" itemprop="commentsCount"></span>
+ <span class="post-comments-count hc-comment-count" data-xid="{{ post.path }}" itemprop="commentCount"></span>
</a>
</span>
</span>
<!--/noindex-->

Значение “” в поле commentCount не является корректным значением целого числа

Этот фикс у себя я не исполнил, т.к. по-факту кол-во комментариев подгружается асинхронно скриптом. И в том, что до подгрузки кол-ва комментариев, изначально у меня будет стоять цифра 0 вместо пустого поля, легче никому от этого не станет (кроме Яндекса, конечно же). В любом случае, фикс ниже.

$ nano themes/next/layout/_macro/post.swig
1
2
-<span class="post-comments-count hc-comment-count" data-xid="{{ post.path }}" itemprop="commentCount"></span>
+<span class="post-comments-count hc-comment-count" data-xid="{{ post.path }}" itemprop="commentCount">0</span>

Яндекс.Справочник — Организация

Не выполнено обязательное условие для структурированных сниппетов Яндекс.Справочника: поле address отсутствует или пусто
Не выполнено обязательное условие для структурированных сниппетов Яндекс.Справочника: для данной категории организаций необходимо указать telephone

Опять же, никто не требует адресов и телефонов, а вот Яндексу надо. Если у Вас действительно организация, то добавить эти поля имеет смысл. Если же нет, то, в принципе, можно заполнить фейковые данные.

$ nano themes/next/layout/_macro/post.swig 
1
2
3
4
5
6
7
8
	<span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="{{ config.title }}">
+ <meta itemprop="telephone" content="+7 495 555-00-00">
+ <meta itemprop="address" content="{{ config.timezone }}">
<span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
<img style="display:none;" itemprop="url" alt="{{ config.title }}" src="{{ theme.custom_logo.image }}">
</span>
</span>

Не выполнено обязательное условие для передачи данных в Яндекс.Картинки: поле contentUrl или image или thumbnail отсутствует или пусто

Здесь в контексте http://schema.org/ImageObject к каждому полю itemprop нужно помимо св-ва url добавить image, contentUrl или thumbnail.
Вот как-то так, например: itemprop="url image".

И да, кто под вордпрессом, самая актуальная и обсуждаемая статья про микроразметку — здесь.