Next.jsで構造化データを入れる【Art Navi開発記録 #9】
はじめに
こんにちは。
なかのひとカンパニーの archer です。
美術展検索サービス Art Navi の開発内容を、備忘録も兼ねて記事にしています。
- サービスURL: https://art-weekend.jp/
前回は、sitemap.xml と robots.txt を整備した内容について書きました。
今回は、Art Naviで対応した 構造化データ についてまとめます。
今回やりたいこと
Art Naviでは、展覧会ページや施設ページを検索エンジンに正しく伝えるために、構造化データを入れる方針にしました。
今回やりたいことは以下です。
- JSON-LDで構造化データを出力する
- WebSite情報を伝える
- パンくず情報を伝える
- 展覧会ページや施設ページに応用できる形にする
構造化データを入れることで、検索エンジンにページの意味を伝えやすくなります。
構造化データとは
構造化データは、ページ内の情報を検索エンジンが理解しやすい形で伝えるためのデータです。
通常のHTMLだけでもページ内容は伝わりますが、構造化データを使うことで、以下のような情報をより明確に伝えられます。
- このサイトは何のサイトか
- このページは何のページか
- パンくずの階層はどうなっているか
- 展覧会名や会場名は何か
- 施設名や住所は何か
Art Naviでは、まずSEOの基本対応として、JSON-LD形式で構造化データを出力することにしました。
JSON-LDで出力する
構造化データはいくつか書き方がありますが、今回はJSON-LDを使います。
Next.jsでは、script タグで以下のように出力できます。
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd),
}}
/>
dangerouslySetInnerHTML という名前は少し怖いですが、JSON-LDを出力するときによく使う形です。
外部入力をそのまま埋め込む場合は注意が必要ですが、自分で生成したJSONを出す用途で使っています。
WebSiteの構造化データ
まずは、サイト全体を表す WebSite の構造化データを入れます。
const websiteJsonLd = {
"@context": "https://schema.org",
"@type": "WebSite",
name: "Art Navi",
url: "https://art-weekend.jp/",
description: "美術館や展覧会をエリア・ジャンルから探せるWebサービスです。",
};
ページ内では以下のように出力します。
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(websiteJsonLd),
}}
/>
これで、検索エンジンに対してArt NaviがWebサイトであることを伝えられます。
パンくずの構造化データ
次に、パンくずリストを表す BreadcrumbList を入れます。
たとえば、展覧会詳細ページでは以下のような階層を想定しています。
ホーム
↓
展覧会一覧
↓
展覧会詳細
JSON-LDでは以下のように書きます。
const breadcrumbJsonLd = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: [
{
"@type": "ListItem",
position: 1,
name: "ホーム",
item: "https://art-weekend.jp/",
},
{
"@type": "ListItem",
position: 2,
name: "展覧会一覧",
item: "https://art-weekend.jp/exhibitions",
},
{
"@type": "ListItem",
position: 3,
name: "展覧会詳細",
item: "https://art-weekend.jp/exhibitions/1",
},
],
};
パンくずは、ページの階層構造を検索エンジンに伝えるために使います。
Art Naviでは、展覧会詳細ページや施設詳細ページで特に重要だと考えています。
コンポーネント化する
毎回 script タグを書くと重複するため、JSON-LD出力用のコンポーネントを用意しました。
type JsonLdProps = {
data: Record<string, unknown>;
};
export function JsonLd({ data }: JsonLdProps) {
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(data),
}}
/>
);
}
使う側では、以下のように書けます。
<JsonLd data={breadcrumbJsonLd} />
共通コンポーネントにしておくと、ページごとに構造化データを追加しやすくなります。
展覧会詳細ページで使う
展覧会詳細ページでは、パンくずの構造化データを動的に生成します。
const exhibition = {
id: 1,
title: "印象派と光の表現",
};
const breadcrumbJsonLd = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: [
{
"@type": "ListItem",
position: 1,
name: "ホーム",
item: "https://art-weekend.jp/",
},
{
"@type": "ListItem",
position: 2,
name: "展覧会一覧",
item: "https://art-weekend.jp/exhibitions",
},
{
"@type": "ListItem",
position: 3,
name: exhibition.title,
item: `https://art-weekend.jp/exhibitions/${exhibition.id}`,
},
],
};
ページ内では以下のように出力します。
<JsonLd data={breadcrumbJsonLd} />
展覧会名をパンくずの最後に入れることで、ページごとの内容に合わせた構造化データになります。
施設詳細ページで使う
施設詳細ページでも同じようにパンくずを生成できます。
const venue = {
id: 1,
name: "上野の美術館",
};
const breadcrumbJsonLd = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: [
{
"@type": "ListItem",
position: 1,
name: "ホーム",
item: "https://art-weekend.jp/",
},
{
"@type": "ListItem",
position: 2,
name: "施設一覧",
item: "https://art-weekend.jp/venues",
},
{
"@type": "ListItem",
position: 3,
name: venue.name,
item: `https://art-weekend.jp/venues/${venue.id}`,
},
],
};
Art Naviでは、展覧会ページだけでなく、施設ページも検索流入の入口にしたいと考えています。
そのため、施設詳細ページにも構造化データを入れていく方針です。
URLは絶対URLにする
構造化データ内のURLは、相対URLではなく絶対URLで書くようにしました。
OK:
https://art-weekend.jp/exhibitions/1
NG:
/exhibitions/1
サイト全体で使うため、ベースURLは定数化しておくと便利です。
const BASE_URL = "https://art-weekend.jp";
本番URLを複数箇所に直接書くと変更に弱くなるため、最終的には環境変数や共通設定に寄せたいです。
確認方法
構造化データを入れたら、ページのHTMLにJSON-LDが出力されているか確認します。
ブラウザの開発者ツールで、以下のようなタグが出ていればOKです。
<script type="application/ld+json">
...
</script>
また、構造化データの形式に問題がないか確認するために、Googleのリッチリザルトテストなどでチェックします。
確認するときは、公開URLを入力します。
https://art-weekend.jp/
https://art-weekend.jp/exhibitions/1
エラーが出た場合は、JSON-LDの構造や必須項目を見直します。
気をつけたこと
構造化データを入れるときに気をつけたことは以下です。
- JSONとして壊れていないこと
- URLは絶対URLにすること
- 存在しないURLを入れないこと
- ページ内容と違う情報を入れないこと
- パンくずの順番を正しくすること
- 動的ページではページごとの値を使うこと
特に、ページに表示していない情報や、実態と違う情報を構造化データに入れないように注意しました。
SEO目的でも、ページ内容と一致していることが大事だと考えています。
今後やりたいこと
今後は、以下の構造化データも検討したいです。
- 展覧会ページ用の構造化データ
- 美術館・ギャラリーなど施設ページ用の構造化データ
- エリアページ用の構造化データ
- OGP画像との整合性確認
- Search Consoleでの検出状況確認
まずは、WebSite と BreadcrumbList を入れて、土台を作るところから進めています。
まとめ
今回は、Art Naviで対応した構造化データについてまとめました。
今回のポイントは以下です。
- 構造化データはJSON-LDで出力する
- Next.jsでは
script type="application/ld+json"を使う - 共通の
JsonLdコンポーネントを作ると使いやすい -
WebSiteでサイト全体の情報を伝える -
BreadcrumbListでページ階層を伝える - URLは絶対URLで書く
- ページ内容と一致した情報を入れる
SEOはすぐに効果が出るものではありませんが、サイト構造を検索エンジンに伝えるための土台として、早めに整備しておきたい部分だと感じました。
次回は、エリアページを作って検索導線を増やす内容について書く予定です。