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_Response 或 WP_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,你可以參考我們之前的文章:
- 別再寫出連自己都看不懂的 API!資深工程師的 WordPress REST API 設計原則終極指南
- 別再把 WordPress 當部落格!資深工程師手把手 CPT 實戰,打造真正客製化的網站後台
- 你的表單安全嗎?揭開 WordPress Nonces 的神秘面紗,杜絕 CSRF 攻擊的終極防線!
有任何關於 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 變得不標準且難以維護。






