- SEO
構造化データJSON-LDの書き方|型別コピペ例と検証手順
JSON-LDとは、ページの内容(記事・商品・イベントなど)を検索エンジンが読み取りやすい形で伝えるための、JSON形式の構造化データの書き方です。 HTML の中に <script type="application/ld+json"> を1つ置き、schema.org の語彙で「このページは記事で、著者は誰で、公開日はいつか」といった情報を書きます。Google は JSON-LD を推奨形式としており、条件を満たすと検索結果にリッチリザルト(パンくず、商品の価格や評価、イベント日時などの拡張表示)が表示されることがあります。
この記事では、Google が2026年10月時点でサポートしている型の一覧と、FAQ・HowTo など表示が終了した型の判断表を Google 検索セントラルで確認してまとめました。そのうえで、架空の中立なデータを使った9種類のコピペ用 JSON-LD、必須・推奨プロパティ表、Python 3.11 の標準ライブラリで構文と必須プロパティを自動チェックした実行結果、WordPress の functions.php から出力するコード(PHP 8.4 で出力を確認)を紹介します。
JSON-LDの早見表
| やりたいこと | 使う型(@type) | Google の必須プロパティ | 主な表示 |
|---|---|---|---|
| ブログ・ニュース記事を伝える | Article / BlogPosting / NewsArticle |
なし(推奨:headline・image・datePublished・dateModified・author) | 記事のタイトル・画像・日付の理解 |
| パンくずを表示する | BreadcrumbList |
itemListElement(ListItem に position・name・item) | URL 部分がパンくず表示に |
| 会社・組織の情報を伝える | Organization |
なし(推奨:name・url・logo・sameAs など) | ナレッジパネル・ロゴの参考 |
| サイト名を伝える | WebSite |
name・url(トップページに置く) | 検索結果のサイト名 |
| 商品の価格・評価を出す | Product + Offer |
name + offers・review・aggregateRating のどれか | 価格・在庫・星評価 |
| イベントを載せる | Event |
name・startDate・location(location.address) | イベント一覧の表示 |
| 求人を載せる | JobPosting |
title・description・datePosted・hiringOrganization・jobLocation | Google しごと検索 |
| 店舗・事業所の情報 | LocalBusiness(Store など下位型) |
name・address | 店舗情報の理解 |
| 動画を伝える | VideoObject |
name・thumbnailUrl・uploadDate | 動画のサムネイル・再生時間 |
| 書き方の基本 | 内容 |
|---|---|
| 置き場所 | <head> または <body> のどこでも可。<script type="application/ld+json"> の中に書く |
@context |
"https://schema.org" |
@type |
上の表の型名(大文字小文字も一致させる) |
| 日付 | ISO 8601 形式:2026-10-01 や 2026-10-01T09:00:00+09:00 |
| URL | https:// から始まる絶対URL |
| 複数の型 | @graph の配列にまとめる、または <script> を複数置く |
| 内容 | ページに実際に表示されている内容と一致させる |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「構造化データJSON-LDの書き方|型別コピペ例と検証手順」
Googleが現在サポートしている型(2026年10月時点)
Google 検索セントラルの「Search Gallery(検索ギャラリー)」に載っている構造化データの機能は次のとおりです。
| 分類 | 機能(Search Gallery の名称) |
|---|---|
| 記事・サイト | Article、Breadcrumb、Carousel、Organization、Profile page、Speakable、Subscription and paywalled content、Image metadata |
| 商品・評価 | Product(商品スニペット・販売者リスティング)、Review snippet、Employer aggregate rating、Software app |
| イベント・求人・店舗 | Event、Job posting、Local business、Vacation rental |
| 動画・作品 | Video、Movie、Recipe |
| 学習・Q&A | Course list、Education Q&A、Math solver、Q&A、Discussion forum |
| データ | Dataset(Dataset Search 向け。Google 検索の表示向けではないと明記) |
表示が終了・縮小した型の判断表
Google 検索セントラルの「ドキュメントの更新履歴」と各ページの告知で確認した内容です。
| 型 | 状況 | 時期 | 既存のマークアップ |
|---|---|---|---|
FAQ(FAQPage) |
リッチリザルトの表示を終了 | 2026年5月(2023年8月から一部の公的な権威あるサイトに限定されていた) | 残しても問題なし。新しく追加する必要はない |
HowTo(HowTo) |
リッチリザルトの表示を終了 | 2023年9月 | 同上 |
サイトリンク検索ボックス(WebSite の potentialAction / SearchAction) |
機能自体を終了 | 2024年11月 | 同上。WebSite はサイト名用として引き続き使う |
| Course info、Estimated salary、Learning video、Special announcement、Vehicle listing | 表示を終了し、ドキュメントも削除 | 2025年6月に告知、9月に削除 | 同上 |
| ClaimReview(ファクトチェック) | 2025年6月に段階的終了を告知 | 2025年6月 | 同上 |
| Practice problem | 終了を告知し、2026年1月から削除開始 | 2025年11月告知 | 同上 |
| Book actions | 2025年6月に終了を告知したが、11月に撤回され継続 | 2025年11月 | 引き続き利用可 |
判断の目安は「Search Gallery に載っている型だけがリッチリザルトの対象」 です。表示が終了した型のマークアップは、エラーや評価の低下につながるものではないため、急いで削除する必要はありません。ただし、これから新しく作る場合は、Search Gallery にある型を優先すると手間に見合った効果が得られます。
型別コピペ集(架空のデータ)
すべて架空のサイト「サンプル書店」「サンプル文具店」「サンプル株式会社」のデータで、ドメインは example.com です。HTML に貼るときは <script type="application/ld+json"> と </script> で囲みます。
<script type="application/ld+json">
{ ここに下の JSON を貼る }
</script>
1. 記事(BlogPosting / Article)
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "在庫管理の始め方|備品を表で整理する手順",
"image": [
"https://www.example.com/images/inventory-1x1.png",
"https://www.example.com/images/inventory-4x3.png",
"https://www.example.com/images/inventory-16x9.png"
],
"datePublished": "2026-10-01T09:00:00+09:00",
"dateModified": "2026-10-01T09:00:00+09:00",
"author": [{
"@type": "Person",
"name": "山田 花子",
"url": "https://www.example.com/authors/hanako/"
}],
"publisher": {
"@type": "Organization",
"name": "サンプル書店",
"logo": { "@type": "ImageObject", "url": "https://www.example.com/logo.png" }
},
"mainEntityOfPage": "https://www.example.com/articles/inventory-basics/"
}
Article には必須プロパティがありません。 画像は 1:1・4:3・16:9 の3比率を用意すると、表示場所に合わせて選ばれやすくなります。著者が複数なら author の配列に追加します。
2. パンくずリスト(BreadcrumbList)
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "ホーム", "item": "https://www.example.com/" },
{ "@type": "ListItem", "position": 2, "name": "記事一覧", "item": "https://www.example.com/articles/" },
{ "@type": "ListItem", "position": 3, "name": "在庫管理の始め方" }
]
}
最後の項目(今いるページ)は item を省略できます。 position は 1 から順番に付けます。
3. 組織(Organization)
{
"@context": "https://schema.org",
"@type": "Organization",
"@id": "https://www.example.com/#organization",
"name": "サンプル書店",
"alternateName": "Sample Books",
"url": "https://www.example.com/",
"logo": "https://www.example.com/logo.png",
"sameAs": [
"https://x.com/example",
"https://www.youtube.com/@example"
],
"contactPoint": {
"@type": "ContactPoint",
"telephone": "+81-3-0000-0000",
"contactType": "customer support",
"availableLanguage": ["Japanese"]
},
"address": {
"@type": "PostalAddress",
"streetAddress": "見本町1-2-3",
"addressLocality": "千代田区",
"addressRegion": "東京都",
"postalCode": "100-0000",
"addressCountry": "JP"
}
}
トップページまたは会社概要ページに1つ置くのが基本です。@id を付けておくと、他の JSON-LD から { "@id": "https://www.example.com/#organization" } で参照できます。
4. サイト名(WebSite)
{
"@context": "https://schema.org",
"@type": "WebSite",
"@id": "https://www.example.com/#website",
"name": "サンプル書店",
"alternateName": ["Sample Books", "サンプルブックス"],
"url": "https://www.example.com/",
"publisher": { "@id": "https://www.example.com/#organization" }
}
検索結果に表示されるサイト名の参考にされます。 トップページだけに置きます。サイトリンク検索ボックス用の potentialAction は機能が終了したため、新しく書く必要はありません。
5. 商品(Product)
{
"@context": "https://schema.org",
"@type": "Product",
"name": "A5 方眼ノート 80枚",
"image": ["https://www.example.com/items/notebook-a5.png"],
"description": "5mm方眼のA5ノート。開きやすい糸かがり綴じです。",
"sku": "NB-A5-080",
"brand": { "@type": "Brand", "name": "サンプル文具" },
"offers": {
"@type": "Offer",
"url": "https://www.example.com/items/notebook-a5/",
"price": 880,
"priceCurrency": "JPY",
"availability": "https://schema.org/InStock",
"itemCondition": "https://schema.org/NewCondition"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": 4.4,
"reviewCount": 27
}
}
price は数値、priceCurrency は ISO 4217 の3文字(日本円は JPY) で書きます。購入できるページ(販売者リスティング)では offers と priceCurrency が必須、レビューや比較のページ(商品スニペット)では offers・review・aggregateRating のどれか1つが必須です。評価はページ上に実際に表示しているものだけを書きます。
6. イベント(Event)
{
"@context": "https://schema.org",
"@type": "Event",
"name": "在庫管理ツール入門勉強会",
"startDate": "2026-11-14T13:00:00+09:00",
"endDate": "2026-11-14T16:00:00+09:00",
"eventStatus": "https://schema.org/EventScheduled",
"eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode",
"location": {
"@type": "Place",
"name": "見本町ホール 3F",
"address": {
"@type": "PostalAddress",
"streetAddress": "見本町1-2-3",
"addressLocality": "千代田区",
"addressRegion": "東京都",
"postalCode": "100-0000",
"addressCountry": "JP"
}
},
"image": ["https://www.example.com/events/study-16x9.png"],
"description": "表計算で備品と在庫を管理する方法を、手を動かしながら学ぶ勉強会です。",
"offers": {
"@type": "Offer",
"url": "https://www.example.com/events/study/",
"price": 0,
"priceCurrency": "JPY",
"availability": "https://schema.org/InStock",
"validFrom": "2026-10-01T10:00:00+09:00"
},
"organizer": { "@type": "Organization", "name": "サンプル書店", "url": "https://www.example.com/" }
}
日時はタイムゾーン付き(+09:00)で書くと、時差による表示のずれを防げます。延期・中止のときは eventStatus を EventPostponed・EventCancelled に変えます。
7. 求人(JobPosting)
{
"@context": "https://schema.org",
"@type": "JobPosting",
"title": "Webエンジニア",
"description": "<p>自社の会員サイトと在庫管理システムの開発を担当します。</p><p>使用技術:TypeScript、PostgreSQL</p>",
"datePosted": "2026-10-01",
"validThrough": "2026-12-31T23:59:59+09:00",
"employmentType": "FULL_TIME",
"hiringOrganization": {
"@type": "Organization",
"name": "サンプル株式会社",
"sameAs": "https://www.example.com/",
"logo": "https://www.example.com/logo.png"
},
"jobLocation": {
"@type": "Place",
"address": {
"@type": "PostalAddress",
"streetAddress": "見本町1-2-3",
"addressLocality": "千代田区",
"addressRegion": "東京都",
"postalCode": "100-0000",
"addressCountry": "JP"
}
},
"baseSalary": {
"@type": "MonetaryAmount",
"currency": "JPY",
"value": { "@type": "QuantitativeValue", "minValue": 4000000, "maxValue": 6000000, "unitText": "YEAR" }
},
"identifier": { "@type": "PropertyValue", "name": "サンプル株式会社", "value": "ENG-2026-001" },
"directApply": true
}
title には職種名だけを書きます(求人番号・勤務地・給与は入れない)。description は HTML の段落タグが使えます。募集終了時は validThrough を過ぎるか、ページを削除・noindex にします。フルリモートの場合は jobLocationType: "TELECOMMUTE" と applicantLocationRequirements を加えます。
8. 店舗(LocalBusiness)
{
"@context": "https://schema.org",
"@type": "Store",
"name": "サンプル文具店 見本町店",
"image": ["https://www.example.com/shop/front.png"],
"url": "https://www.example.com/shop/mihon/",
"telephone": "+81-3-0000-0000",
"address": {
"@type": "PostalAddress",
"streetAddress": "見本町1-2-3",
"addressLocality": "千代田区",
"addressRegion": "東京都",
"postalCode": "100-0000",
"addressCountry": "JP"
},
"geo": { "@type": "GeoCoordinates", "latitude": 35.6812, "longitude": 139.7671 },
"openingHoursSpecification": [{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
"opens": "10:00",
"closes": "19:00"
}],
"priceRange": "¥"
}
@type は LocalBusiness のままでも使えますが、Store・Restaurant・Library など、より具体的な下位型を選ぶと内容が伝わりやすくなります。店舗が複数あるときは、店舗ごとのページにそれぞれ置きます。
9. 動画(VideoObject)
{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "在庫管理表の作り方(5分)",
"description": "表計算ソフトで在庫管理表を作る手順を5分で紹介します。",
"thumbnailUrl": ["https://www.example.com/videos/inventory-thumb.png"],
"uploadDate": "2026-10-01T09:00:00+09:00",
"duration": "PT5M12S",
"contentUrl": "https://www.example.com/videos/inventory.mp4",
"embedUrl": "https://www.example.com/embed/inventory",
"creator": { "@type": "Organization", "name": "サンプル書店", "url": "https://www.example.com/" }
}
duration は ISO 8601 の期間形式(PT5M12S = 5分12秒)です。creator は 2026年9月のドキュメント更新で推奨プロパティとして明記されました。
複数の型を @graph でまとめる
1ページに記事・パンくず・組織を載せるときは、@graph で1つの <script> にまとめると管理しやすくなります。
{
"@context": "https://schema.org",
"@graph": [
{ "@type": "Organization", "@id": "https://www.example.com/#organization", "name": "サンプル書店", "url": "https://www.example.com/", "logo": "https://www.example.com/logo.png" },
{ "@type": "BlogPosting", "headline": "在庫管理の始め方", "datePublished": "2026-10-01T09:00:00+09:00", "publisher": { "@id": "https://www.example.com/#organization" } },
{ "@type": "BreadcrumbList", "itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "ホーム", "item": "https://www.example.com/" },
{ "@type": "ListItem", "position": 2, "name": "在庫管理の始め方" }
] }
]
}
必須・推奨プロパティ表
Google 検索セントラルの各機能ページで確認した内容です(2026年10月時点)。必須が欠けるとリッチリザルトの対象外、推奨が欠けると表示される情報が減る、という違いがあります。
| 型 | 必須 | 主な推奨 |
|---|---|---|
| Article / BlogPosting | なし | headline、image、datePublished、dateModified、author(author.name・author.url) |
| BreadcrumbList | itemListElement | ― |
| ListItem | position、name、item(最後の項目は省略可) | ― |
| Organization | なし | name、url、logo、sameAs、address、contactPoint、alternateName |
| WebSite(サイト名) | name、url | alternateName |
| Product(商品スニペット) | name + offers・review・aggregateRating のどれか | aggregateRating、offers、review |
| Offer | price(または priceSpecification.price)、販売者リスティングでは priceCurrency も | availability、priceValidUntil、priceCurrency |
| Event | name、startDate、location(location.address) | description、endDate、eventStatus、image、offers、organizer、performer |
| JobPosting | title、description、datePosted、hiringOrganization、jobLocation | validThrough、employmentType、baseSalary、identifier、directApply、jobLocationType |
| LocalBusiness | name、address | url、telephone、geo、openingHoursSpecification、priceRange、image |
| VideoObject | name、thumbnailUrl、uploadDate | description、duration、contentUrl、embedUrl、creator、expires |
検証手順:Pythonで自動チェック(実行結果つき)
公開前に、JSON の構文エラーと必須プロパティの抜けを手元で一括チェックするスクリプトです。Python 3.11 の標準ライブラリだけで動きます。.json ファイルと、<script type="application/ld+json"> を含む .html ファイルのどちらも読めます。
check_jsonld.py
"""JSON-LD の構文と必須プロパティをチェックする(Python 3.11 標準ライブラリのみ)
使い方: python3 check_jsonld.py ファイル.json|ファイル.html [...]
"""
import json
import sys
from datetime import date, datetime
from html.parser import HTMLParser
from urllib.parse import urlparse
# Google 検索セントラルの「必須プロパティ」(2026年10月時点で確認)
REQUIRED = {
"Article": [], "BlogPosting": [], "NewsArticle": [], # 必須なし(推奨のみ)
"BreadcrumbList": ["itemListElement"],
"ListItem": ["position", "name"], # 最後の項目以外は item も必要
"Organization": [], # 必須なし(推奨のみ)
"WebSite": ["name", "url"], # サイト名
"Product": ["name", ["offers", "review", "aggregateRating"]], # name + いずれか1つ
"Offer": ["price", "priceCurrency"],
"Event": ["name", "startDate", "location"],
"JobPosting": ["title", "description", "datePosted", "hiringOrganization", "jobLocation"],
"LocalBusiness": ["name", "address"], "Store": ["name", "address"],
"VideoObject": ["name", "thumbnailUrl", "uploadDate"],
}
RECOMMENDED = {
"BlogPosting": ["headline", "image", "datePublished", "dateModified", "author"],
"Article": ["headline", "image", "datePublished", "dateModified", "author"],
"Event": ["description", "endDate", "eventStatus", "image", "offers", "organizer"],
"JobPosting": ["validThrough", "employmentType", "baseSalary", "identifier"],
"VideoObject": ["description", "duration", "contentUrl", "embedUrl"],
}
DATE_KEYS = {"datePublished", "dateModified", "startDate", "endDate", "datePosted",
"validThrough", "uploadDate", "validFrom"}
URL_KEYS = {"url", "item", "logo", "image", "thumbnailUrl", "contentUrl", "embedUrl", "sameAs"}
class LdParser(HTMLParser):
def __init__(self):
super().__init__()
self.inside = False
self.blocks = []
def handle_starttag(self, tag, attrs):
if tag == "script" and dict(attrs).get("type") == "application/ld+json":
self.inside = True
self.blocks.append("")
def handle_endtag(self, tag):
if tag == "script":
self.inside = False
def handle_data(self, data):
if self.inside:
self.blocks[-1] += data
def is_iso(v: str) -> bool:
for f in (datetime.fromisoformat, date.fromisoformat):
try:
f(v)
return True
except ValueError:
pass
return False
def walk(node, path, out):
"""ノードを再帰的にたどって @type ごとにチェックする"""
if isinstance(node, list):
for i, n in enumerate(node):
walk(n, f"{path}[{i}]", out)
return
if not isinstance(node, dict):
return
t = node.get("@type")
types = t if isinstance(t, list) else [t]
for ty in types:
for req in REQUIRED.get(ty, []):
if isinstance(req, list):
if not any(k in node for k in req):
out.append(("NG", f"{path}({ty}): {' / '.join(req)} のどれか1つが必須"))
elif req not in node:
out.append(("NG", f"{path}({ty}): 必須の {req} がない"))
for rec in RECOMMENDED.get(ty, []):
if rec not in node:
out.append(("注意", f"{path}({ty}): 推奨の {rec} がない"))
for k, v in node.items():
if k in DATE_KEYS and isinstance(v, str) and not is_iso(v):
out.append(("NG", f"{path}.{k}: ISO 8601 形式ではない: {v}"))
if k in URL_KEYS:
for u in (v if isinstance(v, list) else [v]):
if isinstance(u, str) and not urlparse(u).scheme:
out.append(("NG", f"{path}.{k}: 絶対URLではない: {u}"))
if k == "price" and not str(v).replace(".", "", 1).isdigit():
out.append(("NG", f"{path}.price: 数値ではない: {v}"))
if isinstance(v, (dict, list)):
walk(v, f"{path}.{k}", out)
def check_text(label, text):
try:
data = json.loads(text)
except json.JSONDecodeError as e:
print(f"[{label}] 構文エラー: {e.msg} (行 {e.lineno}, 列 {e.colno})")
return
out = []
for i, root in enumerate(data if isinstance(data, list) else [data]):
ctx = root.get("@context", "")
if "schema.org" not in str(ctx):
out.append(("NG", f"$[{i}]: @context が schema.org ではない: {ctx!r}"))
if "@graph" in root:
walk(root["@graph"], "$.@graph", out)
else:
walk(root, "$", out)
t = data.get("@type", "@graph") if isinstance(data, dict) else "配列"
ng = sum(1 for lv, _ in out if lv == "NG")
print(f"[{label}] {t}: 必須OK" if ng == 0 else f"[{label}] {t}: NG {ng}件")
for lv, msg in out:
print(f" {lv}: {msg}")
for path in sys.argv[1:]:
text = open(path, encoding="utf-8").read()
if path.endswith(".html"):
p = LdParser()
p.feed(text)
for i, b in enumerate(p.blocks, 1):
check_text(f"{path}#{i}", b)
else:
check_text(path, text)
よくある間違いを入れたテスト用 HTML(bad.html)
<!doctype html>
<html lang="ja"><head>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Event",
"name": "在庫管理ツール入門勉強会",
"startDate": "2026/11/14 13:00",
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Event",
"name": "在庫管理ツール入門勉強会",
"startDate": "2026/11/14 13:00",
"image": "/events/study.png"
}
</script>
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "Product",
"name": "A5 方眼ノート 80枚",
"offers": { "@type": "Offer", "price": "880円" }
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{ "@type": "Organization", "@id": "https://www.example.com/#organization", "name": "サンプル書店", "url": "https://www.example.com/" },
{ "@type": "WebSite", "name": "サンプル書店", "publisher": { "@id": "https://www.example.com/#organization" } }
]
}
</script>
</head><body></body></html>
実行結果
上のコピペ集9種を samples/ に保存し、bad.html と一緒にチェックしました。
$ python3 --version
Python 3.11.15
$ python3 check_jsonld.py samples/*.json bad.html
[samples/article.json] BlogPosting: 必須OK
[samples/breadcrumb.json] BreadcrumbList: 必須OK
[samples/event.json] Event: 必須OK
[samples/jobposting.json] JobPosting: 必須OK
[samples/localbusiness.json] Store: 必須OK
[samples/organization.json] Organization: 必須OK
[samples/product.json] Product: 必須OK
[samples/video.json] VideoObject: 必須OK
[samples/website.json] WebSite: 必須OK
[bad.html#1] 構文エラー: Expecting property name enclosed in double quotes (行 7, 列 1)
[bad.html#2] Event: NG 3件
NG: $(Event): 必須の location がない
注意: $(Event): 推奨の description がない
注意: $(Event): 推奨の endDate がない
注意: $(Event): 推奨の eventStatus がない
注意: $(Event): 推奨の offers がない
注意: $(Event): 推奨の organizer がない
NG: $.startDate: ISO 8601 形式ではない: 2026/11/14 13:00
NG: $.image: 絶対URLではない: /events/study.png
[bad.html#3] Product: NG 2件
NG: $.offers(Offer): 必須の priceCurrency がない
NG: $.offers.price: 数値ではない: 880円
[bad.html#4] @graph: NG 1件
NG: $.@graph[1](WebSite): 必須の url がない
結果から分かることは次のとおりです。
- コピペ集の9種はすべて必須プロパティを満たしていました。
- #1 の構文エラーは、最後のプロパティの後ろの余分なカンマ(末尾カンマ)が原因です。JSON は末尾カンマを許さないため、エラー位置は次の行の
}(7行目1列目)と表示されます。 - 日付の
2026/11/14 13:00は ISO 8601 ではないため NG。2026-11-14T13:00:00+09:00に直します。 "880円"は数値ではないため NG。880と"priceCurrency": "JPY"に分けます。http://schema.orgは schema.org として読まれるため OK としていますが、新しく書くならhttps://に統一すると見た目がそろいます。
このスクリプトは構文と必須項目の抜けを素早く見つけるための手元チェックです。最終確認は次の Google のツールで行います。
リッチリザルトテストと Schema Markup Validator の使い方
どちらもブラウザで使う外部ツールのため、ここでは手順のみを紹介します(本記事の環境からは実行していません)。
| ツール | 確認できること | 向いている場面 |
|---|---|---|
| リッチリザルトテスト(Google) | Google のリッチリザルトの対象になるか、必須・推奨の不足 | Google 検索での表示を確認したいとき |
| Schema Markup Validator(schema.org) | schema.org の語彙として正しいか(Google 非対応の型も含む) | 型やプロパティ名の綴りを確認したいとき |
| Search Console の「拡張」レポート | 公開後のサイト全体でのエラー・警告の件数 | 公開後に継続して確認したいとき |
リッチリザルトテストの手順
- Google の「リッチリザルトテスト」を開きます。
- 公開済みなら「URL」、公開前なら「コード」タブに HTML または JSON-LD を貼り付けます。
- 「スマートフォン」のクローラーを選んでテストを実行します。
- 「検出された構造化データ」に型が表示されます。赤(エラー)は必須の不足、黄(警告)は推奨の不足です。
- 項目をクリックすると、該当するプロパティと値を確認できます。
Schema Markup Validator の手順
- 「validator.schema.org」を開きます。
- URL を入力するか、コードを貼り付けて実行します。
- 抽出された型とプロパティがツリーで表示されます。プロパティ名の綴り間違い(例:
datepublished)はここで見つけやすくなります。
flowchart LR
A[JSON-LDを書く] --> B[check_jsonld.pyで構文と必須を確認]
B --> C[リッチリザルトテストで対象か確認]
C --> D[公開]
D --> E[Search Consoleの拡張レポートで継続確認]
WordPressでの入れ方
functions.php に wp_head で出力する
テーマ(できれば子テーマ)の functions.php に追記する例です。投稿ページにだけ、BlogPosting と BreadcrumbList を @graph で出力します。
<?php
/**
* 投稿ページに BlogPosting と BreadcrumbList の JSON-LD を出力する
* テーマ(子テーマ)の functions.php に追記
*/
add_action( 'wp_head', 'mytheme_output_jsonld', 20 );
function mytheme_output_jsonld() {
if ( ! is_singular( 'post' ) ) {
return;
}
$post_id = get_queried_object_id();
$permalink = get_permalink( $post_id );
$image = get_the_post_thumbnail_url( $post_id, 'full' );
$graph = array(
array(
'@type' => 'BlogPosting',
'@id' => $permalink . '#article',
'headline' => wp_strip_all_tags( get_the_title( $post_id ) ),
'datePublished' => get_the_date( 'c', $post_id ),
'dateModified' => get_the_modified_date( 'c', $post_id ),
'author' => array(
'@type' => 'Person',
'name' => get_the_author_meta( 'display_name', get_post_field( 'post_author', $post_id ) ),
'url' => get_author_posts_url( get_post_field( 'post_author', $post_id ) ),
),
'mainEntityOfPage' => $permalink,
),
array(
'@type' => 'BreadcrumbList',
'itemListElement' => array(
array( '@type' => 'ListItem', 'position' => 1, 'name' => 'ホーム', 'item' => home_url( '/' ) ),
array( '@type' => 'ListItem', 'position' => 2, 'name' => wp_strip_all_tags( get_the_title( $post_id ) ) ),
),
),
);
if ( $image ) {
$graph[0]['image'] = array( $image );
}
$data = array(
'@context' => 'https://schema.org',
'@graph' => $graph,
);
echo "\n" . '<script type="application/ld+json">'
. wp_json_encode( $data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_HEX_TAG )
. '</script>' . "\n";
}
| ポイント | 理由 |
|---|---|
get_the_date( 'c' ) |
c は ISO 8601 形式(2026-10-01T09:00:00+09:00)で日付を返す書式 |
wp_json_encode() |
WordPress の JSON 出力関数。配列から JSON を作るので、手書きのカンマ抜け・引用符抜けが起きない |
JSON_UNESCAPED_UNICODE |
日本語をそのままの文字で出力し、ソースを読みやすくする |
JSON_HEX_TAG |
値に < > が含まれても Unicode エスケープに置き換えるため、タイトルに </script> のような文字列が入っても script 要素が途中で閉じない |
wp_strip_all_tags() |
タイトルに含まれる HTML タグを取り除く |
is_singular( 'post' ) |
投稿ページだけに出力する(固定ページ・一覧には出さない) |
出力の確認(PHP 8.4 で動作確認)
WordPress 本体はこの環境では動かしていませんが、使っている WordPress 関数を同じ値を返す仮の関数(スタブ)に置き換え、PHP 8.4.21 で上のコードを実行して出力を確認しました。タイトルにはわざと </script><b>手順</b> を含めています。
$ php -l jsonld.php
No syntax errors detected in jsonld.php
$ php stub_test.php
<script type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":"BlogPosting","@id":"https://www.example.com/articles/inventory-basics/#article","headline":"在庫管理の始め方 手順","datePublished":"2026-10-01T09:00:00+09:00","dateModified":"2026-10-01T09:00:00+09:00","author":{"@type":"Person","name":"山田 花子","url":"https://www.example.com/author/hanako/"},"mainEntityOfPage":"https://www.example.com/articles/inventory-basics/","image":["https://www.example.com/images/inventory-16x9.png"]},{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"ホーム","item":"https://www.example.com/"},{"@type":"ListItem","position":2,"name":"在庫管理の始め方 手順"}]}]}</script>
この出力を先ほどの check_jsonld.py にかけた結果も [out.html#1] @graph: 必須OK でした。wp_strip_all_tags() でタグが取り除かれ、見出しは「在庫管理の始め方 手順」になっています。
プラグインとの重複に注意
| 状況 | 起きること | 対処 |
|---|---|---|
| SEO プラグインとテーマの両方で BlogPosting を出力 | 同じ記事の情報が2つ出力され、値が食い違うことがある | どちらか一方に任せる。プラグインの設定で該当スキーマをオフにするか、テーマ側を出力しない |
| テーマが独自にパンくず JSON-LD を出力している | BreadcrumbList が2つになる | テーマの設定・フックを確認して片方に |
| 全ページに Organization を出力 | 動作上は問題ないが重複して見える | トップページや会社概要ページだけに絞るか、@id で参照する形にする |
確認方法は、ブラウザでページのソースを表示し application/ld+json を検索することです。何件出力されているか、どの型が重複しているかがすぐ分かります。
よくある間違いと直し方
| 間違い | どうなるか | 直し方 |
|---|---|---|
| 末尾カンマ・シングルクォート | JSON の構文エラーで全体が読まれない | 最後の項目のカンマを外す。文字列は " で囲む |
日付が 2026/10/01 |
日付として解釈されない | 2026-10-01 または 2026-10-01T09:00:00+09:00 |
価格が "880円" |
数値として読めない | "price": 880, "priceCurrency": "JPY" |
| 画像やURLが相対パス | 画像やリンクを特定できない | https:// からの絶対URL |
| ページに表示していない評価や価格を書く | 構造化データのガイドラインに沿わない | 画面に表示している内容だけを書く |
@type の大文字小文字違い(blogposting) |
型として認識されない | schema.org の綴りどおり(BlogPosting) |
| JavaScript で後から挿入 | Google はレンダリング後に読めるが、処理が遅れることがある | 可能ならサーバー側で HTML に含める |
| 終了した FAQ・HowTo を追加し続ける | 表示されないため効果がない | Search Gallery にある型を優先 |
よくある質問
Q. JSON-LD と microdata、RDFa のどれを使えばよいですか?
A. Google は JSON-LD を推奨しています。 HTML の本文に属性を書き込む microdata・RDFa と違い、<script> に分けて書けるため、デザインの変更に影響されにくく管理しやすいのが利点です。
Q. 構造化データを入れれば必ずリッチリザルトが表示されますか? A. いいえ。必須プロパティを満たすと「表示の対象」になりますが、実際に表示するかは Google が判断します。 正しく書いたうえで、Search Console の拡張レポートでエラーがないことを確認します。
Q. FAQPage のマークアップは削除した方がよいですか? A. FAQ のリッチリザルトは2026年5月に表示を終了しましたが、マークアップが残っていることで不利になるとはされていません。急いで削除する必要はなく、テンプレートを作り直すときに整理するくらいで十分です。
Q. JSON-LD は head と body のどちらに書けばよいですか?
A. どちらでも読み取られます。 WordPress では wp_head に出力するのが一般的で、管理しやすい場所を選んでかまいません。
まとめ
- JSON-LD は
<script type="application/ld+json">に schema.org の語彙で書く、Google 推奨の形式 - リッチリザルトの対象は Search Gallery の型。FAQ(2026年5月)・HowTo・サイトリンク検索ボックスなどは表示を終了
- 型ごとの必須プロパティを押さえる(Event は name・startDate・location、VideoObject は name・thumbnailUrl・uploadDate など)
- 日付は ISO 8601、URL は絶対URL、価格は数値+通貨コード
- Python の自動チェックで、末尾カンマ・日付形式・価格・必須漏れを公開前に検出できた
- WordPress では
wp_json_encode()とJSON_HEX_TAGで安全に出力し、SEO プラグインとの重複を確認する - 最終確認はリッチリザルトテストと Search Consoleで行う
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「構造化データJSON-LDの書き方|型別コピペ例と検証手順」
株式会社RJCでは、構造化データとSEOの仕組みを仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。