本文へ移動
aapp-hacks
← 記事一覧へ
著者
app-hacks
公開日
更新日
確認日

Astro / SEO / JSON-LD

AstroでBlogPosting・BreadcrumbList構造化データを実装する

Astroの共通headでBlogPostingとBreadcrumbListのJSON-LDを生成し、生成HTMLで検証する実装に絞って解説します。

AstroでBlogPosting・BreadcrumbList構造化データを実装する

構造化データを記事ごとにMarkdownへ手書きすると、画面上のタイトル、公開日、canonicalとJSON-LDの値がずれやすくなります。記事ページがすでにFrontmatterから表示情報を受け取っているなら、同じ値を共通コンポーネントでBlogPostingとBreadcrumbListへ渡す方が安全です。

この記事では、Astroの記事レイアウトから受け取る実データだけでJSON-LDを出力し、生成HTMLで確認する方法を説明します。

Frontmatterとルート情報をSEOHeadへ渡し、BlogPostingとBreadcrumbListのJSON-LDを作る流れ

JSON-LDへ渡す値を画面表示と共有する

記事のtitle、description、正規URL、公開日、更新日、著者は、表示用と構造化データ用で別々に管理しません。共通のSEOコンポーネントへ渡し、記事ページでは実在するFrontmatterだけを使います。

<SEOHead
  title={`${post.data.title} | app-hacks`}
  description={post.data.description}
  canonical={canonicalUrl}
  type="article"
  pubDate={post.data.pubDate}
  updatedDate={post.data.updatedDate}
  article={{
    headline: post.data.title,
    authorName: post.data.author,
  }}
  breadcrumbs={breadcrumbs}
/>

公開日がない下書きは本番ルートを生成しないため、存在しない日付を補ってJSON-LDを出す必要はありません。著者や画像も、確認できない値を推測で追加しないことが重要です。

BlogPostingを条件付きで作る

JSON-LDは通常の<script>要素へ文字列として出力します。記事と公開日がある場合だけBlogPostingを配列へ加えます。

const blogPosting = article && pubDate
  ? {
      '@context': 'https://schema.org',
      '@type': 'BlogPosting',
      headline: article.headline,
      description,
      url: canonicalUrl.href,
      datePublished: pubDate.toISOString(),
      dateModified: (updatedDate ?? pubDate).toISOString(),
      author: { '@type': 'Organization', name: article.authorName },
    }
  : undefined;

dateModifiedは更新日がなければ公開日を使う、といった明示的な規則を置きます。これにより、表示上の公開日と構造化データの日付が別々に更新されるのを防げます。

パンくずもURLから組み立てる

パンくずは、ホーム、記事一覧、現在の記事のように、画面のナビゲーションと同じ順番で作ります。各項目の表示名とURLを配列で渡し、コンポーネント側で位置を付けます。

const breadcrumbs = [
  { name: 'ホーム', url: '/' },
  { name: '記事一覧', url: '/blog/' },
  { name: post.data.title, url: canonicalUrl },
];

URLを手書きの文字列で複数箇所に持つと、ルート変更時に片方だけ古くなります。new URL()を使ってサイトの正規URLを基準に絶対URLへ変換すれば、JSON-LDとcanonicalのホストもそろえられます。

scriptへ安全に埋め込む

オブジェクトはJSON.stringify()でJSONへ変換します。記事タイトルや説明に<が含まれる場合、script要素の解釈へ影響しないように置換してから出力します。

const jsonLdText = JSON.stringify(jsonLd).replace(/</g, '\\u003c');

この処理は構造化データの内容を創作するためではなく、HTML内でJSONを安全に扱うためのものです。値の正しさは、元のFrontmatterとcanonical URLの整合で担保します。

生成HTMLを確認する

npm run buildの後、実際の記事HTMLでapplication/ld+jsonを確認します。チェックするのは、@type、headline、description、URL、日付、著者、パンくずの順序です。特に開発用のlocalhost、公開前のURL、存在しない画像URLが混ざっていないかを確認してください。

構造化データは検索結果の表示を保証するものではありません。それでも、画面と同じ実データから生成し、公開前にHTMLを確認することで、値のずれや存在しない情報の掲載を防げます。

関連記事