WordPress REST API 宇宙大爆炸:從零開始打造你的第一個自訂端點!

2025/07/22 | WP 開發技巧

WordPress REST API 宇宙大爆炸:從零開始打造你的第一個自訂端點!

嗨,我是浪花科技的 Eric。身為一個整天跟程式碼打交道的工程師,我最常被問到的問題之一就是:「Eric,WordPress 內建的 REST API 很好用,但如果我想拿一些它沒有提供的資料,或是想自己組合一個特別的資料格式,該怎麼辦?」

問得好!這就好像你買了一台性能超強的電腦,但原廠附的軟體總有那麼點不順手。你當然不會就此罷休,而是會開始安裝自己需要的工具、調整設定,把它打造成專屬於你的戰鬥機。WordPress REST API 也是一樣的道理。它給了我們一個強大的基礎,但真正的威力,在於我們如何去「擴充」它。今天,我就要帶你捲起袖子,從零開始,深入 WordPress REST API 自訂端點開發 的世界,打造出完全符合你需求的 API!

為何要自訂 WordPress REST API 端點?罐頭 API 不夠香嗎?

你可能會想,WordPress 不是已經內建了文章、頁面、使用者等等的 API 了嗎?為什麼我們還需要自己動手做?這問題的答案,通常藏在你的專案需求裡。身為工程師,我們最討厭的就是「繞路」。

讓我舉幾個血淋淋的例子:

  • Headless WordPress 應用: 當你用 React 或 Vue 這類前端框架來做網站時,你需要的可能不是整個文章物件,而是精簡過的「標題、特色圖片、摘要」組合包,甚至還想順便把作者的頭像一起打包。內建 API 可能要你發好幾個請求才能湊齊資料,但自訂端點可以一次搞定。
  • 手機 App 整合: 你的 App 可能需要一個特別的端點來處理會員登入、個人資料更新,或是讀取客製化的活動列表。這些商業邏輯,內建 API 根本不可能知道。
  • 第三方服務串接: 假設你要把網站訂單即時拋送到 ERP 系統。你需要一個高度客製化、包含特定安全驗證的端點來接收資料,而不是讓 ERP 去遷就 WordPress 的資料結構。
  • 效能考量: 內建 API 為了通用性,回傳的資料包山包海。但在某些情境下,你只需要一兩個欄位。自訂端點可以精準地只回傳你需要的資料,大幅減少網路傳輸量,提升前端載入速度。這對斤斤計較效能的工程師來說,簡直是福音!

簡單來說,當你需要「特定格式的資料」、「執行特定商業邏輯」或「嚴格的權限控管」時,就是自訂端點上場救援的最佳時機。

REST API 自訂端點的核心:認識 register_rest_route()

好了,理論說完了,該來點硬核的了。在 WordPress 的世界裡,要註冊一個新的 API 端點,我們只需要認識一個函式:register_rest_route()。所有魔法都圍繞著它發生。這個函式通常會掛載在 rest_api_init 這個 action hook 上。

它的基本結構長這樣:

add_action( 'rest_api_init', function () {
  register_rest_route( $namespace, $route, $args );
});

參數拆解:Namespace, Route, 和最重要的 Args

我們來一個個拆解這三個參數,搞懂它們,你就等於掌握了 80% 的精髓。

  • $namespace (命名空間): 這就像是你的 API 的姓氏。例如 wp/v2 就是 WordPress 官方的命名空間。我們自訂時,通常會用「外掛名稱/版本號」的格式,例如 'my-awesome-plugin/v1'。這能有效避免跟其他外掛或核心功能衝突,也是一個好習慣。拜託,千萬別亂取或不取,不然以後專案變大,你會哭著回來找我。
  • $route (路由): 這就是你的 API 的名字,也就是 URL 的路徑。例如 /posts/book/(?P<id>\d+)。這裡可以用正規表示法 (Regex) 來捕捉 URL 中的變數,像 (?P<id>\d+) 就是用來抓取一個名為 `id` 的數字。
  • $args (參數陣列): 這是最關鍵的部分,它是一個陣列,用來定義這個端點的行為。裡面有幾個重要的鍵:
    • methods: HTTP 請求方法,可以是 'GET', 'POST', 'PUT', 'DELETE',或是它們的組合陣列。例如 ['GET', 'POST']
    • callback: 當這個端點被請求時,要執行的 PHP 函式。所有的資料處理、商業邏輯都在這裡。這是我們的大腦。
    • permission_callback: 權限檢查函式。它會在 `callback` 執行之前被呼叫,用來判斷當前使用者是否有權限訪問這個端點。這是我們的保鑣,非常非常重要!沒寫好等於大門敞開。

實戰教學:一步步打造你的第一個自訂端點

光說不練假把戲。我們來實作一個簡單的需求:建立一個 API 端點,用來獲取特定「書籍 (Book)」這個自訂文章類型 (CPT) 的書名和作者。

Step 1: 註冊你的 API 命名空間與路由

假設我們已經有一個叫 `book` 的 CPT。現在,我們在主題的 `functions.php` 或是一個自訂外掛中,加入以下程式碼。

add_action( 'rest_api_init', 'roamer_tech_register_book_routes' );

function roamer_tech_register_book_routes() {
    register_rest_route( 'roamer-tech/v1', '/book/(?P<id>\d+)', array(
        'methods'  => 'GET',
        'callback' => 'roamer_tech_get_book_data',
    ) );
}

這段程式碼的意思是:我們註冊了一個路徑為 /roamer-tech/v1/book/<書本ID> 的端點,它只接受 GET 請求,並且會呼叫 roamer_tech_get_book_data 這個函式來處理。

Step 2: 撰寫資料處理的核心 Callback 函式

接下來,我們要來實作 roamer_tech_get_book_data 這個函式。這個函式會接收一個 WP_REST_Request 物件作為參數,我們可以從中取得 URL 上的變數。

function roamer_tech_get_book_data( WP_REST_Request $request ) {
    // 從請求中獲取 URL 上的 id 參數
    $book_id = $request->get_param( 'id' );

    // 根據 ID 獲取文章物件
    $post = get_post( $book_id );

    // 檢查文章是否存在,以及文章類型是否為 'book'
    if ( empty( $post ) || 'book' !== $post->post_type ) {
        // 如果找不到書,回傳一個 WP_Error 物件,並帶上 404 狀態碼
        return new WP_Error( 'book_not_found', '找不到指定的書籍', array( 'status' => 404 ) );
    }

    // 假設作者資訊存在一個叫做 'book_author' 的 meta field
    $author = get_post_meta( $book_id, 'book_author', true );

    // 準備要回傳的資料
    $response_data = array(
        'id'     => $post->ID,
        'title'  => $post->post_title,
        'author' => $author ? $author : '未知作者',
    );

    // 使用 WP_REST_Response 來包裝回傳的資料,這是最佳實踐!
    return new WP_REST_Response( $response_data, 200 );
}

注意到了嗎?我們不是直接 `echo json_encode()`,而是回傳一個 WP_REST_ResponseWP_Error 物件。這是標準做法,WordPress 會幫我們處理好 HTTP 狀態碼和 Headers。拜託,寫專業的 API 就該這樣,別再用土炮方法了。

Step 3: 加上權限控管的守門員 permission_callback

現在我們的端點任何人都能存取。但如果這是機密資料呢?我們需要加上權限檢查。修改一下 `register_rest_route` 的程式碼:

register_rest_route( 'roamer-tech/v1', '/book/(?P<id>\d+)', array(
    'methods'             => 'GET',
    'callback'            => 'roamer_tech_get_book_data',
    'permission_callback' => function () {
        // 只允許登入的使用者,且具備 'edit_posts' 權限的人存取
        return current_user_can( 'edit_posts' );
    }
) );

在這裡,我用了一個匿名函式。permission_callback 必須回傳 `true` 或 `false`。如果回傳 `false`,請求會直接被擋掉,並回傳 401 或 403 錯誤,連 `callback` 函式都不會執行。你也可以回傳一個 `WP_Error` 物件來自訂錯誤訊息。這層防護絕對不能省!

進階技巧:讓你的 API 更專業、更安全

掌握了基本功,我們再來聊聊幾個能讓你 API 水平三級跳的進階技巧。

處理 POST/PUT 請求:不只讀取,還要能寫入!

如果我們要建立一本新書呢?我們可以註冊一個 `POST` 方法的端點。

register_rest_route( 'roamer-tech/v1', '/book', array(
    'methods'             => 'POST',
    'callback'            => 'roamer_tech_create_book',
    'permission_callback' => function() {
        return current_user_can( 'publish_posts' );
    },
) );

function roamer_tech_create_book( WP_REST_Request $request ) {
    // 從 POST 的 body 中取得 JSON 參數
    $params = $request->get_json_params();
    $title = sanitize_text_field( $params['title'] );
    $author = sanitize_text_field( $params['author'] );

    // ... 這裡可以加上更多參數驗證 ...

    $post_id = wp_insert_post( array(
        'post_title'   => $title,
        'post_type'    => 'book',
        'post_status'  => 'publish',
    ) );

    if ( is_wp_error( $post_id ) ) {
        return $post_id; // 直接回傳 WP_Error 物件
    }

    update_post_meta( $post_id, 'book_author', $author );

    return new WP_REST_Response( array('id' => $post_id, 'message' => '書籍建立成功'), 201 );
}

參數驗證與清理:別讓髒資料污染你的系統

在 `register_rest_route` 的 `$args` 裡,還有一個 `args` 鍵可以定義接收的參數規則。這才是真正專業的做法!

register_rest_route( 'roamer-tech/v1', '/book', array(
    'methods'  => 'POST',
    'callback' => 'roamer_tech_create_book_with_validation',
    'args'     => array(
        'title' => array(
            'required'          => true,
            'validate_callback' => function( $param, $request, $key ) {
                return is_string( $param ) && ! empty( $param );
            },
            'sanitize_callback' => 'sanitize_text_field',
        ),
        'author' => array(
            'required'          => false,
            'default'           => '匿名',
            'sanitize_callback' => 'sanitize_text_field',
        ),
    ),
) );

透過定義 `args`,WordPress 會自動幫我們做掉大部分的驗證、清理和預設值設定。我們的 `callback` 函式就可以變得更乾淨,專注在核心業務邏輯上。這才是工程師該有的優雅!

經過這樣一番操作,你已經不只是一個會用 API 的人,而是一個能創造 API 的開發者了。從簡單的資料查詢,到複雜的資料寫入與驗證,你都能一手掌握。這不論是在開發 Headless 應用、串接外部服務,或是打造更強大的外掛功能時,都會是你手中最強大的武器。

結語

今天我們從為什麼需要自訂端點開始,一路深入到 register_rest_route 的核心,並透過實戰範例,學會了如何建立、保護和優化我們的 API。WordPress REST API 的彈性遠不止於此,它就像一個樂高宇宙,等著我們去發掘和創造。

記住,好的 API 設計不僅僅是讓程式能動,更要考慮到安全性、效能和未來的擴充性。希望今天的分享能為你打開一扇新的大門。如果你在開發過程中遇到任何瓶頸,或是有更複雜的串接需求,別忘了,浪花科技的團隊永遠是你最堅實的後盾。

對於更進階的 REST API 設計原則,或是如何處理 CPT,你可以參考我們之前的文章:

有任何關於 WordPress 企業級開發、API 串接,或是網站效能優化的疑難雜症嗎?不要猶豫,立即聯繫浪花科技,讓我們專業的工程師團隊為你提供最頂尖的解決方案!

常見問題 (FAQ)

Q1: 什麼是 WordPress REST API 的 Namespace (命名空間)?為什麼它很重要?

A1: Namespace 像是你自訂 API 的一個獨特前綴或群組名稱,例如 `my-plugin/v1`。它的主要目的是「避免衝突」。想像一下,如果你的外掛和另一個外掛都註冊了 `/products` 這個路徑,系統就不知道該聽誰的了。使用 Namespace 可以確保你的 `/my-plugin/v1/products` 和別人的 `/their-plugin/v1/products` 和平共存。同時,它也利於版本管理,未來如果你要推出不相容的 API v2 版本,就可以用新的 Namespace `my-plugin/v2`,而不會影響到還在使用 v1 的舊應用。

Q2: `permission_callback` 和在 `callback` 函式開頭自己寫權限檢查,有什麼不同?

A2: 這是個很好的問題,關鍵在於「執行的時間點」和「職責分離」。`permission_callback` 是 WordPress REST API 流程中,專門用來處理權限的「官方守門員」。它會在執行任何主要邏輯(也就是 `callback` 函式)之前就被呼叫。如果權限不足,請求會立刻被中斷並回傳標準的 401/403 錯誤,效率更高也更安全。反之,若在 `callback` 函式內才檢查,代表程式碼已經開始執行,這不僅混合了權限和業務邏輯,也可能在權限檢查前意外執行了某些程式碼,有潛在風險。所以,請務必使用 `permission_callback` 來處理權限問題。

Q3: 我可以直接在 callback function 裡 `echo json_encode($data);` 嗎?為什麼要用 `WP_REST_Response`?

A3: 技術上你可以這樣做,但這是非常不推薦的「土炮」做法。使用 `WP_REST_Response` 物件是 WordPress 官方推薦的最佳實踐,原因有三:1. 狀態碼控制: 你可以精準設定 HTTP 狀態碼,例如成功是 200,建立資源是 201,找不到是 404。這對前端應用程式判斷 API 回應至關重要。 2. Headers 管理: 你可以輕易地新增或修改 HTTP Headers,例如快取控制的 Headers。 3. 一致性與擴充性: WordPress 核心會統一處理 `WP_REST_Response` 物件,確保回傳的 JSON 格式正確無誤,並且能和 API 基礎架構的其他部分(如嵌入連結)無縫協作。直接 `echo` 會繞過這整個流程,讓你的 API 變得不標準且難以維護。

 
立即諮詢,索取免費1年網站保固