メモログ

塵が積もって山とならないメモのログ

Add JSON-LD structured data

構造化データ(structured data)の部分をmicrodataからJSON-LDに置き換えてみた。

とりあえずArticle | Search | Google Developersにある「SEE MARKUP」からサンプルのJSON-LDのデータをコピーして、それを元にhexoのテンプレートの個別のページのアーカイブに下記のJSON-LDを追加。

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
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "BlogPosting",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "<%- page.permalink %>"
},
"headline": "<%- page.title %>",
<% if (page.featured && page.featured.image) { %>
"image": [
"https://memolog.org/assets/images/<%= page.featured.image %>/<%= page.featured.image %>.jpg"
],
<% } %>
"datePublished": "<%- page.date %>",
"dateModified": "<%- page.updated %>",
"author": {
"@type": "Person",
"name": "Yutaka Yamaguchi"
},
"publisher": {
"@type": "Organization",
"name": "メモログ",
"logo": {
"@type": "ImageObject",
"url": "https://memolog.org/assets/icons/icon-1024.png"
}
},
"description": "<%- remove_html(page.excerpt) %>"
}
</script>

descriptionにはHTMLを含まないテキストを出力したいのだけど、hexoのpage.excerptの出力にはHTMLが含まれていてそれを取り除く手段が標準ではない(ように見える)。なので、remove_htmlという簡単なヘルパーを用意した。改行の情報などもいらないので、DOMにデータを入れてそれをtextContentでテキスト部分を取得するだけ。

1
2
3
4
5
6
const jsdom = require('jsdom');
const { JSDOM } = jsdom;

hexo.extend.helper.register('remove_html', function(content){
return new JSDOM(`<div>${content}</div>`).window.document.getElementsByTagName('div')[0].textContent || '';
});

同様に、各ページの共通の情報としてLogoSocial Profileのデータを追加している。

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
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@graph":
[
{
"@context": "http://schema.org",
"@type": "Organization",
"url": "http://memolog.org",
"logo": "https://memolog.org/assets/icons/icon-1024.png"
},
{
"@context": "http://schema.org",
"@type": "Person",
"name": "Yutaka Yamaguchi",
"url": "http://memolog.org",
"sameAs": [
"https://www.facebook.com/yutaka.yamaguchi",
"https://www.linkedin.com/in/yutakayamaguchi/",
"https://twitter.com/memolog"
]
}
]
}
</script>

二つのトップレベルのアイテムを一つのscriptタグで追加したい場合は、@graphで記入すると良いとweb - JSON-LD Schema.org: Multiple video/image page - Stack Overflowに書かれてあったのでそのようにした(複数のscriptタグに分けてもいい)。

インデックステンプレートの方にはCarouselsの記述を入れることにした。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script type="application/ld+json">
{
"@context":"http://schema.org",
"@type":"ItemList",
"itemListElement":[
<% page.posts.each( (post, i) => { %>
{
"@type":"ListItem",
"position":<%- i+1 %>,
"url": "<%- post.permalink %>"
}<% if (i + 1 < page.posts.length ) { %>,<% } %>
<% }) %>
]
}
</script>

Carouselの表示はMark Up Your Content Items には、「The Top stories carousel requires that your content be published in AMP. For more information, see AMP with structured data.」とあり、non-AMPページではいわゆるカルーセルでの表示ではなく、リスト表示になるようである。

ので、そのうちAMPにも対応したいなと思うけど、まあそのうち。

最後に構造化データ テストツールで表示を確認。実際の検索結果に出てくるかどうかはわからないけど、データ的には特に問題なさそうである。

以上。