你的團隊同意轉向 Sanity。你匯出了 80,000 篇 WordPress 文章,啟動了一個 Studio 實例,然後發現一半的後設欄位遵循三種不同的架構——沒有人記錄了驅動整個網站導航的自訂分類法邏輯。我在三年內進行了 40 多次 Sanity 遷移。有些在兩週內完成。其他的延伸到三個月,讓我重新考慮導致我成為自由職業者的每一個決定。區別從來不是你是否離開 WordPress、Contentful 或 Drupal。它歸結為三件事:你在一開始對內容模型的坦誠評估程度、你是否將欄位映射視為架構或繁忙工作,以及你的團隊中是否有人承認他們不理解舊 CMS 實際上是如何工作的。本指南帶你了解每個決定,這些決定決定了你的遷移是否是一次乾淨的衝刺或緩慢的瓦解——並向你展示確切的檢查清單、指令碼和心智模式,區分兩者。

這是我開始進行 CMS 遷移時希望擁有的指南。它涵蓋了從 WordPress、Contentful 和 Drupal 遷移到 Sanity GROQ 驅動的世界。我將坦誠地談論 Sanity 的優勢、它將令你沮喪的地方,以及真實的時間表是什麼樣的。

目錄

Sanity Migration Playbook:從 WordPress、Contentful 或 Drupal 遷移

為什麼團隊在 2026 年遷移到 Sanity

讓我們先拋開明顯的東西。Sanity 的實時協作編輯、可自訂的 Studio 和結構化內容方法確實很好。但大多數團隊聯絡我們進行遷移的原因不是因為他們讀了一篇關於 Sanity 功能的部落格文章。那是因為出了問題。

WordPress 網站在擁有 50,000 個以上複雜自訂文章類型的內容時會遇到擴展限制。Contentful 的定價模型在企業層開始擠壓——我們看過團隊面臨 3,500 美元以上/月的帳單,實際上只是內容 API。Drupal 團隊再也找不到開發人員了,至少找不到想在 2026 年使用 PHP 範本的人。

Sanity 的定價模型對大多數團隊來說確實更容易預測。免費層最多可支援 100K API 請求/月和 500K 資產。增長計畫在 99 美元/月/項目,可為你提供 250 萬 API 請求和 100 萬資產。相比之下,Contentful 的團隊計畫運行 300 美元/月,Contentful 的高級層可以輕鬆超過 2,000 美元/月。

但這是我的誠實想法:如果你目前的 CMS 運行良好,你的團隊生產力強,不要只是因為 Sanity 更新或更酷就遷移。遷移總是花費比你想像的要多。

遷移前審計:每個人都跳過的步驟

在你寫一行遷移程式碼之前,你需要進行內容審計。不是快速掃描——一個實際的審計。這是什麼樣的:

內容清單

記錄每個內容類型、每個欄位、每個關係。我使用包含這些欄位的試算表:

  • 內容類型名稱
  • 項目總數
  • 欄位(包含類型)
  • 與其他內容類型的關係
  • 媒體附件(數量和總大小)
  • 自訂功能(短代碼、小工具、嵌入)
  • 上次修改日期
  • 仍然相關?(是/否/也許)

你會驚訝有多少內容是死重物。在一次 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 資料夾中找到原始版本?有趣的時光。

遷移指令碼方法

我通常使用一個 Node.js 指令碼,它擊中 WordPress REST API 並寫入 Sanity 的 mutation API:

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,但自訂元素和短代碼需要個別處理器。

現實時間表

對於一個典型的 WordPress 網站,擁有 500-2,000 篇文章、標準自訂欄位和少數自訂文章類型:4-8 週,包括內容建模、遷移指令碼、驗證和編輯器培訓。

Sanity Migration Playbook:從 WordPress、Contentful 或 Drupal 遷移 - 架構

Contentful 到 Sanity 遷移

Contentful 到 Sanity 的遷移實際上是三個中最平順的遷移路徑。為什麼?因為兩者都是具有類似心智模型的結構化內容平台。你的內容已經在一個無頭 CMS 中,具有定義的內容類型和欄位。

要考慮的關鍵差異

功能 Contentful Sanity
豐富文字 豐富文字(JSON 型) Portable Text(JSON 型)
內容建模 網頁 UI 程式碼定義的架構
查詢語言 GraphQL / REST GROQ(+ GraphQL)
本地化 內建欄位級 外掛或自訂
參考 連結(條目/資產) 具有類型的參考
Webhooks
資產處理 內建 CDN Sanity CDN + hotspot/crop
定價(中層) ~300 美元/月(團隊) 99 美元/月(增長)

豐富文字轉換

Contentful 的豐富文字和 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)中定義,而不是在網頁 UI 中。這實際上是一個巨大的優勢——你的內容模型存在於版本控制中。

使用 Contentful 管理 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 遷移是讓我倒第二杯咖啡的。不是因為 Drupal 不好——它是一個強大的系統。但 Drupal 網站往往很舊、高度自訂,並在沒有人完全理解的基礎設施上執行。

Drupal 特定的挑戰

  • 擁有 50 個以上欄位的內容類型:Drupal 使新增欄位變得容易。太容易了。我看過擁有 80 個欄位的內容類型,其中一半未使用。
  • 分類法術語參考:Drupal 的分類系統很靈活,但可以建立深度嵌套的層次結構,需要為 Sanity 拉平。
  • 段落模組:如果網站使用 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 遷移差異很大。一個直接的 Drupal 10 網站,擁有 5-10 個內容類型:5-8 週。具有 30 個以上內容類型、段落和多語言內容的舊版 Drupal 7 網站:8-16 週。我沒有誇大。

內容建模:正確獲取你的架構

以下是大多數遷移指南不會告訴你的內容:不要在 Sanity 中複製你的舊內容模型。這是你修復多年累積內容債務的機會。

常見的建模錯誤

  1. 建立 1:1 欄位映射:只是因為 WordPress 有「副標題」自訂欄位,不意味著 Sanity 需要一個。也許它應該是結構化「英雄」物件的一部分。
  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 進行匯入——熟悉它
  • jsdomhtmlparser2:用於在豐富文字轉換期間進行 HTML 解析

遷移架構

我將每次遷移構構為具有四個階段的管道:

提取 → 轉換 → 載入 → 驗證

每個階段都是一個單獨的指令碼。這很重要,因為你將執行遷移多次——通常在最終生產運行之前 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 的映射
  • 使用並行上傳(但要尊重速率限制——增長計畫為 25 req/sec)
  • 在上傳前驗證影像尺寸和格式
  • 不要遷移縮圖大小——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%。如果你評估前端選項,請查看我們的工作。

時間表和預算比較

根據我們最近幾年完成的專案:

遷移路徑 內容量 複雜性 時間表 預算範圍
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

注意:這些範圍僅包括內容遷移。前端開發是額外的。如需特定專案的估計,請聯絡我們。

這些數字包括內容建模、遷移指令碼、資料驗證和基本編輯器培訓。他們不包括前端開發、設計或持續維護。

遷移後檢查清單

以下是我在每次遷移中使用的檢查清單:

  • 所有內容類型已遷移並驗證
  • 所有參考/關係保持不變
  • 所有影像和檔案已上傳並正確連結
  • 豐富文字內容正確呈現(檢查格式問題)
  • 設置了 URL 重定向並進行了測試
  • SEO 後設資料已遷移(標題、描述、OG 資料)
  • XML Sitemap 已重新生成
  • 搜尋控制台已更新為新 Sitemap
  • 分析跟蹤已保留
  • 編輯器帳戶已建立並設定了權限
  • 編輯器培訓已完成
  • 內容預覽(草稿模式)有效
  • 為構建觸發器配置的 Webhooks
  • 源 CMS 資料的備份已存檔
  • DNS 更改已規劃(如果適用)
  • 效能基線已測量
  • 為前 30 天設置了 404 監控

最後一點很重要。無論你的重定向映射有多徹底,一些 URL 都會滑過。在前 30 天主動監控你的 404。

常見問題

典型的 WordPress 到 Sanity 遷移需要多長時間? 對於一個標準 WordPress 網站,擁有不到 2,000 篇文章和直觀的自訂欄位,預計 4-8 週。這包括內容建模、遷移指令碼、資料驗證和編輯器培訓。擁有複雜 Gutenberg 區塊、WooCommerce 或多語言內容的網站可能需要 10-16 週。內容量比內容類型的複雜性要少。

我能否在沒有資料丟失的情況下從 Contentful 遷移到 Sanity? 是的,這實際上是我在這裡涵蓋的三個中最乾淨的遷移路徑。兩個平台都使用結構化、基於 JSON 的內容,所以映射相對直接。豐富文字需要從 Contentful 的格式轉換為 Portable Text,參考需要重新映射,但你不應該丟失任何資料。我建議首先針對暫存資料集執行遷移,並在完全切換之前進行徹底的內容比較。

在 CMS 遷移期間我的 SEO 排名會發生什麼? 這是讓行銷主任整夜睡不著的問題。如果你正確處理重定向,盡可能保持你的 URL 結構,並遷移所有 SEO 後設資料,你應該看到最小的影響。Google 自己的文件說,適當重定向的遷移可能在 2-4 週內看到臨時下降,然後恢復。關鍵詞是「適當」。跳過重定向映射,你會摧毀你的排名。我們看過它發生。

對於企業使用,Sanity 比 Contentful 便宜嗎? 在大多數情況下,是的——有時顯著便宜。Sanity 的增長計畫在 99 美元/月涵蓋了 Contentful 300 美元/月團隊計畫所需的內容。在企業規模上,差異變得更大。Contentful 的高級定價不會公開列出,但通常為 2,000-4,000 美元以上/月。Sanity 企業定價也是自訂的,但對於等效使用通常低於 Contentful。真正的成本差異在於 API 呼叫——Sanity 的內含限制更慷慨。

我應該將我的 Drupal 7 網站遷移到 Sanity 還是先升級到 Drupal 10? 直接前往 Sanity。從 Drupal 7 遷移到 Drupal 10 幾乎與遷移到不同 CMS 一樣費力——版本之間的架構改變得那麼劇烈。如果你已經投資於主要遷移,你不妨遷移到你實際想長期使用的平台。一個例外是:如果你的團隊深深投入 Drupal 生態系統,只想現代化,Drupal 10 與無頭前端是一個有效的途徑。

在遷移到 Sanity 時,我需要重建我的前端嗎? 如果你來自 WordPress 或 Drupal 等單體 CMS,是的——你將需要新的前端,因為 Sanity 是無頭的。這通常是專案的更大部分。如果你來自 Contentful,你通常可以重用你現有的前端,只需修改 API 呼叫,尤其是如果你已經使用 Next.js 或類似框架。我們將 CMS 遷移和前端構建處理為整合專案。

在遷移期間,我可以並行執行舊 CMS 和 Sanity 嗎? 絕對可以,我建議這樣做。在初始遷移後並行執行兩個系統 2-4 週。編輯可以繼續在舊 CMS 中工作,同時驗證 Sanity 中的資料。只是在最終遷移執行前凍結舊系統中的內容——你不想追逐一個移動的目標。有些團隊在最終切換前 48 小時設定「內容凍結」日期。

團隊在 Sanity 遷移期間犯的最大錯誤是什麼? 試圖在 Sanity 中完全複製他們的舊 CMS 結構。我經常看到這個。來自 WordPress 的團隊試著在 Sanity 中構建 WordPress 形狀的架構——具有靈活佈局的通用「頁面」類型,而不是目的構建的內容類型。Sanity 的強度是結構化內容。將遷移用作適當建模內容的機會。在內容建模上多花一週。它將在以後為你節省數月的痛苦。如果你想要本指南,請聯絡我們——內容建模是我們在遷移專案中花費最多時間的東西之一。