Sanity Migration Playbook: WordPress、Contentful、Drupalからの移行
過去3年間、私はSanityへの移行プロジェクトを約40件手がけてきました。中には2週間のクリーンなスプリントで終わったものもあれば、3ヶ月のプロジェクトになり、キャリアの選択を後悔したものもあります。その差は、移行元のCMSにはほとんど起因しません。本当の要因は、準備、コンテンツモデリングの決定、そして実際に何に取り組んでいるのかを正直に認識することです。
これは、CMS移行に取り組み始めた時に欲しかったガイドです。WordPress、Contentful、DrupalからSanityのGROQパワードな世界への移行をカバーしています。Sanityがどこでしっかりしているか、どこでイライラさせるか、実際のタイムラインはどのようなものかについて、率直に説明します。
目次
- なぜ2026年にチームがSanityに移行しているのか
- 移行前監査:みんなスキップするステップ
- WordPressからSanityへの移行
- ContentfulからSanityへの移行
- DrupalからSanityへの移行
- コンテンツモデリング:スキーマを正しく設定する
- データ移行戦略とツール
- 誰も話さない隠れたコスト
- 移行後チェックリスト
- タイムラインと予算の比較
- よくある質問

なぜ2026年にチームがSanityに移行しているのか
まず明らかなことから始めましょう。Sanityのリアルタイムコラボレーティブ編集、カスタマイズ可能なStudio、構造化コンテンツアプローチは本当に優れています。ただし、ほとんどのチームが移行について相談してくる本当の理由は、Sanityの機能についてのブログ記事を読んだからではなく、何かが壊れたからです。
WordPressサイトは、複雑なカスタム投稿タイプを使って50,000以上のコンテンツピースでスケーリングの壁にぶつかります。Contentfulの価格モデルはエンタープライズティアで圧力が高まります。実際に見たケースでは、コンテンツAPIに月額3,500ドル以上の請求を受けているチームもあります。Drupalチームは開発者を見つけることができなくなっています。少なくとも2026年にPHPテンプレート作成で作業したいと思う開発者は見つかりません。
Sanityの価格モデルは、ほとんどのチームにとって本当に予測可能です。無料ティアは月間最大100K APIリクエストと500Kアセットをカバーしています。月額99ドルのGrowthプランは2.5M APIリクエストと1Mアセットを提供します。比較すると、ContentfulのTeamプランは月額300ドルで、ContentfulのPremiumティアは簡単に月額2,000ドルを超えます。
しかし、これが私の正直な意見です。現在のCMSが正常に機能していて、チームが生産的であれば、Sanityがより新しいまたはクールだからといって移行しないでください。移行は常に予想より多くのコストがかかります。
移行前監査:みんなスキップするステップ
移行コードを1行書く前に、コンテンツ監査が必要です。簡単なスキャンではなく、実際の監査です。これはこのようになります。
コンテンツインベントリ
あらゆるコンテンツタイプ、あらゆるフィールド、あらゆる関係を文書化します。以下の列を含むスプレッドシートを使用します:
- コンテンツタイプ名
- 総項目数
- フィールド(タイプ付き)
- 他のコンテンツタイプとの関係
- メディア添付ファイル(数と合計サイズ)
- カスタム機能(ショートコード、ウィジェット、埋め込み)
- 最終更新日
- 関連があるか?(はい/いいえ/わかりません)
不要なコンテンツがどれほど多いかに驚くでしょう。あるWordPress移行では、クライアントは12,000個の投稿を持っていました。監査後、4,200個だけが関連していました。つまり、移行、テスト、検証するコンテンツが65%少なくなります。
技術的依存関係マッピング
現在のCMSが使用するあらゆるプラグイン、モジュール、または統合をリストします。各々について、以下を判定します:
- Sanityはこれをネイティブに処理できるか?
- Sanityプラグインがあるか?
- カスタムソリューションを構築する必要があるか?
- これを完全にドロップできるか?
このマッピングだけで、後で何週間もの驚きから救われます。
チーム準備状況評価
Sanity Studioはレベースです。コンテンツエディターはトレーニングが必要です。開発者は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のショートコードは特に複雑です。
- プラグイン生成コンテンツ:WooCommerceProducts、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はHTML-to-Portable-Text変換が必要です
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週間。

ContentfulからSanityへの移行
ContentfulからSanityへの移行は、実は3つの中で最もスムーズな移行パスです。なぜか?両方が構造化コンテンツプラットフォームで、似た思考モデルを持っているからです。コンテンツは既に定義されたコンテンツタイプとフィールドを備えたヘッドレスCMSに含まれています。
考慮すべき主な違い
| 機能 | Contentful | Sanity |
|---|---|---|
| リッチテキスト | Rich Text(JSON形式) | Portable Text(JSON形式) |
| コンテンツモデリング | ウェブUI | コード定義スキーマ |
| クエリ言語 | GraphQL / REST | GROQ(+ GraphQL) |
| ローカライゼーション | 組み込みフィールドレベル | プラグインまたはカスタム |
| 参照 | リンク(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':
// カスタムPortable Textタイプにマップ
return mapEmbeddedEntry(node)
// ... すべてのノードタイプを処理
}
}).filter(Boolean)
}
コンテンツタイプからスキーマへのマッピング
ContentfulコンテンツタイプはSanityドキュメントおよびオブジェクトタイプにかなり直接的にマップされます。最大の転換点は、Sanityスキーマがコード(JavaScript/TypeScript)で定義されており、ウェブ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 コア9.x以降に含まれているDrupal JSON:APIモジュールを抽出層として使用することを好みます:
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フィールドマッピングの作成:WordPressに「副題」カスタムフィールドがあったからといって、Sanityに必要なわけではありません。構造化された「ヒーロー」オブジェクトの一部である可能性があります。
- オブジェクトの過度なネスト:Sanityではオブジェクトを深くネストできます。衝動に抵抗してください。フラットなスキーマはGROQでクエリしやすく、エディターが使いやすくなります。
- Portable Textのパワーを無視する:単にHTMLを1つのテキストフィールドに投げ込まないでください。コンテンツパターンに一致するカスタムブロックタイプを設計します。「コールアウト」ブロック、「コードスニペット」ブロック、「キャプション付き画像」ブロック。これらはエディターの生活を向上させます。
スキーマデザインプロセス
この順序で従います:
- 既存コンテンツの監査(移行前に実行)
- 実際のコンテンツパターンを識別します(CMSが強いたものではなく)
- 最初に紙/ホワイトボードでスキーマを設計します
- コードでスキーマを構築
- 小さなテストバッチ(50~100項目)をインポート
- エディターがStudioエクスペリエンスをテストする
- 完全な移行前にスキーマを繰り返す
ステップ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つのステージを持つパイプラインとしてすべての移行を構成します:
Extract → Transform → Load → Validate
各ステージは個別のスクリプトです。重要な理由:移行を複数回実行します。通常は5~10回、本番環境の実行前です。ステージを分けることは、修正が必要な部分だけを再実行できることを意味します。
# Extract
node scripts/extract-wordpress.js > data/raw-posts.ndjson
# Transform
node scripts/transform-posts.js < data/raw-posts.ndjson > data/sanity-posts.ndjson
# Load
sanity dataset import data/sanity-posts.ndjson production --replace
# Validate
node scripts/validate-migration.js
アセットの処理
画像とファイルは常に最も遅い部分です。Sanityのアセットパイプラインは優れていますが、10,000個の画像をアップロードするには時間がかかります。ヒント:
- アセットを最初にアップロードし、古いURLから新しいSanityアセットIDへのマッピングを維持します
- 同時アップロードを使用します(ただし、レート制限を尊重してください。Growthプランの場合は秒間25リクエスト)
- アップロード前に画像サイズと形式を検証します
- サムネイルサイズを移行しないでください。Sanityはイメージ CDN経由でこれらをオンザフライで生成します
誰も話さない隠れたコスト
あなたと正直に言っておきましょう。典型的な移行見積もりに表示されないコストについて。
URLリダイレクト
フロントエンドを変更する場合(ヘッドレスCMSに移行する場合、おそらくそうです)、リダイレクトマッピングが必要です。すべて。すべての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.jsとAstroでの当社の作業を確認してください。
タイムラインと予算の比較
最近完了したプロジェクトに基づいて:
| 移行パス | コンテンツボリューム | 複雑性 | タイムライン | 予算範囲 |
|---|---|---|---|---|
| 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変更が計画されている(該当する場合)
- パフォーマンスベースラインが測定されている
- 最初の30日間の404監視が設定されている
最後のポイントは重要です。いかに徹底的なリダイレクトマッピングでも、いくつかのURLはすり抜けます。最初の月を積極的に404を監視します。
よくある質問
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の月額99ドルのGrowthプランは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から来ている場合はい。ヘッドレスCMSなので新しいフロントエンドが必要です。これは通常、プロジェクトの大きな部分です。Contentfulから来ている場合は、既存のフロントエンドを再利用できることが多いです。特にNext.jsまたは同様のフレームワークを既に使用している場合は、修正されたAPI呼び出しになります。CMS移行とフロントエンド構築の両方を統合プロジェクトとして処理します。
移行中に古いCMSとSanityを並列で実行できますか?
絶対、そしてお勧めします。初期移行後2~4週間両方のシステムを実行します。エディターは古いCMSで作業を続けることができますが、Sanityでデータを検証します。古いシステムでコンテンツをフリーズするだけです。最後の移行実行の48時間前が最終的なカットオーバー日です。移動する目標を追いかけたくありません。いくつかのチームは、最終カットオーバーの48時間前に「コンテンツフリーズ」日付を設定しています。
チームがSanity移行中に最大の間違いを犯すのはどうですか?
古いCMSの構造を正確にSanityで複製しようとしています。これは絶えず見ています。チームはWordPressから来て、Sanityで WordPress形のスキーマを構築しようとします。柔軟なレイアウトの代わりに、汎用「ページ」タイプの代わりに、目的の構築されたコンテンツタイプ。Sanityの強みは構造化コンテンツです。移行をコンテンツを適切にモデル化する機会として使用します。コンテンツモデリングに余分な週を費やしてください。後で数ヶ月の痛みを救います。このことについてのガイダンスが必要な場合は、私たちに連絡してください。コンテンツモデリングは移行プロジェクトで最も時間を費やしているものの1つです。