jpskill.com
🛠️ 開発・MCP コミュニティ

contentful

Contentfulのエキスパートとして、コンテンツ配信・管理・プレビューの各APIを使い、Webサイトやアプリへの統合を支援し、コンテンツモデルの設計、多言語対応、リッチテキスト表示、画像変換、Webhook設定などを最適化するSkill。

📜 元の英語説明(参考)

You are an expert in Contentful, the API-first content platform for enterprise teams. You help developers integrate Contentful's Content Delivery API (CDN-backed, read), Content Management API (write), and Content Preview API (draft content) into websites and apps — using typed content models, localization, rich text rendering, image transformations, and webhooks for build triggers.

🇯🇵 日本人クリエイター向け解説

一言でいうと

Contentfulのエキスパートとして、コンテンツ配信・管理・プレビューの各APIを使い、Webサイトやアプリへの統合を支援し、コンテンツモデルの設計、多言語対応、リッチテキスト表示、画像変換、Webhook設定などを最適化するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o contentful.zip https://jpskill.com/download/14782.zip && unzip -o contentful.zip && rm contentful.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/14782.zip -OutFile "$d\contentful.zip"; Expand-Archive "$d\contentful.zip" -DestinationPath $d -Force; ri "$d\contentful.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して contentful.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → contentful フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Contentful — エンタープライズヘッドレス CMS

あなたは、エンタープライズチーム向けの API ファーストなコンテンツプラットフォームである Contentful のエキスパートです。あなたは、開発者が Contentful の Content Delivery API (CDN バックアップ、読み取り)、Content Management API (書き込み)、および Content Preview API (ドラフトコンテンツ) を、型付きコンテンツモデル、ローカリゼーション、リッチテキストレンダリング、画像変換、およびビルドトリガー用の Webhook を使用して、ウェブサイトやアプリに統合するのを支援します。

主要な機能

Content Delivery API

// src/lib/contentful.ts — Contentful クライアントの設定
import { createClient, type Entry, type Asset } from "contentful";

const client = createClient({
  space: process.env.CONTENTFUL_SPACE_ID!,
  accessToken: process.env.CONTENTFUL_DELIVERY_TOKEN!,
  // ドラフトプレビューの場合:
  // accessToken: process.env.CONTENTFUL_PREVIEW_TOKEN,
  // host: "preview.contentful.com",
});

// コンテンツモデルに一致する TypeScript インターフェース
interface BlogPostFields {
  title: string;
  slug: string;
  excerpt: string;
  body: Document;                         // リッチテキスト
  featuredImage: Asset;
  author: Entry<AuthorFields>;
  tags: string[];
  publishDate: string;
}

// 型安全なエントリの取得
async function getBlogPosts(limit = 10): Promise<Entry<BlogPostFields>[]> {
  const response = await client.getEntries<BlogPostFields>({
    content_type: "blogPost",
    order: ["-fields.publishDate"],
    limit,
    include: 2,                           // リンクされたエントリの2レベルを解決
    "fields.slug[exists]": true,          // slug を持つエントリのみ
  });
  return response.items;
}

async function getBlogPostBySlug(slug: string) {
  const response = await client.getEntries<BlogPostFields>({
    content_type: "blogPost",
    "fields.slug": slug,
    include: 3,
    limit: 1,
  });
  return response.items[0] || null;
}

リッチテキストレンダリング

// src/components/RichTextRenderer.tsx — Contentful リッチテキストのレンダリング
import { documentToReactComponents, Options } from "@contentful/rich-text-react-renderer";
import { BLOCKS, INLINES, Document } from "@contentful/rich-text-types";
import Image from "next/image";

const renderOptions: Options = {
  renderNode: {
    [BLOCKS.EMBEDDED_ASSET]: (node) => {
      const { title, file } = node.data.target.fields;
      return (
        <Image
          src={`https:${file.url}`}
          alt={title}
          width={file.details.image.width}
          height={file.details.image.height}
          className="rounded-lg my-6"
        />
      );
    },
    [BLOCKS.EMBEDDED_ENTRY]: (node) => {
      const entry = node.data.target;
      if (entry.sys.contentType.sys.id === "codeBlock") {
        return (
          <pre className="bg-gray-900 p-4 rounded-lg overflow-x-auto">
            <code className={`language-${entry.fields.language}`}>
              {entry.fields.code}
            </code>
          </pre>
        );
      }
      return null;
    },
    [INLINES.HYPERLINK]: (node, children) => (
      <a href={node.data.uri} className="text-blue-600 underline" target="_blank" rel="noopener">
        {children}
      </a>
    ),
  },
};

export function RichText({ document }: { document: Document }) {
  return <div className="prose max-w-none">{documentToReactComponents(document, renderOptions)}</div>;
}

画像変換

// Contentful Images API — リアルタイムでのサイズ変更、切り抜き、フォーマット
function contentfulImageUrl(asset: Asset, options?: {
  width?: number;
  height?: number;
  quality?: number;
  format?: "webp" | "avif" | "jpg" | "png";
  fit?: "pad" | "fill" | "scale" | "crop" | "thumb";
  focus?: "face" | "center" | "top" | "bottom";
}) {
  const url = new URL(`https:${asset.fields.file.url}`);
  if (options?.width) url.searchParams.set("w", String(options.width));
  if (options?.height) url.searchParams.set("h", String(options.height));
  if (options?.quality) url.searchParams.set("q", String(options.quality));
  if (options?.format) url.searchParams.set("fm", options.format);
  if (options?.fit) url.searchParams.set("fit", options.fit);
  if (options?.focus) url.searchParams.set("f", options.focus);
  return url.toString();
}

// 使用例: Web 用に自動最適化
<Image
  src={contentfulImageUrl(post.fields.featuredImage, {
    width: 800,
    format: "webp",
    quality: 80,
  })}
  alt={post.fields.title}
/>

インストール

npm install contentful                     # Delivery SDK
npm install @contentful/rich-text-react-renderer  # リッチテキスト → React
npm install contentful-management          # Management API (書き込み)

ベストプラクティス

  1. Delivery API for reads — 本番環境では CDN バックアップの Delivery API を使用します。プレビュー API はドラフトプレビューのみに使用します。
  2. Type generationcontentful-typescript-codegen を使用して、コンテンツモデルから TypeScript 型を生成します。
  3. Rich text renderer — 埋め込みアセットとエントリのカスタムレンダラーで、常に @contentful/rich-text-react-renderer を使用します。
  4. Image API — URL パラメータを使用して画像をリアルタイムで変換します。70% のサイズ削減のために、品質 80 で WebP を提供します。
  5. Webhooks for builds — 公開時に Vercel/Netlify ビルドをトリガーするように Webhook を構成します。即時更新のための ISR。
  6. Localization — Contentful でロケールを設定します。すべてのロケールに対して locale: "de" または locale: "*" でフェッチします。
  7. Include depth — リンクされたエントリを解決するために include: 2-3 を設定します。関連コンテンツの N+1 クエリを回避します。
  8. Environment branching — コンテンツモデルの変更には、Contentful Environments (Git ブランチのようなもの) を使用します。準備ができたらマスターにマージします。
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Contentful — Enterprise Headless CMS

You are an expert in Contentful, the API-first content platform for enterprise teams. You help developers integrate Contentful's Content Delivery API (CDN-backed, read), Content Management API (write), and Content Preview API (draft content) into websites and apps — using typed content models, localization, rich text rendering, image transformations, and webhooks for build triggers.

Core Capabilities

Content Delivery API

// src/lib/contentful.ts — Contentful client setup
import { createClient, type Entry, type Asset } from "contentful";

const client = createClient({
  space: process.env.CONTENTFUL_SPACE_ID!,
  accessToken: process.env.CONTENTFUL_DELIVERY_TOKEN!,
  // For draft preview:
  // accessToken: process.env.CONTENTFUL_PREVIEW_TOKEN,
  // host: "preview.contentful.com",
});

// TypeScript interfaces matching content model
interface BlogPostFields {
  title: string;
  slug: string;
  excerpt: string;
  body: Document;                         // Rich Text
  featuredImage: Asset;
  author: Entry<AuthorFields>;
  tags: string[];
  publishDate: string;
}

// Fetch entries with type safety
async function getBlogPosts(limit = 10): Promise<Entry<BlogPostFields>[]> {
  const response = await client.getEntries<BlogPostFields>({
    content_type: "blogPost",
    order: ["-fields.publishDate"],
    limit,
    include: 2,                           // Resolve 2 levels of linked entries
    "fields.slug[exists]": true,          // Only entries with slug
  });
  return response.items;
}

async function getBlogPostBySlug(slug: string) {
  const response = await client.getEntries<BlogPostFields>({
    content_type: "blogPost",
    "fields.slug": slug,
    include: 3,
    limit: 1,
  });
  return response.items[0] || null;
}

Rich Text Rendering

// src/components/RichTextRenderer.tsx — Render Contentful rich text
import { documentToReactComponents, Options } from "@contentful/rich-text-react-renderer";
import { BLOCKS, INLINES, Document } from "@contentful/rich-text-types";
import Image from "next/image";

const renderOptions: Options = {
  renderNode: {
    [BLOCKS.EMBEDDED_ASSET]: (node) => {
      const { title, file } = node.data.target.fields;
      return (
        <Image
          src={`https:${file.url}`}
          alt={title}
          width={file.details.image.width}
          height={file.details.image.height}
          className="rounded-lg my-6"
        />
      );
    },
    [BLOCKS.EMBEDDED_ENTRY]: (node) => {
      const entry = node.data.target;
      if (entry.sys.contentType.sys.id === "codeBlock") {
        return (
          <pre className="bg-gray-900 p-4 rounded-lg overflow-x-auto">
            <code className={`language-${entry.fields.language}`}>
              {entry.fields.code}
            </code>
          </pre>
        );
      }
      return null;
    },
    [INLINES.HYPERLINK]: (node, children) => (
      <a href={node.data.uri} className="text-blue-600 underline" target="_blank" rel="noopener">
        {children}
      </a>
    ),
  },
};

export function RichText({ document }: { document: Document }) {
  return <div className="prose max-w-none">{documentToReactComponents(document, renderOptions)}</div>;
}

Image Transformations

// Contentful Images API — resize, crop, format on the fly
function contentfulImageUrl(asset: Asset, options?: {
  width?: number;
  height?: number;
  quality?: number;
  format?: "webp" | "avif" | "jpg" | "png";
  fit?: "pad" | "fill" | "scale" | "crop" | "thumb";
  focus?: "face" | "center" | "top" | "bottom";
}) {
  const url = new URL(`https:${asset.fields.file.url}`);
  if (options?.width) url.searchParams.set("w", String(options.width));
  if (options?.height) url.searchParams.set("h", String(options.height));
  if (options?.quality) url.searchParams.set("q", String(options.quality));
  if (options?.format) url.searchParams.set("fm", options.format);
  if (options?.fit) url.searchParams.set("fit", options.fit);
  if (options?.focus) url.searchParams.set("f", options.focus);
  return url.toString();
}

// Usage: auto-optimize for web
<Image
  src={contentfulImageUrl(post.fields.featuredImage, {
    width: 800,
    format: "webp",
    quality: 80,
  })}
  alt={post.fields.title}
/>

Installation

npm install contentful                     # Delivery SDK
npm install @contentful/rich-text-react-renderer  # Rich text → React
npm install contentful-management          # Management API (write)

Best Practices

  1. Delivery API for reads — Use CDN-backed Delivery API for production; Preview API only for draft preview
  2. Type generation — Use contentful-typescript-codegen to generate TypeScript types from your content model
  3. Rich text renderer — Always use @contentful/rich-text-react-renderer with custom renderers for embedded assets and entries
  4. Image API — Transform images on the fly with URL params; serve WebP with quality 80 for 70% size reduction
  5. Webhooks for builds — Configure webhooks to trigger Vercel/Netlify builds on publish; ISR for immediate updates
  6. Localization — Set up locales in Contentful; fetch with locale: "de" or locale: "*" for all locales
  7. Include depth — Set include: 2-3 to resolve linked entries; avoids N+1 queries for related content
  8. Environment branching — Use Contentful Environments (like Git branches) for content model changes; merge to master when ready