Use Cases (更新: 2026/6/2)

Claude CodeでSanity CMSを本番運用する設計ガイド

Sanity CMSをClaude Codeで実装し、記事運用、商品LP、多言語CMSを収益化につなげる実践ガイド。

Claude CodeでSanity CMSを本番運用する設計ガイド

Sanity CMSとは何か

Sanity CMSは、記事、商品ページ、FAQ、著者プロフィール、キャンペーン文言などを構造化して管理するヘッドレスCMSです。ヘッドレスCMSとは、管理画面と表示画面を分け、Webサイト、アプリ、ニュースレター、社内ツールなど複数の出力先へ同じコンテンツを配信できるCMSのことです。Sanityではコンテンツの型をTypeScriptに近いスキーマで定義し、GROQというクエリ言語で必要なデータだけを取り出します。

CMSを「記事を置く場所」とだけ見ると、収益化にはつながりにくくなります。CMS/content opsの読者にとって重要なのは、検索流入、リード獲得、商品導線、更新作業、監査ログを同じ運用フローに乗せられるかです。Sanity CMSはスキーマを細かく設計できるため、Claude Codeで「記事の型」「CTAの型」「レビュー項目」「公開条件」をコードとして扱いやすいのが強みです。

2026年に本番導入するなら、最初に決めるべきことはCMSの画面ではなく、収益に関係するコンテンツ単位です。たとえば、ブログ記事には検索キーワード、想定読者、内部リンク、CTA、検証メモを持たせます。商品LPには価格、対象者、比較表、購入ボタン、FAQを持たせます。トレーニングや導入相談のページには、問い合わせ前に読んでほしい記事、必要な前提知識、担当者が確認する質問を持たせます。

Sanityの型定義は公式のSchema Typesで確認できます。GROQの構文は公式のGROQ syntaxを見ながら、Claude Codeに「この一覧画面で必要なフィールドだけ返すクエリを書いて」と依頼すると実装が速くなります。ただし、Claude Codeに丸投げするのではなく、公開条件、slugの一意性、draft除外、画像alt、CTAの有無を人間がレビューするのが本番運用の前提です。

2026年の本番アーキテクチャ

Sanity CMSを収益化サイトで使うときは、編集画面、Content Lake、フロントエンド、分析、販売導線を分けて考えます。下の表は小さなメディア、教材販売サイト、B2Bのコンテンツマーケティングで使いやすい最小構成です。

レイヤー役割本番で見る指標Claude Codeに任せる作業
Sanity Studio編集者が記事、商品、CTAを入力する管理画面下書き滞留数、必須項目の未入力、レビュー戻し数schemaTypes、プレビュー設定、入力バリデーションの作成
Content Lake公開済みコンテンツをAPIで保持する場所クエリ速度、不要フィールド量、dataset分離GROQクエリ、draft除外、locale別取得の実装
Next.js/AstroSEOページ、LP、一覧、詳細を表示する層Core Web Vitals、インデックス数、CVRfetch関数、型、一覧UI、内部リンク生成
Analytics/CRM検索流入から問い合わせまでを見る層CTAクリック、資料請求、購入、相談予約イベント名、計測仕様、レビュー用チェックリスト
MonetizationGumroad、Stripe、相談フォーム、メール導線売上、無料PDF登録、商談化率CTA文言案、比較表、FAQ、導線テスト案

この構成なら、CMSを変更してもフロントエンド全体を壊しにくくなります。記事の本文だけではなく、CTAや関連リンクも構造化しておくと、後から「API開発の記事を読んだ人には導入相談を出す」「Contentful比較記事からSanity移行相談へ送る」といった導線を作れます。

内部リンクも最初から設計に入れます。SanityをブログCMSとして使う全体像はClaude CodeブログCMS構築、Contentfulとの比較や移行視点はClaude Code Contentful CMS、CMSからAPIを切り出す考え方はClaude Code API開発を合わせて確認してください。チーム導入やコンテンツ運用の相談導線は導入相談に集約します。

実際に効くユースケース

1つ目のユースケースは、多言語SEOメディアです。日本語で作った記事を英語、中国語、韓国語、スペイン語などに展開するとき、本文だけを翻訳しても成果は出ません。Sanity側でlocalecanonicalSlugtargetKeywordsearchIntentlocalizedCtaを分けておくと、各言語で検索意図とCTAを調整できます。Claude Codeには、既存記事から不足している内部リンク、長すぎるdescription、CTA欠落を検出するチェックを作らせます。

2つ目のユースケースは、教材やテンプレート販売のLP運用です。記事の末尾に毎回同じ購入リンクを貼るだけでは、読者の温度感に合いません。SanityにofferTypepriceNoteproofPointaudiencenextActionを持つCTAドキュメントを作ると、「初心者には無料PDF」「実装者にはテンプレート」「チームリードには導入相談」という出し分けができます。Claude CodeはCTAの表示コンポーネント、GROQクエリ、イベント計測の雛形をまとめて生成できます。

3つ目のユースケースは、CMS移行とコンテンツ監査です。Notion、Markdown、Contentful、WordPressからSanityへ移すとき、単純な移行だけでは価値が薄いです。移行のタイミングで、古い記事、重複記事、収益導線のない記事、公式リンクが古い記事を分類します。SanityのスキーマにcontentScorelastReviewedAtreviewOwnermonetizationStatusを持たせれば、公開後の改善タスクが見えるようになります。

4つ目のユースケースは、営業資料と公開記事の共通化です。B2Bでは、営業チームが使う説明と公開サイトの記事がずれやすいです。Sanityに「機能説明」「導入事例」「FAQ」「反論処理」を構造化しておくと、公開ページ、提案資料、メールテンプレートで同じ原稿を参照できます。Claude Codeは、Sanityから取得したデータをLP、社内ダッシュボード、APIレスポンスへ分けて出すコードを生成できます。

コピペで始めるスキーマ

以下はSanity v3系のschemaTypes/post.tsとして使える最小の投稿スキーマです。本文、slug、言語、CTA、検証メモ、公開レビュー状態を持たせています。bodyはPortable Textのブロック配列として扱い、画像にはaltテキストを必須にします。

// schemaTypes/post.ts
import {defineField, defineType} from 'sanity'

export const post = defineType({
  name: 'post',
  title: 'Post',
  type: 'document',
  fields: [
    defineField({
      name: 'title',
      title: 'Title',
      type: 'string',
      validation: (rule) => rule.required().max(90),
    }),
    defineField({
      name: 'slug',
      title: 'Slug',
      type: 'slug',
      options: {source: 'title', maxLength: 96},
      validation: (rule) => rule.required(),
    }),
    defineField({
      name: 'locale',
      title: 'Locale',
      type: 'string',
      options: {
        list: [
          {title: 'Japanese', value: 'ja'},
          {title: 'English', value: 'en'},
          {title: 'Chinese', value: 'zh'},
        ],
      },
      validation: (rule) => rule.required(),
    }),
    defineField({
      name: 'description',
      title: 'SEO description',
      type: 'text',
      rows: 3,
      validation: (rule) => rule.required().max(120),
    }),
    defineField({
      name: 'heroImage',
      title: 'Hero image',
      type: 'image',
      options: {hotspot: true},
      fields: [
        defineField({
          name: 'alt',
          title: 'Alt text',
          type: 'string',
          validation: (rule) => rule.required(),
        }),
      ],
      validation: (rule) => rule.required(),
    }),
    defineField({
      name: 'body',
      title: 'Body',
      type: 'array',
      of: [{type: 'block'}, {type: 'image'}],
      validation: (rule) => rule.required(),
    }),
    defineField({
      name: 'cta',
      title: 'Monetization CTA',
      type: 'object',
      fields: [
        defineField({name: 'label', title: 'Label', type: 'string'}),
        defineField({name: 'href', title: 'URL', type: 'url'}),
        defineField({name: 'intent', title: 'Intent', type: 'string'}),
      ],
    }),
    defineField({
      name: 'verificationNote',
      title: 'Verification note',
      type: 'text',
      rows: 4,
    }),
    defineField({
      name: 'publishedAt',
      title: 'Published at',
      type: 'datetime',
      validation: (rule) => rule.required(),
    }),
  ],
  preview: {
    select: {title: 'title', subtitle: 'locale', media: 'heroImage'},
  },
})

schemaTypes/index.tsでは、上のスキーマを必ず配列へ登録します。ここを忘れるとStudioに型が出ません。

// schemaTypes/index.ts
import {post} from './post'

export const schemaTypes = [post]

GROQとクライアント取得

GROQでは一覧用と詳細用を分けます。一覧では本文を返さず、カード表示に必要なtitle、slug、description、画像、CTAだけを返します。詳細では本文、検証メモ、関連リンクを返します。クエリを小さくするほど、フロントエンドの実装とキャッシュ戦略が読みやすくなります。

// src/lib/sanity/queries.ts
export const postsByLocaleQuery = `
  *[
    _type == "post" &&
    locale == $locale &&
    defined(slug.current) &&
    defined(publishedAt)
  ] | order(publishedAt desc) [0...$limit] {
    _id,
    title,
    description,
    "slug": slug.current,
    publishedAt,
    "heroImageUrl": heroImage.asset->url,
    "heroImageAlt": heroImage.alt,
    cta
  }
`

export const postBySlugQuery = `
  *[
    _type == "post" &&
    locale == $locale &&
    slug.current == $slug
  ][0] {
    _id,
    title,
    description,
    "slug": slug.current,
    publishedAt,
    body,
    verificationNote,
    cta,
    "heroImageUrl": heroImage.asset->url,
    "heroImageAlt": heroImage.alt
  }
`
// src/lib/sanity/client.ts
import {createClient} from '@sanity/client'
import {postBySlugQuery, postsByLocaleQuery} from './queries'

export const sanityClient = createClient({
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID || '',
  dataset: process.env.NEXT_PUBLIC_SANITY_DATASET || 'production',
  apiVersion: '2026-06-02',
  useCdn: process.env.NODE_ENV === 'production',
})

export async function getPosts(locale: string, limit = 12) {
  return sanityClient.fetch(postsByLocaleQuery, {locale, limit})
}

export async function getPostBySlug(locale: string, slug: string) {
  return sanityClient.fetch(postBySlugQuery, {locale, slug})
}

ローカルで動かす前に、依存関係と環境変数をそろえます。Sanity Studio側ではsanity、フロントエンド側では@sanity/clientを使います。Next.jsで画像URLを最適化する場合は@sanity/image-urlも入れます。

npm install sanity @sanity/client @sanity/image-url
set NEXT_PUBLIC_SANITY_PROJECT_ID=your_project_id
set NEXT_PUBLIC_SANITY_DATASET=production

失敗例と落とし穴

一番多い失敗は、スキーマを「今の記事に必要な項目」だけで作ることです。最初は速く見えますが、後から多言語化、CTA差し替え、レビュー日、著者プロフィール、商品リンクを足すたびに移行作業が発生します。最初から完璧にする必要はありませんが、収益に関係する項目は本文から分離しておくべきです。

2つ目の失敗は、GROQで本文や画像メタデータを一覧に返しすぎることです。一覧ページで本文全文を取得すると、ビルド時間、転送量、キャッシュの扱いが悪化します。一覧、詳細、関連記事、サイトマップでクエリを分け、必要なフィールドだけ返すようにします。

3つ目の失敗は、draftや未レビュー記事を公開側に混ぜることです。publishedAtがあるだけでは不十分な場合があります。公開レビュー状態をreviewStatusとして持たせる、または公開用datasetと下書き用datasetを分ける設計を検討します。Claude Codeには「draft混入を検出するテスト」や「publishedAtが未来日の記事を除外するクエリ」を作らせると安全です。

4つ目の失敗は、CMSを導入したのに収益導線が固定バナーだけになることです。記事ごとの読者意図に合わないCTAはクリックされません。API実装の記事なら実装レビュー、CMS比較の記事なら移行相談、初心者向け記事なら無料PDF、運用者向け記事ならトレーニングというように、CTAをコンテンツ型として管理します。

ロールアウトチェックリスト

  • 本番前にtitledescriptionslugheroImage.altpublishedAtを必須にする。
  • 記事、商品LP、FAQ、CTAを別ドキュメントに分け、本文へ直書きしすぎない。
  • 一覧用GROQと詳細用GROQを分け、一覧では本文を取得しない。
  • 多言語ではlocalecanonicalSlugを持たせ、翻訳漏れとcanonical重複を確認する。
  • 公式リンク、内部リンク、CTA、検証メモの有無を公開前チェックに入れる。
  • GA4、Search Console、販売ページ、問い合わせフォームのイベント名を統一する。
  • 公開後30日で検索流入、CTAクリック、問い合わせ、購入を確認し、Sanity側に改善メモを残す。

検証メモと収益化CTA

検証メモとして、この記事のスキーマ、GROQ、@sanity/clientの取得関数は、Sanity v3の通常構成で破綻しない形に絞りました。実際の案件では、ここにreviewStatuscanonicalSlugauthorrelatedOfferを足すことが多いです。最初から複雑なワークフローを作るより、記事、CTA、検証メモを分離し、30日ごとに収益指標で改善するほうが運用が続きます。

ClaudeCodeLabでは、Sanity CMS、Contentful、Markdownブログ、API連携を含むコンテンツ運用を、収益導線まで含めて整理します。自社メディア、教材販売、導入相談ページのCMS設計を固めたい場合は、導入相談で既存のリポジトリ、記事一覧、商品導線を前提にしたレビューを依頼してください。無料記事だけで終わらせず、読者が次に買う、問い合わせる、学ぶ導線まで設計するのがCMS本番化の目的です。

#Claude Code #Sanity CMS #Headless CMS #GROQ #Content Ops
無料

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。

Masa

この記事を書いた人

Masa

Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。