Bypass WordPress Database: How to Fetch Static JSON with Zero-Config CORS 封面圖片

aritrhk

你決定用 Next.js 或 Astro 這類現代前端框架建置無頭 WordPress 站點。聽起來是很好的開發體驗——直到你遇到兩個惡名昭彰的障礙:

  1. CORS 地獄:你在 http://localhost:4321http://localhost:3000 啟動本機開發伺服器,發出 fetch 請求,然後……轟!你的瀏覽器主控台瞬間被紅色 CORS 政策錯誤淹沒。
  2. 遲緩的 REST API:標準的 WordPress REST API 或 WPGraphQL 每次請求都會啟動整個 WordPress 核心並查詢 MySQL。回應時間徘徊在 300ms 至 1s 之間,拖慢建置速度,也讓動態伺服端擷取變得緩慢。

如果你能把 WordPress 變成靜態 JSON 產生器、即時提供 API 酬載而不需資料庫查詢,並直接從管理後台管理 CORS 標頭,零伺服器設定,會如何?

以下是使用開源外掛 Static JSON Export & CORS Whitelist 在 1 分鐘內完成的方法。


曾考慮的其他標題

  • How to solve WordPress CORS issues in 1 minute with Astro / Next.js
  • Bypass WordPress Database: How to Fetch Static JSON with Zero-Config CORS(已選)
  • The Clean Way to Headless WordPress: Static JSON + Zero-SDK Plugin

原理說明:靜態 JSON 與動態資料庫查詢的比較

在傳統無頭架構中,前端每次請求都會查詢資料庫:

[Traditional REST API]
Frontend Fetch ──> Boot WordPress ──> Run MySQL Queries ──> Format JSON ──> Return Payloads (200-500ms)

Enter fullscreen mode Exit fullscreen mode

使用靜態 JSON 匯出架構,資料庫將被繞過:

[Static JSON Export]
Content Updated ──> Write Static JSON files in Background
Frontend Fetch  ──> WordPress REST Endpoint  ──> Directly Load JSON file ──> Return Payloads (30-50ms)

Enter fullscreen mode Exit fullscreen mode

由於 JSON 會在發布時預先渲染,因此在提供供稿時資料庫查詢次數為 ,大幅降低流量高峰時的伺服器負載。


1 分鐘 WordPress 設定

  1. 在官方 WordPress 外掛目錄搜尋並安裝 Static JSON Export & CORS Whitelist
  2. 在儀表板中開啟 JSON Export CORS 設定頁面。
  3. CORS Allowed Origins 清單中,加入你的開發網址(例如 http://localhost:4321http://localhost:3000)。
  4. JSON Feeds Settings 中,新增一個名為 posts 的供稿,對應 post 內容類型,然後點擊 Save Settings

外掛會立即將你的文章匯出為靜態 JSON 檔案。你將獲得兩個乾淨的端點:

  • 供稿索引https://your-wp.com/wp-json/sjec/v1/feed?name=posts
  • 單篇文章細節https://your-wp.com/wp-json/sjec/v1/post?feed=posts&slug=hello-world

連接前端

以下是在 Astro 與 Next.js 中使用這個乾淨、已啟用 CORS 的靜態 JSON 供稿的簡單範例。

範例 A:Astro(靜態站點產生)

Astro 以靜態為優先的做法,與靜態 JSON 供稿完美契合。

---
// src/pages/index.astro
interface Post {
  id: number;
  title: string;
  slug: string;
  excerpt: string;
  date: string;
}

// Fetch the static JSON feed (no DB queries executed on WP)
const response = await fetch('https://your-wordpress-site.com/wp-json/sjec/v1/feed?name=posts');
if (!response.ok) {
  throw new Error('Failed to fetch posts');
}
const posts: Post[] = await response.json();
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Fast Headless Astro Blog</title>
  </head>
  <body class="max-w-3xl mx-auto py-12 px-4 bg-slate-50 text-slate-800">
    <header class="mb-12">
      <h1 class="text-4xl font-extrabold">Lightning-Fast Headless Blog</h1>
      <p class="text-slate-500 mt-2">Bypassing WordPress database queries using pre-generated static JSON feeds.</p>
    </header>

    <main class="space-y-6">
      {posts.map((post) => (
        <article class="p-6 bg-white rounded-lg shadow-sm border border-slate-100 hover:shadow-md transition">
          <h2 class="text-2xl font-bold text-indigo-600 hover:underline">
            <a href={`/blog/${post.slug}`}>{post.title}</a>
          </h2>
          <p class="text-slate-600 mt-3" set:html={post.excerpt} />
          <time class="text-xs text-slate-400 block mt-4">
            Published: {new Date(post.date).toLocaleDateString()}
          </time>
        </article>
      ))}
    </main>
  </body>
</html>

Enter fullscreen mode Exit fullscreen mode


範例 B:Next.js(App Router - 增量靜態再生)

Next.js 會自動快取靜態 JSON 檔案並以高效率提供。

// app/blog/page.tsx
export const revalidate = 600; // Cache for 10 minutes

interface WordPressPost {
  id: number;
  title: string;
  slug: string;
  excerpt: string;
  date: string;
}

export default async function BlogIndexPage() {
  const res = await fetch('https://your-wordpress-site.com/wp-json/sjec/v1/feed?name=posts', {
    next: { revalidate: 600 }
  });

  if (!res.ok) {
    throw new Error('Failed to fetch static feed');
  }

  const posts: WordPressPost[] = await res.json();

  return (
    <div className="max-w-4xl mx-auto py-12 px-6">
      <h1 className="text-3xl font-bold mb-8">Next.js + Static JSON Feeds</h1>
      <div className="space-y-6">
        {posts.map((post) => (
          <div key={post.id} className="p-6 bg-white border border-slate-200 rounded-lg shadow-sm">
            <h2 className="text-2xl font-bold">
              <a href={`/blog/${post.slug}`} className="text-blue-600 hover:text-blue-800 hover:underline">
                {post.title}
              </a>
            </h2>
            <div 
              className="text-slate-600 mt-2" 
              dangerouslySetInnerHTML={{ __html: post.excerpt }} 
            />
            <span className="text-xs text-slate-400 mt-4 block">
              Published: {new Date(post.date).toLocaleDateString()}
            </span>
          </div>
        ))}
      </div>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode


效能基準測試

我們在本地環境下比較了標準 WP REST API 與此外掛的回應速度:

路由 / 方法 平均回應時間 資料庫負載 備註
Standard WP REST API ~320 ms 高(啟動 WP + 查詢 MySQL) 速度慢,在負載下容易崩潰
This Plugin (Free Version) ~35 ms 零 (0) 透過 WP REST 提供已儲存的 JSON
This Plugin (PRO Version) <1 ms 零 (0) 透過獨立的 api.php 完全繞過 WP Core

即使是免費版本,也能將回應延遲降低約 90%,並完全消除資料庫查詢,確保你的主機伺服器保持穩定。


🧼 100% 乾淨:無追蹤 SDK、無臃腫

WordPress 目錄中的許多免費外掛都包含第三方行銷 SDK(如 Freemius)來收集使用者追蹤資料。這通常會在管理後台塞滿惱人的升級橫幅。

為了尊重開發環境,此外掛的免費版本完全不含 SDK:

  • 無追蹤器或動態外部腳本。
  • 無侵入式升級通知或行銷彈窗。
  • 輕量級程式碼庫,100% 符合 WordPress.org 提交規範。

若你日後需要高效能功能(如獨立的 api.php 端點、多個自訂供稿或 Webhook 自動觸發),可以另外購買並下載 PRO 版本。


後續步驟

若要在 60 秒內嘗試此設定,請查看:

你是否曾建置無頭 WordPress 站點?你用了什麼方法解決 CORS 並加速 API 回應?歡迎在留言區討論!