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

Claude CodeでブログCMSを作る: Astro MDXで収益につながる記事運用を自動化する

Astro MDXとClaude Codeで、SEO・多言語・QA・CTAまで回るブログCMSを作る実践ガイド。

Claude CodeでブログCMSを作る: Astro MDXで収益につながる記事運用を自動化する

ブログCMSは「記事を書く場所」ではなく、収益まで運ぶ仕組み

ブログを毎日更新しているのに、問い合わせも教材販売も増えない。 その原因は、記事本文ではなく「公開前の運用」が弱いことが多いです。 Claude Codeを使うなら、単なるMarkdown生成ではなく、CMS、翻訳、SEO、QA、CTAまでを一つの流れとして設計します。

ここでいうCMSは、WordPressのような管理画面だけを指しません。CMSはContent Management System、つまり「記事データを決まった形で保管し、編集、確認、公開する仕組み」です。AstroのContent CollectionsとMDXを使えば、ファイルベースでも十分に強いブログCMSを作れます。Claude Codeは、その仕組みの実装、レビュー、翻訳、公開前チェックを手伝うエージェントとして使います。

この記事では、ClaudeCodeLabのような多言語ブログを前提に、次の運用を作ります。

  • MDXとfrontmatterで記事を構造化する
  • Astroのスキーマで壊れた記事をビルド前に止める
  • 10言語の翻訳を同じslugで管理する
  • description、OGP、RSS、sitemapを公開フローに含める
  • 記事から教材、研修、個別相談につなげるCTAを設計する
  • Claude Codeに任せる範囲と、人間が確認する範囲を分ける

関連する設計は、Claude CodeとContentful CMSの連携Claude Codeでコンテンツファネルを監査するも参考になります。RSSやサイトマップを深掘りするなら、Claude CodeでRSSフィードを実装するClaude Codeでサイトマップを生成するを合わせて読むと全体像がつかみやすいです。

公式ドキュメントは必ず参照してください。AstroのContent Collectionsは記事データの型管理、MDX integrationはMarkdown内でコンポーネントを使うための仕組み、Sitemap integrationは検索エンジンに公開URLを伝えるための基礎です。

まずCMSの責務を分ける

Claude Codeに「ブログCMSを作って」と頼むだけだと、記事エディタ、DB、API、認証、プレビュー画面が混ざった大きな実装になりがちです。ファイルベースのAstroブログでは、責務を小さく分けるほうが壊れにくいです。

領域役割Claude Codeに任せる作業
content schemafrontmatterの必須項目と型を決めるcontent.config.tsの実装、型エラーの修正
MDX記事本文、コード、表、CTAを管理する下書き作成、翻訳、構成改善
localization同じslugを10言語でそろえる欠落言語の検出、自然な翻訳
preview公開前に表示崩れを確認するdev server起動、リンク確認、スクリーンショット確認
SEOtitle、description、canonical、sitemapを整えるメタデータ監査、短すぎる説明文の修正
QA gate公開前の落とし穴を止めるNodeスクリプト、ビルド、チェックリスト実行
monetization記事から商品や相談へ導くCTA配置、導線レビュー、成果メモの追加

大切なのは、Claude Codeを「文章を書くAI」ではなく「編集部の作業者」として扱うことです。依頼内容には、触ってよいファイル、触ってはいけないファイル、品質基準、実行するチェックを明記します。

実例1: 個人開発ブログを教材販売につなげる

個人開発者のブログでは、記事のゴールが「読まれること」だけだと収益化しにくいです。たとえば、Claude Codeの使い方記事を書くなら、記事末尾でテンプレート集、動画講座、個別相談のどれかに自然につなげます。

この場合、CMSに必要な項目は本文だけではありません。

  • ctaLabel: ボタンに出す短い文言
  • ctaUrl: 商品、研修、相談ページのURL
  • relatedPosts: 関連記事のslug
  • updatedDate: 最新性を示す日付
  • heroImage: 一覧とOGPで使う画像

記事本文のCTAは毎回手で考えるとぶれます。CMS側にCTA項目を持たせると、「この記事は無料PDF向け」「この記事は研修問い合わせ向け」のように編集できます。

実例2: 企業の技術ブログでレビュー漏れを防ぐ

企業ブログでは、公開前の失敗がそのまま信用低下になります。よくある事故は、未確認のコード、古いAPI名、間違った料金説明、翻訳だけ古いまま残ることです。

Claude Codeには、記事の生成よりもレビューゲートを任せると効果が出ます。たとえば、以下を公開前に止めます。

  • descriptionが120文字を超えている
  • updatedDateがない
  • 日本語だけ更新され、英語や韓国語が古い
  • 公式ドキュメントへの外部リンクがない
  • 内部リンクが1本もない
  • CTAがない
  • コードブロックが疑似コードのまま

この仕組みを入れると、編集者は「公開できるか」を感覚ではなくチェック結果で判断できます。

実例3: 多言語SEOで同じslugを運用する

10言語の記事を管理するとき、最も壊れやすいのはslugの不一致です。日本語のclaude-code-blog-cms.mdxだけ更新して、英語や中国語の同名ファイルが古いままだと、読者体験も検索評価も落ちます。

ファイル構成は次のようにそろえます。

site/src/content/blog/claude-code-blog-cms.mdx
site/src/content/blog-en/claude-code-blog-cms.mdx
site/src/content/blog-zh/claude-code-blog-cms.mdx
site/src/content/blog-ko/claude-code-blog-cms.mdx
site/src/content/blog-es/claude-code-blog-cms.mdx
site/src/content/blog-fr/claude-code-blog-cms.mdx
site/src/content/blog-de/claude-code-blog-cms.mdx
site/src/content/blog-pt/claude-code-blog-cms.mdx
site/src/content/blog-hi/claude-code-blog-cms.mdx
site/src/content/blog-id/claude-code-blog-cms.mdx

言語ごとにタイトルは自然に変えてよいですが、slug、記事の主張、コード例、CTAの意図はそろえます。翻訳は「直訳」ではなく、各言語の読者が検索しそうな語彙に寄せます。たとえば英語では”content operations”、スペイン語では”operaciones de contenido”、インドネシア語では”operasi konten”のように言い換えます。

Astroのcontent schemaを作る

AstroのContent Collectionsは、記事frontmatterを型で守る仕組みです。型とは「このデータは文字列、この項目は日付、この値は決まった候補だけ」という約束です。これを入れると、公開前に壊れた記事を止められます。

次のコードはAstro 5系のsrc/content.config.tsとしてそのまま使える形です。プロジェクトの実際のカテゴリや言語に合わせて調整してください。

// src/content.config.ts
import { defineCollection, z } from "astro:content";
import { glob } from "astro/loaders";

const blogSchema = z.object({
  title: z.string().min(20).max(80),
  description: z.string().min(40).max(120),
  pubDate: z.coerce.date(),
  updatedDate: z.coerce.date(),
  category: z.enum([
    "getting-started",
    "tips-and-tricks",
    "use-cases",
    "comparison",
    "advanced",
  ]),
  tags: z.array(z.string()).min(2).max(8),
  heroImage: z.string().startsWith("/images/"),
  draft: z.boolean().default(false),
  requireAllLocales: z.boolean().default(false),
  lang: z.enum(["ja", "en", "zh", "ko", "es", "fr", "de", "pt", "hi", "id"]),
  ctaLabel: z.string().max(40).optional(),
  ctaUrl: z.string().url().optional(),
});

const makeBlogCollection = (base: string) =>
  defineCollection({
    loader: glob({ pattern: "**/*.{md,mdx}", base }),
    schema: blogSchema,
  });

export const collections = {
  blog: makeBlogCollection("./src/content/blog"),
  "blog-en": makeBlogCollection("./src/content/blog-en"),
  "blog-zh": makeBlogCollection("./src/content/blog-zh"),
  "blog-ko": makeBlogCollection("./src/content/blog-ko"),
  "blog-es": makeBlogCollection("./src/content/blog-es"),
  "blog-fr": makeBlogCollection("./src/content/blog-fr"),
  "blog-de": makeBlogCollection("./src/content/blog-de"),
  "blog-pt": makeBlogCollection("./src/content/blog-pt"),
  "blog-hi": makeBlogCollection("./src/content/blog-hi"),
  "blog-id": makeBlogCollection("./src/content/blog-id"),
};

descriptionを120文字以内にする理由は、検索結果やSNSカードで途中切れしにくくするためです。短すぎると魅力が伝わらず、長すぎると重要な語句が見えません。

MDX frontmatterを商品導線まで含めて書く

MDXはMarkdownにコンポーネントを混ぜられる形式です。難しく考える必要はありません。本文はMarkdownとして書き、必要なところだけCTAや比較表などの部品を使える、と理解すれば十分です。

frontmatterは記事の名札です。title、description、日付、カテゴリ、タグ、画像、言語を必ず入れます。収益化まで考えるなら、CTAのラベルとURLも入れておくと運用が楽になります。

---
title: "Claude CodeでブログCMSを作る: Astro MDXで収益につながる記事運用を自動化する"
description: "Astro MDXとClaude Codeで、SEO・多言語・QA・CTAまで回るブログCMSを作る実践ガイド。"
pubDate: "2025-12-22"
updatedDate: "2026-06-02"
category: "use-cases"
tags: ["Claude Code", "CMS", "ブログ運用", "Astro", "MDX"]
heroImage: "/images/hero/hero-036.png"
lang: "ja"
ctaLabel: "Claude Code運用相談を予約する"
ctaUrl: "https://example.com/consulting"
---

## 最初の見出し

この記事では、Claude Codeを使って記事制作、翻訳、SEO、公開前チェックをつなぐCMSを作ります。

注意点は、frontmatterに本文の結論を書きすぎないことです。descriptionは検索結果で読者を誘導する短い説明、本文の導入は「なぜ今読むべきか」を伝える場所です。

公開前バリデーションをNodeで作る

次のスクリプトは依存パッケージなしで動きます。scripts/validate-blog-cms.mjsとして保存し、node scripts/validate-blog-cms.mjs claude-code-blog-cmsのように実行します。frontmatterの最低限の品質、10言語の存在、内部リンク、公式リンク、CTA、コードブロックを確認します。

// scripts/validate-blog-cms.mjs
import fs from "node:fs";
import path from "node:path";

const slug = process.argv[2];
if (!slug) {
  console.error("Usage: node scripts/validate-blog-cms.mjs <slug>");
  process.exit(1);
}

const locales = [
  ["blog", "ja"],
  ["blog-en", "en"],
  ["blog-zh", "zh"],
  ["blog-ko", "ko"],
  ["blog-es", "es"],
  ["blog-fr", "fr"],
  ["blog-de", "de"],
  ["blog-pt", "pt"],
  ["blog-hi", "hi"],
  ["blog-id", "id"],
];

const root = path.join(process.cwd(), "src", "content");
const failures = [];

function readFrontmatter(source) {
  const match = source.match(/^---\n([\s\S]*?)\n---/);
  if (!match) return {};
  return Object.fromEntries(
    match[1].split("\n").flatMap((line) => {
      const index = line.indexOf(":");
      if (index === -1) return [];
      const key = line.slice(0, index).trim();
      const value = line.slice(index + 1).trim().replace(/^"|"$/g, "");
      return [[key, value]];
    })
  );
}

for (const [dir, lang] of locales) {
  const file = path.join(root, dir, `${slug}.mdx`);
  if (!fs.existsSync(file)) {
    failures.push(`${dir}: missing ${slug}.mdx`);
    continue;
  }

  const source = fs.readFileSync(file, "utf8");
  const data = readFrontmatter(source);
  const body = source.replace(/^---\n[\s\S]*?\n---/, "");

  if (data.lang !== lang) failures.push(`${dir}: lang should be ${lang}`);
  if (!data.updatedDate) failures.push(`${dir}: updatedDate is required`);
  if ((data.description || "").length > 120) {
    failures.push(`${dir}: description is over 120 characters`);
  }
  if (!/heroImage:\s*"\//.test(source)) failures.push(`${dir}: heroImage is missing`);
  if (!/https:\/\/docs\.astro\.build/.test(source)) {
    failures.push(`${dir}: official Astro docs link is missing`);
  }
  if (!/\]\(\/blog\/claude-code-/.test(source)) {
    failures.push(`${dir}: internal ClaudeCodeLab link is missing`);
  }
  if (!/(CTA|相談|consult|training|formation|Beratung|consultoria|konsultasi)/i.test(source)) {
    failures.push(`${dir}: monetization CTA is missing`);
  }
  if ((body.match(/`{3}/g) || []).length < 6) {
    failures.push(`${dir}: expected at least three code blocks`);
  }
}

if (failures.length) {
  console.error(failures.map((item) => `- ${item}`).join("\n"));
  process.exit(1);
}

console.log(`OK: ${slug} passed localized CMS checks.`);

完璧なYAMLパーサーではありませんが、公開前の軽いゲートとしては十分です。本格運用ではgray-matterやAstroのビルドチェックに寄せると、配列や複雑な値も安全に扱えます。

Claude Codeに渡す公開前チェックリスト

Claude Codeへの依頼は、成果物と禁止事項を明確にすると失敗が減ります。次のプロンプトは、そのまま下書きから公開前レビューまで使えます。

Rewrite the article for slug <slug> as a production-ready Astro MDX blog post.

Scope:
- Edit only the localized files for this slug.
- Preserve heroImage, category, and useful tags.
- Add updatedDate: "2026-06-02".

Quality gate:
- Description must be 120 characters or less.
- Explain technical terms in plain language on first use.
- Include at least 3 real use cases.
- Include concrete pitfalls and failure modes.
- Include runnable code blocks, not pseudocode.
- Add official Astro docs links and internal ClaudeCodeLab links.
- Add a training, product, or consultation CTA.
- Add a short hands-on verification note at the end.

After editing:
- Run focused checks if feasible.
- Report changed files, commands, results, and unresolved issues.

このプロンプトのポイントは、「良い記事にして」ではなく、検査可能な条件に分解していることです。Claude Codeは曖昧な品質より、ファイル、日付、文字数、リンク、コード、チェックコマンドのような具体条件に強いです。

RSS、sitemap、OGPをCMSの外に置かない

記事CMSで忘れがちなのが配信面です。記事ファイルが正しくても、RSSに出ない、sitemapに載らない、OGP画像が空、descriptionが古い、という状態では公開の価値が落ちます。

Astroではsitemap統合を入れると静的ルートをクロールしてsitemapを作れます。動的ルートを使う場合はgetStaticPaths()で全言語のパスを生成することが重要です。RSSはgetCollection()で記事を取得し、draftを除外して新しい順に並べます。

CMS設計では次の4つを同じ公開チェックに入れてください。

  • 一覧ページに出るタイトルとdescription
  • OGPカードで使うheroImage
  • RSSに含める最新20件
  • sitemapに含める全公開URL

この4つがそろうと、記事公開が「ファイルを置いた」ではなく「読者に届く状態になった」と言えます。

具体的な落とし穴

1つ目の落とし穴は、frontmatterだけ翻訳して本文が古いまま残ることです。多言語記事では、見出しとCTAだけ新しく見えても、コードが古いと読者はすぐ離脱します。

2つ目は、Claude Codeに広すぎる権限を渡すことです。「関連する記事も直して」と頼むと、別slugやレポートまで触る可能性があります。並行作業中は、書き込み範囲をファイル単位で指定します。

3つ目は、コード例が動かないことです。ブログ用のコードは短くても、実際にコピーして動くことが重要です。疑似コードなら疑似コードと明記し、実装コードとは分けます。

4つ目は、CTAが売り込みだけになることです。読者がまだ基礎を理解していない段階で「問い合わせはこちら」だけを置いても反応は弱いです。無料チェックリスト、テンプレート、教材、研修、相談の順に段階を作ります。

5つ目は、updatedDateを機械的に変えることです。日付は読者への約束です。API名、公式リンク、コード、スクリーンショット、料金や仕様の説明を確認したうえで更新します。

収益化CTAを記事設計に組み込む

Claude CodeのブログCMSで目指すべき導線は、PVから直接売上ではありません。おすすめは、記事ごとに次のどれかを選ぶことです。

記事タイプCTA目的
入門記事無料チェックリスト、メール講座読者との接点を作る
実装記事テンプレート、サンプルコード集小さな商品購入につなげる
比較記事導入相談、研修問い合わせ高単価の相談につなげる
失敗談記事監査サービス、レビュー依頼課題を持つ読者を拾う

この記事のテーマなら、CTAは「Claude Codeで記事運用CMSを整えたい方向けに、スキーマ設計、翻訳フロー、公開前QA、教材・相談導線までレビューします」が自然です。単発の執筆代行ではなく、運用の仕組みを売るほうが継続収益につながります。

まとめ

Claude CodeでブログCMSを作る価値は、記事を速く増やすことではありません。価値が出るのは、記事データをスキーマで守り、多言語を同じslugでそろえ、SEOメタデータを確認し、RSSとsitemapで配信し、最後に商品、研修、相談へつなげる流れを作ったときです。

ファイルベースのAstro MDX CMSは、小さく始められて、壊れた記事をビルド前に止めやすい構成です。Claude Codeには、下書き生成だけでなく、翻訳差分の確認、コードブロックの検査、公開前レビュー、CTA改善まで任せると効果が出ます。

ClaudeCodeLabでは、Claude Codeを使ったブログ運用、教材化、研修用ハンズオン、記事から相談につなげる導線設計を扱っています。社内ブログや個人メディアを「更新して終わり」から「検証して収益につなげる」運用に変えたい場合は、記事CMSのスキーマとQAゲートから整えるのが近道です。

実際に試した結果

この記事の内容に沿って、Astroのcontent schema、MDX frontmatter、Nodeの公開前チェックを小さな検証環境で動かしました。descriptionの文字数超過、updatedDate漏れ、公式リンク漏れ、CTA漏れはスクリプトで検出でき、ビルド前に修正できました。一方で、翻訳の自然さやCTAの説得力は自動チェックだけでは判断しきれないため、最後は人間が読み、収益導線と読者体験を確認する必要があります。

#Claude Code #CMS #ブログ運用 #Astro #MDX
無料

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

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

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

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

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

Masa

この記事を書いた人

Masa

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

PR

関連書籍・参考図書

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

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