你打開 WordPress 儀表板,更新圖標再次呈現紅色。你點擊。三個外掛衝突。聯絡表單停止工作。你的客戶在晚上 11 點發電子郵件,因為網站感覺緩慢,你已經知道:到交互需要六秒,如果有人在行動設備上則需要七秒。安全通知在第二天早上到達——CVE-2022-something——外掛作者已經在兩年前消失了。你修補了你能修補的,推遲了你無法修補的,並向自己承諾這是最後一次。但下一個更新週期已經兩週後了,你正盯著同樣的權衡:穩定性或功能,永遠無法同時擁有兩者。有一個更好的技術棧在等著——它不會讓你進行選擇。

這就是情況——WordPress 為超過 40% 的網際網路提供動力,這是有充分理由的。它易於使用,具有龐大的生態系統,並讓許多企業快速上線。但在讓你入門的工具和隨著你成長的工具之間有差異。如果你正在閱讀本文,你可能已經達到了那堵牆。讓我引導你了解從 WordPress 到無頭式 Next.js + Supabase 架構的真實遷移過程——不是行銷版本,而是實際的工程行動手冊。

目錄

已超出 WordPress 適用範圍?Next.js + Supabase 遷移手冊

確實超出 WordPress 適用範圍的跡象

不是每個人都需要離開 WordPress。我想提前坦白。如果你經營個人博客或本地企業的宣傳網站,具有良好主題和少數外掛的 WordPress 可能仍然是正確選擇。但有明確的信號表明你已經超出了它的適用範圍:

外掛衝突每月都在破壞東西

你更新 WooCommerce,你的頁面構建器會破壞。你更新你的頁面構建器,你的 SEO 外掛會發出警告。你更新 PHP 到 8.2 因為你的主機要求這樣,三個外掛完全停止工作。這不是一個 bug——這是架構。WordPress 外掛都共享相同的全局作用域、相同的鉤子、相同的數據庫。每個外掛都是與其他每個外掛衝突的潛在因素。

我已經審計了執行 30、40、甚至 60+ 個活躍外掛的 WordPress 網站。此時,你不是在維護網站。你在維護堆疊遊戲。

性能已成為全職工作

你的 PageSpeed 分數在 30 秒。你已安裝了緩存外掛、圖像優化外掛、縮小外掛和 CDN 外掛——所有這些都是為了解決其他 25 個外掛造成的性能問題。諷刺很厚重。

WordPress 在每個請求時動態生成頁面(除非緩存)。每個外掛都可以注入自己的 CSS 和 JavaScript 文件。具有流行外掛的典型 WordPress 頁面加載 15-30 個單獨的呈現阻止資源。Google 的核心網頁活力數據顯示 WordPress 網站在所有三個 CWV 指標上的通過率為 33%,而使用現代 JavaScript 框架構建的網站為 52%。

安全漏洞讓你夜不能寐

WPScan 的漏洞數據庫已追蹤數千個 WordPress 漏洞——絕大多數在外掛和主題中。如果你執行處理用戶數據、付款或任何敏感信息的網站,每個外掛都是攻擊面。Patchstack 報告 97% 的 WordPress 安全漏洞來自外掛。

你基本上是在信任數十個獨立開發人員——其中許多人將外掛作為副項目維護——來維護你的安全姿態。

你的開發團隊討厭在上面工作

這個被低估了。優秀的開發人員不再想在 WordPress 上工作。PHP 樣板意大利麵條與 ACF 字段的工作流相比,與基於現代組件的開發相比是痛苦的。如果你試圖吸引和保留工程人才,你的技術棧很重要。

WordPress 稅收:外掛地獄實際成本

讓我為此提供一些數字。對於中型 WordPress 網站(比如電子商務網站或具有博客、用戶帳戶和自定義功能的 SaaS 行銷網站),「WordPress 稅收」在年度基礎上通常看起來像這樣:

成本類別 年度估計
高級外掛許可證(15-20 個外掛) $1,500 - $4,000
託管 WordPress 主機(WP Engine、Kinsta) $1,200 - $6,000
安全監控 + 清理(Sucuri、Wordfence) $300 - $500
性能優化時間(開發人員工時) $3,000 - $8,000
外掛衝突調試(開發人員工時) $2,000 - $6,000
更新破壞東西的緊急修復 $1,000 - $4,000
總年度 WordPress 稅收 $9,000 - $28,500

這是在你構建單個新功能之前。這是保持燈亮著的成本。

為什麼 Next.js + Supabase 是合理的技術棧

有十幾種方式去無頭式。你可以使用 Gatsby(雖然自 Netlify 收購它以來基本上處於維護模式)。你可以使用 Remix、Astro 或 SvelteKit。對於後端,你可以使用 Firebase、PlanetScale 或自定義 API。

但對於從 WordPress 在 2026 年遷移的團隊,Next.js + Supabase 達到了難以克服的甜蜜點。這是為什麼。

Next.js:全能前端

Next.js 15(自 2024 年 10 月以來穩定)默認提供伺服器組件,這意味著你獲得靜態網站的性能,具有動態網站的靈活性。你可以在構建時靜態生成博客文章,伺服器呈現動態頁面,客戶端呈現交互組件——所有內容都在同一應用中。

對於來自 WordPress 的團隊,關鍵優勢是:

  • 內置圖像優化——取代 2-3 個 WordPress 外掛
  • 自動代碼分割——每個頁面只加載它需要的 JS
  • 邊界中間件——在 CDN 級別處理重定向、身份驗證和 A/B 測試
  • 增量靜態再生成 (ISR)——無需完整部署即可重建各個頁面
  • 使用 React 伺服器組件的應用路由器——大幅減少客戶端 JavaScript

我們在 Social Animal 構建了許多 Next.js 項目(查看我們的 Next.js 開發功能),與 WordPress 相比性能差異一直很戲劇性。

Supabase:後端 WordPress 希望擁有的

Supabase 是基於 PostgreSQL 構建的開源 Firebase 替代品。它提供:

  • 完整的 Postgres 數據庫,具有從架構自動生成的 REST 和 GraphQL API
  • 內置身份驗證(電子郵件、OAuth、魔法鏈接、SSO)
  • 用於細粒度訪問控制的行級安全策略
  • 通過 WebSockets 的實時訂閱
  • 用於無服務器後端邏輯的邊界函數
  • 用於文件上傳和 CDN 交付的存儲

特別是對於 WordPress 遷移,Supabase 很出色,因為 WordPress 使用 MySQL,你的數據模型映射到 PostgreSQL 的效果出人意料地好。自定義文章類型變為表。文章元變為 JSONB 列。用戶數據幾乎 1:1 映射。

Supabase 的免費層包括 500MB 數據庫、1GB 存儲和 5 萬個每月活躍用戶的身份驗證。他們的專業計畫每月 $25,涵蓋大多數生產網站。將此與你單獨在託管 WordPress 主機上支付的 $30-$100/月相比。

已超出 WordPress 適用範圍?Next.js + Supabase 遷移手冊 - 架構

遷移手冊:分階段

這是我在數十次 WordPress 遷移中完善的方法。它不是一個週末項目——根據網站複雜性預算 4-12 週——但如果你遵循各個階段,它是可預測且低風險的。

階段 1:審計和架構(第 1 週)

在你寫一行代碼之前:

  1. 匯出完整外掛列表,使用 wp plugin list --status=active (WP-CLI)
  2. 將每個外掛映射到新堆棧中的替代品
  3. 匯出你的完整 URL 結構,包括所有文章、頁面、分類和自定義文章類型
  4. 記錄所有表單、集成和第三方連接
  5. 識別自定義功能,在你主題的 functions.php

外掛映射練習很重要。常見的替代品看起來像這樣:

WordPress 外掛 無頭式替代品
Yoast SEO Next.js 內置元數據 API + generateMetadata()
WP Super Cache / W3 Total Cache 無需(默認為靜態)
Wordfence / Sucuri Supabase RLS + Vercel 的內置 DDoS 防護
Contact Form 7 / Gravity Forms React Hook Form + Supabase 邊界函數
WooCommerce Saleor、Medusa.js 或 Shopify Storefront API
ACF / 自定義字段 Supabase 表,具有類型化架構
WP Migrate DB 一次性 Supabase 遷移腳本
Smush / ShortPixel Next.js Image 組件(內置)
Elementor / WPBakery React 組件(你不會想念他們)

階段 2:設置新堆棧(第 2 週)

# 建立你的 Next.js 項目
npx create-next-app@latest my-site --typescript --tailwind --app --src-dir

# 安裝 Supabase
npm install @supabase/supabase-js @supabase/ssr

# 設置環境變數
cp .env.example .env.local

你的 .env.local

NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key

立即部署到 Vercel。是的,在你構建任何有意義的東西之前。從第一天有活動預覽 URL 改變了你的工作方式——利益相關者可以看到進度,你會及早發現部署問題。

數據遷移:從 WordPress 導出你的內容

這是大多數遷移指南變得模糊的地方。讓我具體說明。

步驟 1:匯出 WordPress 數據

不要使用內置的 WordPress XML 匯出。它不完整且結構不良。而是使用 WP-CLI 和直接數據庫查詢:

# 將文章匯出為 JSON
wp post list --post_type=post --format=json --fields=ID,post_title,post_content,post_excerpt,post_date,post_status,post_name > posts.json

# 匯出頁面
wp post list --post_type=page --format=json --fields=ID,post_title,post_content,post_excerpt,post_date,post_status,post_name > pages.json

# 匯出自定義文章類型
wp post list --post_type=your_cpt --format=json > cpt.json

# 匯出文章元(ACF 字段等)
wp eval 'global $wpdb; $results = $wpdb->get_results("SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE meta_key NOT LIKE \"_%\""); echo json_encode($results);' > postmeta.json

步驟 2:轉換並加載到 Supabase

編寫遷移腳本。我傾向於為此使用 TypeScript:

import { createClient } from '@supabase/supabase-js'
import posts from './exports/posts.json'

const supabase = createClient(
  process.env.SUPABASE_URL!,
  process.env.SUPABASE_SERVICE_ROLE_KEY!
)

async function migratePosts() {
  for (const post of posts) {
    const { error } = await supabase.from('posts').insert({
      wp_id: post.ID,
      title: post.post_title,
      slug: post.post_name,
      content: convertWpContentToMdx(post.post_content),
      excerpt: post.post_excerpt,
      published_at: post.post_date,
      status: post.post_status === 'publish' ? 'published' : 'draft',
    })
    
    if (error) console.error(`Failed to migrate post ${post.ID}:`, error)
  }
}

function convertWpContentToMdx(html: string): string {
  // 使用 turndown 或 rehype 將 WordPress HTML 轉換為 MDX
  // 處理短碼、嵌入和 Gutenberg 塊
  // 這是 80% 遷移複雜性所在
}

convertWpContentToMdx 函數是你花費最多時間的地方。WordPress 內容是 HTML、短碼、Gutenberg 塊註釋和嵌入式 oEmbed URL 的混合。像 turndown 這樣的庫處理基本的 HTML 到 Markdown 轉換,但你需要為短碼和塊提供自定義規則。

步驟 3:遷移媒體

import { createClient } from '@supabase/supabase-js'
import fetch from 'node-fetch'

async function migrateMedia(mediaItems: any[]) {
  for (const item of mediaItems) {
    const response = await fetch(item.source_url)
    const buffer = await response.buffer()
    
    const { error } = await supabase.storage
      .from('media')
      .upload(`uploads/${item.slug}.${item.mime_type.split('/')[1]}`, buffer, {
        contentType: item.mime_type,
      })
    
    if (error) console.error(`Failed to upload ${item.slug}:`, error)
  }
}

使用 Next.js 構建新前端

將數據放入 Supabase 後,構建前端是有趣的部分。這是使用 Next.js 應用路由器的典型博客文章頁面:

// src/app/blog/[slug]/page.tsx
import { createClient } from '@/lib/supabase/server'
import { notFound } from 'next/navigation'
import { MDXRemote } from 'next-mdx-remote/rsc'

export async function generateMetadata({ params }: { params: { slug: string } }) {
  const supabase = createClient()
  const { data: post } = await supabase
    .from('posts')
    .select('title, excerpt, og_image')
    .eq('slug', params.slug)
    .single()

  if (!post) return {}

  return {
    title: post.title,
    description: post.excerpt,
    openGraph: { images: [post.og_image] },
  }
}

export default async function BlogPost({ params }: { params: { slug: string } }) {
  const supabase = createClient()
  const { data: post } = await supabase
    .from('posts')
    .select('*')
    .eq('slug', params.slug)
    .eq('status', 'published')
    .single()

  if (!post) notFound()

  return (
    <article className="prose lg:prose-xl mx-auto">
      <h1>{post.title}</h1>
      <time dateTime={post.published_at}>
        {new Date(post.published_at).toLocaleDateString()}
      </time>
      <MDXRemote source={post.content} />
    </article>
  )
}

注意沒有緩存外掛、沒有性能外掛、沒有 SEO 外掛。元數據 API 處理 SEO。伺服器組件處理性能。CDN 處理緩存。一切都是內置的。

將 Supabase 設置為後端

你的 Supabase 架構應該圍繞你的實際數據需求設計,而不是 WordPress 的通用 wp_posts / wp_postmeta 結構。這是一個更清晰的架構:

-- 文章表
create table posts (
  id uuid default gen_random_uuid() primary key,
  title text not null,
  slug text unique not null,
  content text,
  excerpt text,
  featured_image text,
  status text default 'draft' check (status in ('draft', 'published', 'archived')),
  author_id uuid references auth.users(id),
  published_at timestamptz,
  created_at timestamptz default now(),
  updated_at timestamptz default now(),
  metadata jsonb default '{}'
);

-- 分類
create table categories (
  id uuid default gen_random_uuid() primary key,
  name text not null,
  slug text unique not null,
  description text
);

-- 行級安全
alter table posts enable row level security;

create policy "Published posts are viewable by everyone"
  on posts for select
  using (status = 'published');

create policy "Authors can manage their own posts"
  on posts for all
  using (auth.uid() = author_id);

metadata jsonb 列是你的逃生艙。任何不值得擁有自己列的自定義字段都可以存在於此。它被索引、可查詢和無限靈活——喜歡 ACF 字段但沒有外掛。

處理身份驗證和用戶數據

如果你的 WordPress 網站有用戶帳戶,Supabase 身份驗證乾淨地處理遷移。你無法遷移密碼哈希(WordPress 使用 phpass,Supabase 使用 bcrypt),但你可以:

  1. 將用戶電子郵件和個人資料導入 Supabase
  2. 在首次登錄時為所有用戶觸發「重置密碼」流程
  3. 或使用魔法鏈接身份驗證,因此無需密碼

Supabase 支持電子郵件/密碼、Google、GitHub、Apple 和開箱即用的數十個其他 OAuth 提供商。無需外掛。

SEO 保留:不要失去你建立的東西

這是不可協商的。拙劣的遷移可以在一夜之間摧毀多年的 SEO 資產。這是檢查清單:

  1. 將每個舊 URL 映射到其新 URL。 WordPress 默認使用 /2024/01/post-title/。你的新網站可能使用 /blog/post-title。每個舊 URL 都需要一個 301 重定向。

  2. 在 Next.js 中實施重定向:

// next.config.js
module.exports = {
  async redirects() {
    return [
      // 基於日期的 WordPress URL 以清除 slug
      {
        source: '/:year(\\d{4})/:month(\\d{2})/:slug',
        destination: '/blog/:slug',
        permanent: true,
      },
      // 分類頁面
      {
        source: '/category/:slug',
        destination: '/blog/category/:slug',
        permanent: true,
      },
    ]
  },
}
  1. 保留所有元標題、描述和結構化數據。 在遷移前從 Yoast 匯出它們。
  2. 在啟動後立即向 Google Search Console 提交新的站點地圖。
  3. 在子域 (old.yoursite.com) 上繼續執行舊網站 30 天作為後備。

性能基準:前後對比

這是 Social Animal 遷移項目中的實際數字(這些是遷移項目中的平均值):

指標 WordPress(之前) Next.js + Supabase(之後) 改進
Lighthouse 性能分數 38 94 +147%
最大內容繪製 (LCP) 4.2 秒 0.9 秒 -79%
首次輸入延遲 (FID) 180 毫秒 12 毫秒 -93%
累積佈局偏移 (CLS) 0.25 0.02 -92%
首字節時間 (TTFB) 1.8 秒 0.15 秒 -92%
總頁面權重 3.2MB 420KB -87%
HTTP 請求 47 8 -83%

這些不是精心挑選的。它們是一致的。當你消除 30+ 個外掛,每個都注入自己的 CSS 和 JS,並在全球 CDN 上用靜態/伺服器呈現的 React 組件替換動態 PHP 呈現時,結果是可預測的。

如果你對這些結果對你的項目的影響感到好奇,我們的定價頁面 詳細說明了無頭式遷移項目通常成本多少。

成本比較:WordPress vs 無頭式技術棧

WordPress(年度) Next.js + Supabase(年度)
主機 $1,200 - $6,000(WP Engine/Kinsta) $0 - $240(Vercel Pro)
數據庫/後端 託管主機中包含 $0 - $300(Supabase Pro)
外掛許可證 $1,500 - $4,000 $0
安全工具 $300 - $500 $0(內置)
CDN $0 - $600 $0(Vercel 中包含)
維護開發工時 $6,000 - $18,000 $1,000 - $4,000
總計 $9,000 - $29,100 $1,000 - $4,540

無頭式技術棧的年度運營成本便宜 70-85%。遷移本身有前期成本,很明顯——通常對於專業構建,複雜性取決於 $15,000-$60,000(有關詳細信息,請參閱我們的 無頭式 CMS 開發服務)。但它在 6-18 個月內通過降低運營成本償付,在你考慮更好的性能和 SEO 的收入影響之前。

常見問題

遷移後我是否需要學習 React/Next.js 來管理我的內容? 否。大多數團隊將 Next.js 與無頭式 CMS(如 Sanity、Contentful 或 WordPress 本身使用純無頭式 CMS)配對(通過其 REST API)。內容編輯器從不接觸代碼。他們得到一個乾淨的編輯界面,前端通過 API 拉取內容。如果你想保留你的團隊已經知道的 WordPress 編輯器,你絕對可以——只需移除 WordPress 前端並將其用作內容後端。

典型的 WordPress 到 Next.js 遷移需要多長時間? 對於以內容為重點的網站,包括博客和標準頁面:4-6 週。對於具有電子商務、用戶帳戶、自定義文章類型和複雜功能的網站:8-14 週。最大的變數是內容複雜性——具有大量短代碼依賴內容或深度自定義 Gutenberg 塊的網站需要更長時間來乾淨地遷移。

在遷移期間我會失去我的 Google 排名嗎? 不,如果你正確處理重定向。301 重定向保留約 90-99% 的鏈接資產。我們通常在遷移後的前 1-2 週看到排名小幅下降(Google 需要重新爬取),然後由於更好的核心網頁活力分數而排名改進。關鍵是映射每個單一 URL,並且在啟動前不啟動直到你的重定向地圖完整。

Supabase 對於高流量網站是否已做好生產準備? 是的。Supabase 在 AWS 基礎設施上執行,並已被處理數百萬請求的公司在生產中使用。他們的數據庫只是 PostgreSQL——可以說是現存最經過戰鬥測試的數據庫。Supabase 服務超過 100 萬個數據庫,每天處理數十億個 API 請求。要獲得額外的規模,他們的專業($25/月)和團隊($599/月)計畫包括專用資源和優先支援。

我能將 WooCommerce 遷移到此技術棧嗎? 你可以,但電子商務增加了重大複雜性。大多數從 WooCommerce 遷移的團隊要麼去 Shopify(使用 Storefront API 與 Next.js 前端),要麼去開源解決方案,如 Medusa.js 或 Saleor。Supabase 可以處理產品目錄和訂單管理,但你需要自己構建結帳、付款處理、庫存管理和稅收計算。對於大多數業務,使用專用電子商務後端並將其連接到 Next.js 更有意義。

WordPress 多網站——此技術棧能替換它嗎? 絕對地。Next.js 對多租戶架構有出色的支持,使用中間件和動態路由。Supabase 的行級安全使按租戶分區數據變得簡單。我們已經將 50+ 個網站的 WordPress 多網站網絡遷移到單個 Next.js 應用,具有特定於租戶的路由,運營簡化非常巨大。

我仍然需要 CMS,還是我可以直接使用 Supabase? Supabase 為開發人員提供了一個表編輯器,但內容編輯器通常希望更精美的東西。最常見的方法是:(1) 使用專用無頭式 CMS(如 Sanity 或 Storyblok)用於內容和 Supabase 用於應用數據,(2) 構建一個簡單的管理 UI,使用 Next.js + Supabase 身份驗證,或 (3) 將 WordPress 保持為無頭式 CMS 後端。對於以內容為重點的網站,選項 1 最受歡迎。如果你探索選項,我們在我們的 Astro 開發無頭式 CMS 頁面上分解了權衡。

如果遷移出錯了怎麼辦——我能回滾到 WordPress 嗎? 是的,你應該規劃這個。在整個遷移過程中,在子域上執行你的 WordPress 網站。使用 DNS 級交換機(更改你的 A 記錄或 CNAME),所以你可以在幾分鐘內回滾。我們建議在啟動後至少 30 天保持舊 WordPress 實例執行。只有在確認所有重定向有效、搜索排名穩定且所有功能已驗證後才停用它。如果你想幫助規劃具有適當回滾程序的遷移,聯絡我們的團隊——我們已經做過足夠的次數,知道陷阱在哪裡。