Use Cases

Sanity CMS with Claude Code

Learn about sanity cms using Claude Code. Practical tips and code examples included.

Sanity CMS開発をClaude Codeで効率化する

Sanityはリアルタイムコラボレーションとカスタマイズ性の高いスタジオが特徴のヘッドレスCMSです。GROQという独自クエリ言語と、Reactベースの管理画面を自由にカスタマイズできる点が魅力です。Claude Codeを使えば、Sanityのスキーマ設計やGROQクエリも効率的に構築できます。

プロジェクトのセットアップ

> Sanityプロジェクトを作成して。
> Next.js App Routerと連携する構成で。
npm create sanity@latest -- --project-id=xxxxx --dataset=production

# Next.jsプロジェクトにSanityクライアントを追加
npm install next-sanity @sanity/image-url

スキーマ定義

> ブログ記事と著者のSanityスキーマを作って。
> リッチテキスト、画像、参照フィールドを含めて。
// sanity/schemas/post.ts
import { defineType, defineField } from 'sanity';

export const postType = defineType({
  name: 'post',
  title: 'Post',
  type: 'document',
  fields: [
    defineField({
      name: 'title',
      title: 'Title',
      type: 'string',
      validation: (rule) => rule.required().max(100),
    }),
    defineField({
      name: 'slug',
      title: 'Slug',
      type: 'slug',
      options: { source: 'title', maxLength: 96 },
      validation: (rule) => rule.required(),
    }),
    defineField({
      name: 'author',
      title: 'Author',
      type: 'reference',
      to: [{ type: 'author' }],
    }),
    defineField({
      name: 'mainImage',
      title: 'Main Image',
      type: 'image',
      options: { hotspot: true },
      fields: [
        defineField({
          name: 'alt',
          title: 'Alt Text',
          type: 'string',
        }),
      ],
    }),
    defineField({
      name: 'publishedAt',
      title: 'Published At',
      type: 'datetime',
    }),
    defineField({
      name: 'categories',
      title: 'Categories',
      type: 'array',
      of: [{ type: 'reference', to: [{ type: 'category' }] }],
    }),
    defineField({
      name: 'body',
      title: 'Body',
      type: 'blockContent',
    }),
  ],
  preview: {
    select: {
      title: 'title',
      author: 'author.name',
      media: 'mainImage',
    },
    prepare({ title, author, media }) {
      return { title, subtitle: author, media };
    },
  },
});

GROQクエリの設計

> ブログ記事一覧と詳細ページ用のGROQクエリを書いて。
> 著者情報とカテゴリも展開して取得して。
// src/lib/sanity/queries.ts
import { groq } from 'next-sanity';

// 記事一覧
export const postsQuery = groq`
  *[_type == "post" && defined(slug.current)] | order(publishedAt desc) {
    _id,
    title,
    "slug": slug.current,
    publishedAt,
    excerpt,
    mainImage {
      asset-> {
        _id,
        url,
        metadata { dimensions, lqip }
      },
      alt
    },
    author-> {
      name,
      "slug": slug.current,
      image { asset-> { url } }
    },
    categories[]-> {
      title,
      "slug": slug.current
    }
  }[0...$limit]
`;

// 個別記事
export const postBySlugQuery = groq`
  *[_type == "post" && slug.current == $slug][0] {
    _id,
    title,
    "slug": slug.current,
    publishedAt,
    body[] {
      ...,
      _type == "image" => {
        ...,
        asset-> { url, metadata { dimensions } }
      }
    },
    mainImage {
      asset-> { url, metadata { dimensions, lqip } },
      alt
    },
    author-> {
      name,
      bio,
      image { asset-> { url } }
    },
    categories[]-> {
      title,
      "slug": slug.current
    },
    "relatedPosts": *[
      _type == "post" &&
      slug.current != $slug &&
      count(categories[@._ref in ^.^.categories[]._ref]) > 0
    ] | order(publishedAt desc) [0...3] {
      title,
      "slug": slug.current,
      publishedAt,
      mainImage { asset-> { url } }
    }
  }
`;

Next.jsでのデータ取得

// src/lib/sanity/client.ts
import { createClient } from 'next-sanity';

export const client = createClient({
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!,
  dataset: process.env.NEXT_PUBLIC_SANITY_DATASET!,
  apiVersion: '2024-01-01',
  useCdn: process.env.NODE_ENV === 'production',
});

// app/blog/page.tsx
import { client } from '@/lib/sanity/client';
import { postsQuery } from '@/lib/sanity/queries';

export default async function BlogPage() {
  const posts = await client.fetch(postsQuery, { limit: 20 });

  return (
    <div className="max-w-4xl mx-auto p-6">
      <h1 className="text-3xl font-bold mb-8">ブログ</h1>
      {posts.map((post: any) => (
        <article key={post._id} className="mb-8 border-b pb-6">
          <h2 className="text-xl font-bold">{post.title}</h2>
          <p className="text-gray-500 text-sm">{post.author?.name}</p>
        </article>
      ))}
    </div>
  );
}

Zusammenfassung

SanityのGROQクエリとカスタマイズ可能なスタジオは、柔軟なコンテンツ管理を実現します。Claude Codeを活用すれば、スキーマ設計やGROQの記述も効率的に進められます。ブログCMS構築ガイドNext.jsフルスタック開発も参考にしてください。

Sanityの詳細はSanity公式ドキュメントを参照してください。

#Claude Code #Sanity #CMS #ヘッドレスCMS #GROQ