Sanity へのマイグレーション完全ガイド:WordPress、Contentful、Drupal からの移行

ここ3年間で、40程度のプロジェクトを Sanity に移行させてきました。クリーンな2週間のスプリントで終わったものもあれば、3ヶ月に及ぶ悪戦苦闘で、キャリアの選択を後悔させるようなものもありました。その差は、ソース CMS にはほぼ関係なく、準備、コンテンツモデリングの決定、そして実際に何をしようとしているのかについての誠実さに左右されます。

これは、CMS マイグレーションを始めた時に欲しかったガイドです。WordPress、Contentful、Drupal から Sanity の GROQ パワードワールドへの移行をカバーしています。Sanity が輝く場所、イライラさせられる場所、そして現実的なタイムラインがどのようなものであるかについて、ぶっきらぼうに説明します。

目次

Sanity マイグレーション完全ガイド:WordPress、Contentful、Drupal からの移行

2025年、チームが Sanity に移行する理由

まず明白なことを片付けましょう。Sanity のリアルタイム協調編集、カスタマイズ可能な Studio、構造化コンテンツアプローチは本当に優れています。しかし、マイグレーションについて我々に問い合わせてくるチームの大多数の理由は、Sanity の機能についてのブログ記事を読んだからではなく、何かが壊れたからです。

WordPress サイトは、複雑なカスタム投稿タイプを持つ50,000以上のコンテンツ数でスケーリングの壁に直面します。Contentful の価格モデルはエンタープライズレベルで圧迫され始めます。コンテンツ API に対して月額3,500ドル以上の請求を受けているチームを見かけました。Drupal チームは開発者を見つけられなくなってきています。少なくとも 2025年に PHP テンプレートで仕事をしたい開発者はいません。

Sanity の価格モデルはほとんどのチームにとってはるかに予測可能です。無料プランは月あたり100K API リクエストと500K アセットをカバーします。月額99ドルの Growth プラン/プロジェクトは2.5M API リクエストと1M アセットを取得します。比較として、Contentful の Team プランは月額300ドルで、Contentful の Premium プランは月額2,000ドルを軽く超える可能性があります。

しかし、正直なところ、現在の CMS が正常に動作していて、チームが生産的な場合は、Sanity が新しいかっこいいからというだけの理由でマイグレーションはしないでください。マイグレーションは常に考えるより多くのコストがかかります。

マイグレーション前監査:みんながスキップするステップ

マイグレーションコードの1行を書く前に、コンテンツ監査が必要です。軽く目を通すだけではなく、実際の監査が必要です。そのようなものは以下のような様子です:

コンテンツインベントリ

すべてのコンテンツタイプ、すべてのフィールド、すべてのリレーションシップをドキュメント化します。以下の列を含むスプレッドシートを使用します:

  • コンテンツタイプ名
  • 総アイテム数
  • フィールド(タイプ付き)
  • 他のコンテンツタイプとのリレーションシップ
  • メディア添付ファイル(カウントと総サイズ)
  • カスタム機能(ショートコード、ウィジェット、埋め込み)
  • 最後の変更日
  • 関連性がありますか?(はい/いいえ/多分)

死んだコンテンツがどのくらいあるかに驚くでしょう。1つの WordPress マイグレーション中に、クライアントは12,000個の投稿を持っていました。監査の後、4,200個だけが関連性がありました。これは、マイグレーション、テスト、検証する必要があるコンテンツの65%削減です。

技術的依存関係マッピング

現在の CMS が使用するすべてのプラグイン、モジュール、または統合をリストアップします。各プラグインについて、以下を判断します:

  1. Sanity がこれをネイティブに処理できますか?
  2. これ用の Sanity プラグインがありますか?
  3. カスタムソリューションを構築する必要がありますか?
  4. これを完全にドロップできますか?

このマッピング自体があれば、今後数週間の驚きから身を守ることができます。

チーム準備状況評価

Sanity Studio は React ベースです。コンテンツエディターはトレーニングが必要になります。開発者は GROQ(または GraphQL を使用できますが、GROQ は Sanity が本当に輝く場所です)を学ぶ必要があります。チームのオンボーディング に1~2週間予算を立てます。素晴らしいものではなく、ラインアイテムとして。

WordPress から Sanity へのマイグレーション

WordPress は、我々がマイグレーションする最も一般的なソース CMS です。また、最もトリッキーです。なぜなら WordPress は単なる CMS ではなく、人々がすべてを取り付けた全体的なアプリケーションプラットフォームだからです。

クリーンに転送できるもの

  • 投稿とページ(基本的なコンテンツ)
  • カテゴリーとタグ
  • 注目画像
  • 著者データ
  • 基本的なカスタムフィールド(ACF、Meta Box)

ぐちゃぐちゃになるもの

  • Gutenberg ブロック:各ブロックタイプは、対応する Sanity Portable Text カスタムブロックまたはオブジェクトタイプが必要です。15個以上のカスタム Gutenberg ブロックがあれば、ここで多くの時間を予算してください。
  • ショートコード:これらを解析、解釈、Portable Text 注釈またはカスタムブロックに変換する必要があります。WPBakery と Elementor のショートコードは特に厄介です。
  • プラグイン生成コンテンツ:WooCommerce 製品、Yoast SEO データ、ACF リピーターフィールド。各々がカスタムマイグレーションロジックを必要とします。
  • メディアライブラリ:WordPress は複数の画像サイズを保存します。Sanity はオンザフライで画像変換を処理するので、元の画像だけが必要です。しかし、散らかった wp-uploads フォルダー内の元の画像を見つけることは?楽しい時間です。

マイグレーションスクリプトアプローチ

通常、WordPress REST API を使用して Sanity のミューテーション API に書き込む Node.js スクリプトを使用します:

import { createClient } from '@sanity/client'
import fetch from 'node-fetch'

const sanity = createClient({
  projectId: 'your-project-id',
  dataset: 'production',
  token: process.env.SANITY_WRITE_TOKEN,
  apiVersion: '2025-01-01',
  useCdn: false,
})

const WP_API = 'https://yoursite.com/wp-json/wp/v2'

async function migratePosts(page = 1) {
  const res = await fetch(`${WP_API}/posts?per_page=100&page=${page}`)
  const posts = await res.json()
  const totalPages = res.headers.get('x-wp-totalpages')

  const transaction = sanity.transaction()

  for (const post of posts) {
    transaction.createOrReplace({
      _id: `wp-post-${post.id}`,
      _type: 'post',
      title: post.title.rendered,
      slug: { current: post.slug },
      publishedAt: post.date,
      // Body requires HTML-to-Portable-Text conversion
      body: await convertToPortableText(post.content.rendered),
    })
  }

  await transaction.commit()
  console.log(`Migrated page ${page} of ${totalPages}`)

  if (page < totalPages) {
    await migratePosts(page + 1)
  }
}

convertToPortableText 関数は、複雑さの80%が存在する場所です。@sanity/block-tools パッケージを jsdom と組み合わせて HTML 解析を行うために使用します。基本的な HTML は適切に処理しますが、カスタム要素とショートコードは個別のハンドラーが必要です。

現実的なタイムライン

500~2,000個の投稿、標準的なカスタムフィールド、少数のカスタム投稿タイプを持つ典型的な WordPress サイトの場合:コンテンツモデリング、マイグレーションスクリプト、検証、エディタートレーニングを含めて 4~8週間

Sanity マイグレーション完全ガイド:WordPress、Contentful、Drupal からの移行 - アーキテクチャ

Contentful から Sanity へのマイグレーション

Contentful から Sanity へのマイグレーションは、3つの中で実際に最もスムーズなマイグレーションパスです。なぜですか?なぜなら、どちらも構造化コンテンツプラットフォームであり、類似した思考モデルを持っているからです。あなたのコンテンツは既に定義されたコンテンツタイプとフィールドを持つヘッドレス CMS にあります。

考慮すべき主な違い

機能 Contentful Sanity
リッチテキスト Rich Text(JSON ベース) Portable Text(JSON ベース)
コンテンツモデリング Web UI コード定義スキーマ
クエリ言語 GraphQL / REST GROQ(+ GraphQL)
ローカライゼーション ビルトイン フィールドレベル プラグインまたはカスタム
リファレンス Links(Entry/Asset) 型付きリファレンス
Webhook あり あり
アセット処理 ビルトイン CDN Sanity CDN + ホットスポット/トリミング
価格(中位層) 約$300/月(Team) $99/月(Growth)

リッチテキスト変換

Contentful の Rich Text と Sanity の Portable Text はどちらも JSON ベースですが、これは素晴らしいことです。ただし、構造は異なります。トランスフォーマーを作成する必要があります:

function contentfulRichTextToPortableText(richTextField) {
  return richTextField.content.map(node => {
    switch (node.nodeType) {
      case 'paragraph':
        return {
          _type: 'block',
          style: 'normal',
          children: node.content.map(mapInlineContent),
        }
      case 'heading-2':
        return {
          _type: 'block',
          style: 'h2',
          children: node.content.map(mapInlineContent),
        }
      case 'embedded-entry-block':
        // Map to your custom Portable Text type
        return mapEmbeddedEntry(node)
      // ... handle all node types
    }
  }).filter(Boolean)
}

コンテンツタイプからスキーマへのマッピング

Contentful コンテンツタイプは Sanity ドキュメント型とオブジェクト型にかなり直接マップされます。最大のシフトは、Sanity スキーマがコード(JavaScript/TypeScript)で定義されており、Web UI ではないということです。これは実は大きな利点です。コンテンツモデルはバージョン管理に存在します。

Contentful Management API を使用してコンテンツモデルをエクスポートしてから、Sanity スキーマファイルを生成するスクリプトを作成します:

contentful space export --space-id YOUR_SPACE_ID --export-dir ./export

現実的なタイムライン

10~20個のコンテンツタイプと5,000~10,000個のエントリを持つ Contentful スペースの場合:3~5週間。これは、既に構造化コンテンツで考えているため、より速くなります。

Drupal から Sanity へのマイグレーション

Drupal マイグレーションは、2杯目のコーヒーを注ぐようにさせるものです。Drupal が悪いからではなく、強力なシステムです。しかし、Drupal サイトは古く、非常にカスタマイズされており、誰も完全に理解していないインフラストラクチャで実行されている傾向があります。

Drupal 固有の課題

  • 50以上のフィールドを持つコンテンツタイプ:Drupal ではフィールドを追加するのは簡単です。簡単すぎます。80個のフィールド(その半分は未使用)を持つコンテンツタイプを見かけました。
  • タクソノミー用語リファレンス:Drupal のタクソノミーシステムは柔軟ですが、Sanity 用に平坦化する必要がある深くネストされた階層を作成できます。
  • Paragraphs モジュール:サイトが Drupal Paragraphs を使用している場合(ほとんどの最新 Drupal サイトはそうです)、各段落タイプは Portable Text ブロックタイプまたは Sanity オブジェクトになります。これが最大の単一タスクです。
  • メディアエンティティ:Drupal 9/10 のメディアシステムは WordPress のものより複雑です。複数のメディアタイプ、再利用可能なメディアエンティティ、ファイルフィールド設定。すべてがマッピングを必要とします。
  • 多言語コンテンツ:Drupal の翻訳システムは洗練されています。Sanity は同じレベルでビルトインローカライゼーションを持っていません。@sanity/document-internationalization プラグインまたはフィールドレベルのアプローチが必要になります。

マイグレーションアプローチ

Drupal の JSON:API モジュール(Drupal 9.x 以降コアに含まれる)を抽出レイヤーとして使用するのに好みがあります:

async function fetchDrupalContent(type, page = 0) {
  const limit = 50
  const offset = page * limit
  const url = `${DRUPAL_URL}/jsonapi/node/${type}?page[limit]=${limit}&page[offset]=${offset}&include=field_image,field_paragraphs`

  const res = await fetch(url, {
    headers: { Authorization: `Basic ${DRUPAL_AUTH}` },
  })
  return res.json()
}

JSON:API がない古い Drupal 7 サイトの場合、データベースに直接クエリする必要があるかもしれません。Drupal 7 のデータベーススキーマは、経験です。field_data_* テーブルはあなたの悪夢を追いかけます。

現実的なタイムライン

Drupal マイグレーションは大きく異なります。5~10個のコンテンツタイプを持つストレートな Drupal 10 サイト:5~8週間。30個以上のコンテンツタイプ、Paragraphs、多言語コンテンツを持つレガシー Drupal 7 サイト:8~16週間。誇張していません。

コンテンツモデリング:スキーマを正しく設計する

ほとんどのマイグレーションガイドが教えないことは、古いコンテンツモデルを Sanity で複製しないでください。これは、長年蓄積されたコンテンツ技術的負債を修正するチャンスです。

一般的なモデリング上の間違い

  1. フィールドマッピングの1:1作成:WordPress に「サブタイトル」カスタムフィールドがあったからといって、Sanity が1つ必要というわけではありません。多分、構造化された「ヒーロー」オブジェクトの一部であるべきです。
  2. オブジェクトの過度なネスト:Sanity はオブジェクトを深くネストできます。衝動に抵抗してください。比較的フラットなスキーマは GROQ でクエリしやすく、エディターが操作しやすいです。
  3. Portable Text のパワーを無視する:単に HTML を単一のテキストフィールドにダンプしないでください。コンテンツパターンに対応するカスタムブロックタイプを設計します。「呼び出し」ブロック、「コードスニペット」ブロック、「キャプション付き画像」ブロック。これらはエディターの人生を楽にします。

スキーマ設計プロセス

この순序で以下を実行します:

  1. 既存コンテンツを監査する(マイグレーション前に実行)
  2. 実際のコンテンツパターンを識別する(CMS が押し付けたものではなく)
  3. 紙/ホワイトボード上で最初にスキーマを設計する
  4. スキーマをコードで構築する
  5. 小さなテストバッチ(50~100アイテム)をインポートする
  6. エディターに Studio エクスペリエンスをテストさせる
  7. 完全なマイグレーション前にスキーマを反復する

ステップ5~7は重要であり、しばしばスキップされます。我々は、ヘッドレス CMS 開発の作業でコンテンツモデリングアプローチについてもっと書きました。

データマイグレーション戦略とツール

必須ツール

  • @sanity/client:Sanity データを読み書きするための公式 JavaScript クライアント
  • @sanity/block-tools:HTML を Portable Text に変換する
  • sanity dataset import/export:完全なデータセット操作用の CLI ツール
  • ndjson:Sanity は改行区切り JSON をインポートに使用します。慣れてください。
  • jsdom または htmlparser2:リッチテキスト変換中の HTML 解析用

マイグレーションアーキテクチャ

すべてのマイグレーションを4段階のパイプラインとして構成します:

抽出 → 変換 → ロード → 検証

各ステージは個別のスクリプトです。これが重要なのは、マイグレーションを複数回実行するからです。通常は最終本番実行前に5~10回実行します。段階を分離することで、修正が必要な部分だけを再実行できます。

# 抽出
node scripts/extract-wordpress.js > data/raw-posts.ndjson

# 変換
node scripts/transform-posts.js < data/raw-posts.ndjson > data/sanity-posts.ndjson

# ロード
sanity dataset import data/sanity-posts.ndjson production --replace

# 検証
node scripts/validate-migration.js

アセットの処理

画像とファイルは常に最も遅い部分です。Sanity のアセットパイプラインは優れていますが、10,000個の画像をアップロードするのには時間がかかります。ヒント:

  • 最初にアセットをアップロードし、古い URL から新しい Sanity アセット ID へのマッピングを保持する
  • 並行アップロードを使用します(ただし、レート制限を尊重します。Growth プランの場合は25 req/秒)
  • アップロード前に画像の寸法と形式を確認する
  • サムネイルサイズをマイグレーションしないでください。Sanity はそのイメージ CDN を通じてこれらをオンザフライで生成します。

誰も話さない隠れたコスト

マイグレーション推定には表示されないコストについて、ぶっきらぼうに述べます。

URL リダイレクト

フロントエンドを変更している場合(Sanity に移行している場合、ほぼ確実に)、URL マッピングのリダイレクトが必要です。すべてのドメイン。SEO の場合、これは妥協の余地がありません。5,000ページのサイトには5,000個のリダイレクトルールが必要です。next.config.js リダイレクトまたは Vercel の _redirects ファイルなどのツールがこれを処理できますが、誰かがマッピングを構築する必要があります。

SEO メタデータマイグレーション

WordPress からの Yoast SEO データ。Drupal からの Metatag モジュールデータ。Contentful の SEO フィールド。すべてが過去を来る必要があります。カスタムメタタイトル、説明、Open Graph 画像、標準 URL、構造化データ。プロジェクト内のプロジェクトです。

エディタートレーニングとドキュメント

最小2~4日を予算してください。Sanity Studio は直感的ですが、エディターが知っているものとは異なります。通常、スクリーンショット付きのカスタム Studio ドキュメントを作成し、3~5個のウォークスルービデオを記録します。

フロントエンド開発

これは部屋の象です。Sanity へのコンテンツマイグレーションはプロジェクトの半分に過ぎません。コンテンツを消費するフロントエンドも必要です。Next.js、Astro、または別のフレームワークを使用しているかどうかにかかわらず、フロントエンドビルドは総プロジェクトコストの50~70%のことが多いです。フロントエンドオプションを評価している場合は、Next.jsAstro での我々の作業を確認してください。

タイムラインと予算の比較

2024~2025年に完了したプロジェクトに基づいて:

マイグレーションパス コンテンツ量 複雑さ タイムライン 予算範囲
WordPress → Sanity < 1,000ページ 3~5週間 $8K~$15K
WordPress → Sanity 1,000~10,000ページ 6~10週間 $15K~$35K
WordPress → Sanity 10,000+ページ 10~16週間 $35K~$75K
Contentful → Sanity < 5,000エントリ 低~中 3~5週間 $7K~$18K
Contentful → Sanity 5,000~20,000エントリ 5~8週間 $18K~$40K
Drupal → Sanity < 2,000ノード 5~8週間 $12K~$25K
Drupal → Sanity 2,000~15,000ノード 8~14週間 $25K~$60K
Drupal 7 → Sanity どれでも 非常に高い 10~20週間 $35K~$90K

注:これらの範囲はコンテンツマイグレーションのみを含みます。フロントエンド開発は追加です。プロジェクト固有の見積もりについては、/pricing でお問い合わせください。

これらの数値には、コンテンツモデリング、マイグレーションスクリプト、データ検証、基本的なエディタートレーニングが含まれます。フロントエンド開発、デザイン、継続的なメンテナンスは含まれていません。

マイグレーション後チェックリスト

すべてのマイグレーション時に使用するチェックリストは次のとおりです:

  • すべてのコンテンツタイプがマイグレーション済みで検証済み
  • すべてのリファレンス/リレーションシップが完全
  • すべての画像とファイルがアップロード済みで正しくリンク済み
  • リッチテキストコンテンツが正しくレンダリングされます(破損した書式をチェック)
  • URL リダイレクトが実施されてテスト済み
  • SEO メタデータがマイグレーション済み(タイトル、説明、OG データ)
  • XML サイトマップが再生成されました
  • 検索コンソールが新しいサイトマップで更新されました
  • 分析トラッキングが保持されました
  • エディターアカウントが作成され、権限が設定されました
  • エディタートレーニングが完了しました
  • コンテンツプレビュー(ドラフトモード)が機能しています
  • ビルドトリガー用の Webhook が設定されました
  • ソース CMS データのバックアップがアーカイブされました
  • DNS 変更が計画されました(該当する場合)
  • パフォーマンスベースラインが測定されました
  • 404 監視が最初の30日間に設定されています

最後のポイントは重要です。どれほど徹底的なリダイレクトマッピングでも、いくつかの URL はスリップします。最初の1ヶ月間、404をアグレッシブに監視してください。

FAQ

WordPress から Sanity へのマイグレーションの典型的な期間は? 2,000以下の投稿を持つ標準的な WordPress サイトで、ストレートなカスタムフィールドの場合、4~8週間と予想してください。これには、コンテンツモデリング、マイグレーションスクリプト、データ検証、エディタートレーニングが含まれます。複雑な Gutenberg ブロック、WooCommerce、多言語コンテンツを持つサイトは、10~16週間かかります。コンテンツ量はコンテンツタイプの複雑さほど問題ではありません。

Contentful から Sanity へのマイグレーション中にデータを失わないようにできますか? はい、実際には私がここでカバーしている3つの中で最もクリーンなマイグレーションパスです。両方のプラットフォームが構造化、JSON ベースのコンテンツを使用するため、マッピングは比較的直接的です。リッチテキストを Contentful の形式から Portable Text に変換する必要があり、リファレンスを再マップする必要がありますが、データを失う必要はありません。本番環境へのカットオーバーの前に、マイグレーションをステージングデータセットに対して実行して、徹底的なコンテンツ比較を行うことをお勧めします。

CMS マイグレーション中の SEO ランキングはどうなりますか? これはマーケティングディレクターを夜中起こす質問です。リダイレクトを正しく処理し、可能な限り URL 構造を維持し、すべての SEO メタデータをマイグレーションすれば、影響はほぼ見えないはずです。Google の独自のドキュメントでは、適切にリダイレクトされたマイグレーションは回復前に2~4週間の一時的な下落を見ることができると述べています。重要な単語は「適切に」です。リダイレクトマッピングをスキップして、ランキングを低下させます。我々はそれが起こるのを見てきました。

Sanity は Contentful よりエンタープライズ使用で安いですか? ほとんどの場合、はい。時々かなり。Sanity の Growth プランは月額99ドルで、Contentful の月額300ドルの Team プランに必要なものをカバーしています。エンタープライズスケールでは、差が大きくなります。Contentful の Premium 価格は公開されていませんが、通常は月額2,000~4,000ドル以上です。Sanity Enterprise 価格はカスタムですが、一般的には同等の使用率でより低くなります。実際のコスト差はAPI呼び出しにあります。Sanity のインクルード制限はより寛容です。

Drupal 7 サイトを Sanity にマイグレーションするか、まず Drupal 10 にアップグレードするか? Sanity に直接進んでください。Drupal 7 から Drupal 10 へのマイグレーションは、異なる CMS へのマイグレーションと同じくらいの作業です。バージョン間のアーキテクチャはそれほど劇的に変わりました。既に大規模なマイグレーションに投資している場合、長期的には実際にいたい場所に移動するのと同じです。1つの例外:チームが Drupal エコシステムに深く投資していて、単にモダナイズしたい場合、ヘッドレスフロントエンドを備えた Drupal 10 は有効なパスです。

Sanity にマイグレーションするときにフロントエンドを再構築する必要がありますか? WordPress や Drupal などのモノリシック CMS から来ている場合はい。Sanity はヘッドレスなので新しいフロントエンドが必要になります。これは通常、プロジェクトの大きな部分です。Contentful から来ている場合、既存フロントエンドを再利用できることが多く、特に Next.js または類似のフレームワークを既に使用している場合は、API 呼び出しを変更しています。我々は CMS マイグレーションと フロントエンドビルド の両方を統合されたプロジェクトとして処理します。

マイグレーション中に古い CMS と Sanity を並行して実行できますか? 絶対に、そして私はそれをお勧めします。初期マイグレーション後、2~4週間、両方のシステムを実行します。エディターは古い CMS で作業を続けることができ、Sanity でデータを検証します。最終マイグレーション実行の前に、古いシステムのコンテンツを凍結してください。移動するターゲットを追いかけたくありません。いくつかのチームは、最終カットオーバーの48時間前に「コンテンツフリーズ」日付を設定します。

Sanity マイグレーション中にチームが最大の間違いは何をしているのですか? 古い CMS 構造を Sanity で正確に複製しようとしています。私はこれを絶えず見ます。WordPress から来るチームは、一般的な「ページ」タイプの代わりに、柔軟なレイアウトの代わりに、Sanity で WordPress 形のスキーマを構築しようとします。Sanity の強さは構造化コンテンツです。マイグレーションをコンテンツを正しくモデル化する機会として使用してください。コンテンツモデリングに余分な1週間を費やします。後で何ヶ月も苦しむことから身を救います。このことについてガイダンスが必要な場合は、お問い合わせください。コンテンツモデリングはマイグレーションプロジェクトで我々が最も時間をかけるものの1つです。