WordPress Multisite 不是多站點:可擴展到 500 個位置的架構
WordPress Multisite 不是多站點架構:可擴展至 500 個位置的架構
WordPress Multisite 聽起來像是你會獲得多個站點。但實際上你得到的是一個 WordPress 安裝,它透過在數據庫表名稱前面添加一個數字來假裝是多個站點。你的主站點使用 wp_posts。子站點 2 使用 wp_2_posts。子站點 3 使用 wp_3_posts。這不是多站點架構。這是一個數據庫,其中包含相同表格的編號副本。而它有後果。
我已將具有 15、40 和一次 87 個子站點的網路從 WordPress Multisite 進行遷移。每一次,客戶都認為他們正在獲得獨立站點。每一次,他們都以艱難的方式發現他們並沒有。如果你在 WordPress Multisite 上運營加盟店、多地點業務或大學部門網路,這篇文章會有點令人不適。但現在了解要比子站點 #47 導致所有其他 46 個站點癱瘓之後才知道要好得多。
目錄
- WordPress Multisite 在後台實際做的事
- 假多站點架構的 7 個後果
- WordPress Multisite 何時有效(老實說)
- 實際上可擴展至 500 個位置的架構
- 架構比較:前綴表與行級安全性
- 實施:用於多位置站點的 Next.js + Supabase
- 遷移路徑:擺脫 WordPress Multisite
- 真實數字:性能和成本比較
- 常見問題

WordPress Multisite 在後台實際做的事
讓我們看看在 WordPress 中啟用 Multisite 時會發生什麼。你在 wp-config.php 中添加幾行程式碼:
define('WP_ALLOW_MULTISITE', true);
define('MULTISITE', true);
define('SUBDOMAIN_INSTALL', false);
define('DOMAIN_CURRENT_SITE', 'example.com');
define('PATH_CURRENT_SITE', '/');
define('SITE_ID_CURRENT_SITE', 1);
define('BLOG_ID_CURRENT_SITE', 1);
WordPress 隨後會建立幾個網路級別的表格(wp_blogs、wp_site、wp_sitemeta、wp_registration_log、wp_signups),並開始為每個新的子站點複製你的核心表格結構。
以下是在只有 5 個子站點後數據庫的樣子:
wp_posts (主站點)
wp_postmeta (主站點)
wp_options (主站點)
wp_users (共享 - 所有站點)
wp_usermeta (共享 - 所有站點)
wp_2_posts (子站點 2)
wp_2_postmeta (子站點 2)
wp_2_options (子站點 2)
wp_3_posts (子站點 3)
wp_3_postmeta (子站點 3)
wp_3_options (子站點 3)
...
wp_5_posts (子站點 5)
wp_5_postmeta (子站點 5)
wp_5_options (子站點 5)
五個子站點,你已經有大約 55 個表格。五十個子站點?你會看到一個 MySQL 數據庫中有超過 500 個表格。五百個位置?超過 5,000 個表格。在一個數據庫中。共享一個連接池。
每個表格都有自己的索引。每個查詢都針對一個特定的前綴表格。查詢規劃程式必須處理所有這些。而這些表格中的每一個都可由在該伺服器上運行的任何 PHP 進程訪問,因為它們都在具有相同憑據的同一數據庫中。
這不是多站點架構。這是一個偽裝成隔離的命名約定。
假多站點架構的 7 個後果
1. 共享漏洞表面
WordPress Multisite 網路中的每個子站點都運行相同的 WordPress 核心、相同的外掛和相同的主題。一個外掛漏洞會影響所有子站點,因為它們共享相同的程式碼庫。
這不是理論上的。在 2026 年 2 月,WPVivid —— 一個擁有超過 900,000 個活躍安裝的備份外掛 —— 披露了一個嚴重程度為 9.8 的 RCE(遠端程式碼執行)漏洞。嚴重程度滿分 10 中的 9.8。這是「未經驗證的攻擊者可以在你的伺服器上執行任意程式碼」的級別。
在獨立的 WordPress 站點上,這是一個被入侵的站點。在具有 30 個子站點的 Multisite 網路上?那是 30 個被入侵的站點。相同的伺服器。相同的數據庫。相同的檔案系統。一個漏洞,整個網路被入侵。
你不能在子站點 #12 上安裝不同版本的外掛,而在子站點 #13 上卻不能。你無法將一個位置的外掛沙箱化與另一個位置分離。每個站點都會獲得相同的攻擊表面。
2. 外掛衝突倍增
在單個 WordPress 站點上,外掛衝突會破壞一個站點。你停用外掛,診斷,然後繼續。令人煩惱但可控。
在 Multisite 上,網路啟用的外掛衝突會同時破壞每個站點。我見過一個 WooCommerce 更新在 Multisite 網路上導致 23 個位置頁面癱瘓,因為一個網路啟用的快取外掛還沒有針對新的 WooCommerce 掛鉤進行更新。23 個位置有破損頁面。一個根本原因,23 位憤怒的位置管理員打電話給同一個人。
而這是關鍵的地方 —— 個別站點管理員通常無法停用網路啟用的外掛。他們必須等待超級管理員修復它。
3. 性能退化
五十個子站點共享一個 MySQL 實例。子站點 #47 上的每個頁面加載都運行以下查詢:
SELECT * FROM wp_47_posts WHERE post_type = 'page' AND post_status = 'publish';
SELECT option_value FROM wp_47_options WHERE option_name = 'active_plugins';
SELECT * FROM wp_47_postmeta WHERE post_id IN (142, 143, 144, 145);
同時,子站點 #12 正在針對 wp_12_posts、wp_12_options 和 wp_12_postmeta 運行自己的一組查詢。每個其他子站點也是如此,所有這些都擊中相同的 MySQL 實例。
MySQL 的查詢規劃程式感到困惑。表格快取填滿。每個前綴表格都維護自己的索引,但緩衝池是共享的。隨著你添加更多子站點,性能會非線性退化。從 10 個子站點增加到 20 個不是兩倍的負載 —— 根據流量模式,由於鎖定爭用和緩衝池抖動,可能是三倍或四倍的負載。
我曾經基準化過一個 40 子站點網路。子站點 #1 上的平均查詢時間是 45 毫秒。當我們測試子站點 #38 時,平均查詢時間已經爬升至 380 毫秒。相同的查詢結構。每個站點相同的數據量。數據庫只是在被表格淹沒。
4. 遷移是一場噩夢
嘗試將子站點 #23 從 50 站點網路提取到它自己的獨立 WordPress 安裝中。以下是你需要做的事情:
- 導出所有
wp_23_前綴的表格 - 將每個表格從
wp_23_前綴重新映射到wp_前綴 - 重新序列化所有選項和小工具數據(WordPress 將序列化的 PHP 儲存在數據庫中,當你更改前綴時字符串長度會改變)
- 將媒體路徑從
/uploads/sites/23/重新映射到/uploads/ - 搜索並替換所有內部 URL
- 在
wp_usermeta中將用戶功能從wp_23_capabilities重新映射到wp_capabilities - 從共享的
wp_users表格中提取用戶(只有那些屬於子站點 #23 的用戶) - 重新建立用戶與站點的關係
序列化中出現一個錯誤,你就會得到被破壞的數據。小工具設置消失。主題自訂程式選項斷裂。菜單結構消失。我已經執行過數十次這個提取過程,即使使用 WP Migrate DB Pro 之類的工具,每個子站點也需要花費 4-8 小時。如果你正在停用網路,將其乘以 50 個子站點。
WordPress 生態系統對此有工具,當然。但是這些工具需要存在的事實告訴你關於架構的一些事情。
5. 沒有真正的數據隔離
這是那個應該會讓你害怕的一個,如果你關心安全性或合規性的話。
子站點 #2 上的 SQL 注入漏洞不只會暴露 wp_2_posts。連接到 MySQL 的數據庫用戶可以訪問數據庫中的每個表格。這意味著 wp_posts(主站點)、wp_3_posts(子站點 3)、wp_users(所有站點中的所有用戶)和其他所有表格。
沒有數據庫級別的隔離。沒有行級安全性。沒有模式分離。WordPress Multisite 是一個數據庫、一組憑據和一個命名約定。就是這樣。
對於在多個位置處理客戶數據的企業 —— 醫療辦公室、律師事務所、金融服務 —— 這是一個合規問題。HIPAA、SOC 2 和 PCI DSS 都對數據隔離有要求。「我們使用了不同的表格前綴」不會滿足審計員。
6. 超級管理員瓶頸
WordPress Multisite 有一個稱為超級管理員的角色。只有超級管理員可以:
- 安裝或刪除外掛
- 安裝或刪除主題
- 啟用網路範圍的外掛
- 向網路添加新站點
- 管理網路設置
個別站點管理員的能力受限。他們無法安裝自己的外掛。他們無法添加自己的主題。每個涉及共享基礎架構的更改都要經過一個人(或一個小團隊)。
對於 3 站點網路,這沒問題。對於 50 位置的加盟品牌,其中每個位置經理想要添加自己的預訂小工具或菜單 PDF 外掛?它是一個引起不滿和影子 IT 的瓶頸。
7. 域名映射脆弱性
想要每個位置有自己的域名?denver.yourbrand.com 或 yourbrand-denver.com?WordPress Multisite 不能以可靠的方式本地處理此問題。你需要域名映射解決方案,而內置的 sunrise.php dropin 方法以出了名地脆弱而聞名。
映射域名的 SSL 證書添加了另一層。DNS 配置添加了另一層。每個映射的域名都是另一個潛在故障點,你的超級管理員必須管理。一個 DNS 更改、一個過期的證書、一個錯誤配置的映射條目,一個位置的站點就會下線。
WordPress Multisite 何時有效(老實說)
我不打算假裝它毫無用處。WordPress Multisite 在特定場景中表現很好:
- 小型網路(低於 10 個站點),其中所有站點由同一團隊管理
- 大學部門站點,其中集中控制實際上是理想的
- 開發/測試/生產鏡像,用於同一項目
- 部落格網路,其中內容隔離不是關鍵
如果你有 5-8 個站點、一個稱職的系統管理員,並且你不需要站點之間的數據隔離 —— Multisite 很好。當你嘗試將其擴展到數十或數百個位置時,問題開始出現。

實際上可擴展至 500 個位置的架構
以下是我們在 Social Animal 為多位置企業使用的替代方法:一個無頭架構,前端使用 Next.js,後端使用 Supabase(PostgreSQL),使用行級安全性(RLS)實現真正的數據隔離。
核心想法:與其為每個位置複製表格,你擁有一組表格,帶有一個 location_id 列。數據庫級別的安全策略確保查詢只返回授權位置的數據。與其有 500 個獨立的 WordPress 安裝假裝是獨立的,你有一個應用程式部署,其中 /locations/[slug] 從數據庫行動態呈現每個位置的頁面。
行級安全性實際上如何運作
-- 建立位置表
CREATE TABLE locations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
slug TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
address TEXT,
phone TEXT,
hours JSONB,
metadata JSONB,
created_at TIMESTAMPTZ DEFAULT now()
);
-- 建立具有位置隔離的頁面表
CREATE TABLE pages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
location_id UUID REFERENCES locations(id),
title TEXT NOT NULL,
content JSONB,
slug TEXT NOT NULL,
published BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT now()
);
-- 啟用 RLS
ALTER TABLE pages ENABLE ROW LEVEL SECURITY;
-- 策略:位置管理員只能看到自己位置的頁面
CREATE POLICY "location_isolation" ON pages
FOR ALL
USING (location_id = (SELECT location_id FROM user_locations WHERE user_id = auth.uid()));
-- 策略:公眾可以閱讀任何位置的已發佈頁面
CREATE POLICY "public_read" ON pages
FOR SELECT
USING (published = true);
有了這個設置,丹佛的位置經理,即使不知何故製作了一個惡意查詢,從物理上也不能訪問奧斯汀的數據。數據庫強制執行它。不是應用程式層。不是命名約定。數據庫本身。
架構比較:前綴表與行級安全性
以下是兩種架構的視覺表示:
WordPress Multisite 架構:
┌─────────────────────────────────────────────┐
│ 單個 MySQL 數據庫 │
│ │
│ wp_posts (主站點) │
│ wp_options (主站點) │
│ wp_2_posts (丹佛) │
│ wp_2_options (丹佛) │
│ wp_3_posts (奧斯汀) │
│ wp_3_options (奧斯汀) │
│ wp_4_posts (西雅圖) │
│ wp_4_options (西雅圖) │
│ ... x 500 位置 = 5,000+ 表格 │
│ │
│ ⚠️ 一組數據庫憑據 │
│ ⚠️ 一個 PHP 進程訪問所有表格 │
│ ⚠️ 零數據庫級別隔離 │
└─────────────────────────────────────────────┘
Next.js + Supabase 架構:
┌─────────────────────────────────────────────┐
│ 單個 PostgreSQL 數據庫 │
│ │
│ locations (500 行,每個位置一個) │
│ pages (每個位置的內容) │
│ media (每個位置的圖像) │
│ staff (每個位置的團隊) │
│ reviews (每個位置的評論) │
│ │
│ ✅ RLS 策略強制隔離 │
│ ✅ 丹佛用戶無法查詢奧斯汀數據 │
│ ✅ 5 個表格總計,不是 5,000 │
│ ✅ 標準索引,最佳查詢計劃 │
└─────────────────────────────────────────────┘
兩種情況下都是一個數據庫。但隔離模型根本上不同。RLS 在 PostgreSQL 引擎級別強制執行 —— 不是應用程式可以繞過的東西。
| 因素 | WordPress Multisite | Next.js + Supabase |
|---|---|---|
| 500 位置時的表格 | ~5,500+ | ~5-15 |
| 數據隔離 | 無(僅命名約定) | 數據庫強制 RLS |
| 漏洞表面 | 一個漏洞 = 所有站點 | 按位置身份驗證隔離 |
| 外掛衝突 | 網路範圍內停機 | 不適用(無外掛架構) |
| 添加位置 | 建立子站點 + 配置 | 插入數據庫行 |
| 移除位置 | 複雜提取過程 | 刪除帶有 CASCADE 的行 |
| 域名映射 | 需要外掛,脆弱 | 中間件重寫,原生 |
| 構建/部署時間 | 不適用(運行時 PHP) | ~30 秒增量構建 |
| TTFB(平均,無快取) | 800 毫秒 - 2 秒+ | 50-150 毫秒(邊緣) |
| 每月託管(500 個站點) | $200-800/月(託管 WP) | $25-75/月(Supabase + Vercel) |
| 從入侵恢復 | 完整網路修復 | 輪換金鑰,重新部署 |
實施:用於多位置站點的 Next.js + Supabase
以下是使用 Next.js 在實踐中路由的工作方式:
// app/locations/[slug]/page.tsx
import { createClient } from '@/lib/supabase/server';
import { notFound } from 'next/navigation';
export async function generateStaticParams() {
const supabase = createClient();
const { data: locations } = await supabase
.from('locations')
.select('slug');
return locations?.map(({ slug }) => ({ slug })) ?? [];
}
export default async function LocationPage({
params
}: {
params: { slug: string }
}) {
const supabase = createClient();
const { data: location } = await supabase
.from('locations')
.select(`
*,
pages(*),
staff(*),
reviews(*, rating)
`)
.eq('slug', params.slug)
.single();
if (!location) notFound();
return (
<div>
<h1>{location.name}</h1>
<LocationHero location={location} />
<LocationServices pages={location.pages} />
<LocationTeam staff={location.staff} />
<LocationReviews reviews={location.reviews} />
</div>
);
}
添加新位置?插入一行:
INSERT INTO locations (slug, name, address, phone, hours)
VALUES (
'portland-or',
'Portland, OR',
'123 Burnside St, Portland, OR 97209',
'(503) 555-0142',
'{"mon": "9-5", "tue": "9-5", "wed": "9-5"}'
);
就是這樣。下一個構建會選擇它。或者如果你使用 ISR(增量靜態再生),它會在你的再驗證窗口內顯示,無需構建。
移除位置?DELETE FROM locations WHERE slug = 'portland-or'; 級聯刪除會處理其餘的。沒有 4-8 小時的提取過程。
對於每個位置的自訂域名,Next.js 中間件乾淨地處理它:
// middleware.ts
import { NextResponse } from 'next/server';
const DOMAIN_MAP: Record<string, string> = {
'yourbrand-denver.com': '/locations/denver-co',
'yourbrand-austin.com': '/locations/austin-tx',
// ... 在生產中從邊緣配置加載
};
export function middleware(request: Request) {
const hostname = new URL(request.url).hostname;
const rewritePath = DOMAIN_MAP[hostname];
if (rewritePath) {
return NextResponse.rewrite(new URL(rewritePath, request.url));
}
return NextResponse.next();
}
沒有外掛。沒有 sunrise.php dropin。沒有脆弱的映射表。只是邊緣的重寫規則。
遷移路徑:擺脫 WordPress Multisite
如果你目前在 WordPress Multisite 上有 20 個以上的位置,以下是現實的遷移路徑:
第 1 階段:數據導出(1-2 週)
使用 WordPress REST API 或 WP-CLI 從每個子站點導出內容。不要嘗試手動重新映射前綴表格。使用 API —— 它抽象了前綴的噩夢。
# 從子站點 23 導出所有帖子
wp post list --url=example.com/location-23 --format=json > location-23-posts.json
# 導出所有媒體
wp media list --url=example.com/location-23 --format=json > location-23-media.json
第 2 階段:模式設計(1 週)
圍繞你的實際內容模型而不是 WordPress 的帖子/postmeta 模型設計你的 Supabase 模式。這是修復多年積累的數據模型技術債務的時刻。
第 3 階段:內容遷移(1-2 週)
編寫遷移腳本,將 WordPress 內容轉換為你的新模式。處理序列化數據、短代碼和古騰堡塊。
第 4 階段:前端構建(3-4 週)
構建 Next.js 前端。這是你看到實際性能收益的地方。在 WordPress 上耗時 1.5 秒的頁面現在在 200 毫秒以下加載。
第 5 階段:DNS 切換(1 天)
將你的域名指向新基礎架構。保持舊網路作為 30 天的唯讀備份運行。
對於需要此遷移過程幫助的企業,我們已在我們的 無頭 CMS 開發頁面上記錄了我們的方法。我們已經做了足夠多的遷移來知道屍體埋在哪裡。
真實數字:性能和成本比較
以下是我們在 2025 年第 1 季度完成的實際遷移數據 —— 一個擁有 34 個位置的牙科診所網路:
| 指標 | WordPress Multisite(之前) | Next.js + Supabase(之後) |
|---|---|---|
| 平均 TTFB | 1,240 毫秒 | 89 毫秒 |
| 最大內容繪製 | 3.8 秒 | 1.1 秒 |
| 每月託管成本 | $347/月(WP Engine) | $45/月(Vercel Pro + Supabase Pro) |
| 添加新位置的時間 | 2-3 小時(手動設置) | 15 分鐘(插入行 + 內容) |
| 更新所有位置的時間 | 外掛更新 + 祈禱 | git push |
| 核心網路指標通過率 | 34 個位置中的 12 個 | 34 個位置中的 34 個 |
| 安全事件(12 個月) | 3 | 0 |
僅託管成本節省就在 8 個月內支付了遷移費用。性能改進在 90 天內為 28 個位置中的 34 個推動了可測量的本地搜索排名增加。
如果你正在為自己的網路評估成本,我們的 定價頁面對多位置項目有透明的細分。
常見問題
WordPress Multisite 適合管理多個位置嗎? 對於少量位置(低於 10 個)有集中管理,WordPress Multisite 可以工作。但它的設計初衷不是為了多位置企業需要獨立運營、數據隔離或大規模高性能。共享數據庫架構建立了安全、性能和運營問題,這些問題隨著你添加的每個位置而增加。
WordPress Multisite 的最大問題是什麼? 七個主要問題是:共享漏洞表面(一個漏洞擊中所有站點)、外掛衝突倍增(一個衝突導致每個站點停機)、非線性性能退化、噩夢般的遷移/提取過程、零數據庫級別的數據隔離、超級管理員瓶頸用於所有管理更改,以及脆弱的域名映射。這些問題是架構性的 —— 它們無法通過外掛或更好的託管來修復。
WordPress Multisite 可以處理 100 多個站點嗎? 從技術上講,是的。從實踐上講,超過 30-50 個站點會變得非常痛苦。在 100 個站點,你處理單個 MySQL 實例中 1,100 多個數據庫表,嚴重的查詢規劃程式退化,以及需要專門 DevOps 人員的操作複雜性。在 500 個站點,對於大多數託管環境來說,這是不可行的。
WordPress Multisite 的最佳替代方案是什麼,用於多個位置? 使用無頭架構,前端使用 Next.js 或 Astro,後端使用 PostgreSQL 數據庫(例如 Supabase),使用行級安全性提供真正的數據隔離,戲劇性地改進性能,降低託管成本,以及微不足道的位置管理。每個位置是一個數據庫行,而不是整個 WordPress 安裝。
你如何從 WordPress Multisite 遷移到無頭架構? 最安全的方法是通過 WordPress REST API 或 WP-CLI 而不是嘗試手動重新映射前綴表格來提取內容。按子站點導出內容,在目標數據庫中設計乾淨的模式,編寫轉換腳本,構建新前端,並切換 DNS。對於 20 個以上站點的網路,計劃總共需要 6-10 週。
WordPress Multisite 影響 SEO 嗎? 間接地,是的。WordPress Multisite 的性能退化導致頁面加載速度變慢,這會傷害核心網路指標得分。Google 已確認頁面體驗信號影響排名。在我們的遷移數據中,在遷移到具有低於 200 毫秒 TTFB 的無頭架構後 90 天內,82% 的位置看到了改進的本地搜索排名。
WordPress Multisite 對業務數據安全嗎? 否,如果你將安全定義為包括位置之間的數據隔離。WordPress Multisite 使用一個數據庫和一組憑據。任何子站點上的 SQL 注入都可以訪問每個其他子站點的數據。對於遵守 HIPAA、SOC 2、PCI DSS 或類似合規要求的企業,缺乏數據庫級別隔離是一個重大風險。
運行 WordPress Multisite 與無頭替代方案相比花費多少? Multisite 的託管 WordPress 託管通常運行 $200-800/月,取決於站點數量和流量級別(WP Engine 的 Multisite 計劃在 2025 年從其增長層 $240/月開始)。可比的無頭設置在 Vercel Pro ($20/月) 加上 Supabase Pro ($25/月) 上可以以成本的一小部分處理相同的流量。無頭方法的初始構建投資較高,但每月運營成本顯著降低。如果你想要針對你的網路規模的具體成本比較,請隨時 聯繫我們。