記事ページにJSON-LDを追加する

背景

サイトの成長を感じるために毎日Google Search Consoleを見ています。

どれくらい検索結果に表示されて、どれくらいクリックされているのかを確認するのが毎日とても楽しみにしているのですが、最近クリック率が徐々に下がってきてしまっています(6.0%->5.7%)

表示回数が増えるとクリック率も下がるかとは思うのですが、このままでは良くないと思い、json-ldを導入することにしました。

JSON-LDの仕様の確認

Googleの構造化データを含む非AMPページの箇所を確認します

https://developers.google.com/search/docs/advanced/structured-data/article

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
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "NewsArticle",
"headline": "Article headline",
"image": [
"https://example.com/photos/1x1/photo.jpg",
"https://example.com/photos/4x3/photo.jpg",
"https://example.com/photos/16x9/photo.jpg"
],
"datePublished": "2015-02-05T08:00:00+08:00",
"dateModified": "2015-02-05T09:20:00+08:00",
"author": [{
"@type": "Person",
"name": "Jane Doe",
"url": "http://example.com/profile/janedoe123"
},{
"@type": "Person",
"name": "John Doe",
"url": "http://example.com/profile/johndoe123"
}]
}
</script>

となっています。

これを各記事ページで動的に対応していきます。

項目の精査

それぞれ項目をどう設定するかを見ていきます。

@context

こちらは固定で https://schema.orgで良さそうです。

@type

こちらはArticleNewsArticleBlogPostingが選択できるようですが、一旦Articleにしておきます

headline

Headlineはtitleと同じでよいかなと思います。変数で指定します

image

記事内の画像の一覧を変数で指定します

datePublished

記事内の変数を参照します

datePublished

こちらも同じように記事内の変数を参照します

author

こちらは固定で@typeはPerson、nameは自分の名前、urlはaboutmeを指定します

ではパーシャルを作成していきます。

パーシャルの作成

themes/landscape/layout/_partial/ディレクトリの下にjson-ld.ejsというファイルを作成します。

中身は以下のようにします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "<%- post.title %>",
<% if (post.twitter_image){ %>
"image": [
"<%- post.twitter_image %>"
],
<% } %>
"datePublished": "<%- date(post.date, "YYYY-MM-DDTHH:mm:ss") %>",
"dateModified": "<%- date(post.updated, "YYYY-MM-DDTHH:mm:ss") %>",
"author": [{
"@type": "Person",
"name": "Motoaki Shibagaki",
"url": "https://book-reviews.blog/aboutme/"
}]
}
</script>

最初、"image"は複数設定できた方が良いかなと思い、記事内のymlで画像URLの配列を作成していたのですが、うまく文字列の配列を作成できず断念しました。こちらについてはまた時間を作ってチャレンジしたいと思います。

記事ページの判定

作成したパーシャルをheadタグ周りのパーシャルであるthemes/landscape/layout/_partial/head.ejsで読み込みます。

1
2
3
4
5
6
7
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<%- partial('google-analytics') %>
<%- partial('google-adsense') %>
<%- partial('json-ld') %>

しかし、このままでは、記事ページ以外でもjson-ldのスクリプトが表示されてしまいます。

ですので、記事ページの判定を行います。記事ページの判定にはis_post()という関数を利用します。

最終的にjson-ld.ejsは以下のようになります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<% if (is_post()){ %>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "<%- post.title %>",
<% if (post.twitter_image){ %>
"image": [
"<%- post.twitter_image %>"
],
<% } %>
"datePublished": "<%- date(post.date, "YYYY-MM-DDTHH:mm:ss") %>",
"dateModified": "<%- date(post.updated, "YYYY-MM-DDTHH:mm:ss") %>",
"author": [{
"@type": "Person",
"name": "Motoaki Shibagaki",
"url": "https://book-reviews.blog/aboutme/"
}]
}
</script>
<% } %>

動作確認

では動作確認をします。

記事ページを表示させて、json-ldが表示されているかを確認します。記事ページはhttps://book-reviews.blog/error-creating-the-test-database-on-Django/で試しました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Djangoでテスト実行時にテスト用データベース作成エラーが発生した時の対応",

"image": [
"https://book-reviews.blog/images/django-logo.png"
],

"datePublished": "2021-12-07T23:30:00",
"dateModified": "2021-12-07T23:30:00",
"author": [{
"@type": "Person",
"name": "Motoaki Shibagaki",
"url": "https://book-reviews.blog/aboutme/"
}]
}

大丈夫そうですね!

エラー発生

リリースしてから何日か後にサーチコンソールでエラーが発生しました。

解析不能な構造化データがあるというエラーでした。

原因を調べてみると、タイトルにダブルクォートが入っていて、タイトルの区切り文字として認識されてしまい、syntax errorになっていました。

一旦ダブルクォートを利用しないようにして対応しましたが、本当はもっといい方法があると思います。こちらも時間があるときに調査したいと思います。

まとめ

CTRを上げるために、JSON-LDを追加しました。結果はというと、かなり良い感じでCTRが上がっています(5.7% -> 6.5%)。

短期的に見ているので、実際はもう少し下がるのかなと思うのですが、効果が出ていて嬉しいです。

良い構造化データを作成するために、画像の複数指定や、タイトルの作成についてもう少し掘っていきたいと思います。