今天我想分享一下在開發一個 WooCommerce 自訂訂閱商品類型時,所遇到的一連串「卡關」經驗。這個過程就像在剝洋蔥,每解決一層問題,就會流著淚發現底下還有一層更深的挑戰。希望這篇紀錄能幫助到正在或未來將要踏上這條路的朋友們。
我們的目標很單純:建立一個名為「ORCA 訂閱商品」的自訂產品類型,它繼承自「簡單商品」,並擁有自己專屬的設定分頁。
記錄一下過程中踩到的bug
訂單產品類型無法存檔?為何自動被降級成「簡單商品」?
一切的起點,就是我發現無論怎麼設定,我的訂閱商品在儲存後,總是被 WooCommerce 無情地降級成「簡單商品」。後台的自訂分頁消失,一切都回到了原點。
經過追查 debug.log
,我們發現了第一個驚人的事實:WooCommerce 在某些內部流程中,傳遞給 woocommerce_product_class
filter 的 product_type
值,竟然是產品的顯示名稱(例如 URL 編碼後的「ORCA 訂閱商品」),而不是我們預期的 slug (orca_wooplus_subscription
)!
這導致我們的判斷式 if ( $product_type === 'orca_wooplus_subscription' )
永遠失敗,WooCommerce 因為找不到對應的 PHP 類別,只好安全地將它降級。
💡 解決方案:模仿 WooCommerce 的核心作法
我們回頭研究 WooCommerce 如何註冊 simple
、variable
等內建類型,發現了關鍵:
- 註冊 Term 時:使用
wp_insert_term
時,將name
和slug
設定為完全相同的英文值,例如orca_wooplus_subscription
。這統一了程式內部的識別碼。 - 加入下拉選單時:在
product_type_selector
這個 filter 中,才使用翻譯函式__()
將orca_wooplus_subscription
這個 key 對應到「ORCA 訂閱商品」這個 UI 上的顯示名稱。
這個修正,確保了無論 WooCommerce 內部傳遞的是 name
還是 slug
,我們收到的都會是 orca_wooplus_subscription
,成功解決編輯產品時無法綁定「ORCA 訂閱商品」
後台 UI 大崩壞,我的設定分頁們集體失蹤!
當產品類型終於被正確識別後,新的問題來了:除了我們自訂的「ORCA 訂閱設定」分頁,原本的「一般」、「庫存」等標準分頁全都消失了!
這是因為 WooCommerce 的後台 UI 是由 JavaScript 透過 CSS class 控制的。每個分頁和面板都帶有 show_if_simple
、show_if_variable
等 class。當產品類型切換到我們的 orca_wooplus_subscription
時,JS 找不到對應的 show_if_orca_wooplus_subscription
class,於是就把所有不相關的分頁都隱藏了。
💡 解決方案:用 JavaScript 賦予我們的類型「顯示權限」
我們透過 admin_footer
hook 注入了一段 JavaScript,它的核心任務很簡單:
當偵測到產品類型是
orca_wooplus_subscription
時,就用 jQuery 的addClass()
方法,將show_if_orca_wooplus_subscription
這個 class 動態地加到「一般」、「庫存」等所有我們需要顯示的分頁和面板上。
這等於是告訴 WooCommerce 的 JS:「嘿,當主角是我的訂閱商品時,這些屬於簡單商品的配角們也可以一起登場!」
前台「加入購物車」按鈕的神秘消失
後台完美了,但前台商品頁卻一片死寂——最重要的「加入購物車」按鈕消失了。
原因和後台 UI 類似:WooCommerce 的模板系統在準備顯示購買按鈕時,會觸發一個動態的 hook:woocommerce_{product_type}_add_to_cart
。對於我們這個它不認識的 orca_wooplus_subscription
類型,它不知道該載入哪個模板檔案,於是為了安全,它選擇什麼都不做。
💡 解決方案:明確告訴 WooCommerce 使用哪個模板
我們只需要在程式中掛載這個動態 hook,並在觸發時明確地告訴它要載入哪個檔案:
<?php
// 在 ORCA_Product_Type 的建構函式或 hook 註冊函式中
add_action( ‘woocommerce_orca_wooplus_subscription_add_to_cart’, [ $this, ‘add_to_cart_template’ ] );
// 新增對應的函式
public function add_to_cart_template() {
// 強制載入簡單商品的按鈕模板
wc_get_template( ‘single-product/add-to-cart/simple.php’ );
}
這個修正,等於是給迷路的 WooCommerce 指了一條明路,讓它順利地找到了按鈕模板,並將其顯示出來。
結論
這次的開發歷程,深刻體會到開發 WooCommerce 自訂功能,不僅僅是寫 PHP 而已,更是一場與 WooCommerce 核心載入順序、模板系統、後台 JavaScript 行為的綜合練習。每一個「卡關」的點,背後都代表著一個我們尚未完全理解的 WooCommerce 內部機制。
最終,成功建立了一個穩固的自訂產品類型,它不僅功能正常,而且完美地融入了 WooCommerce 的操作流程中。希望這些血淚經驗,能為你的開發之路帶來一點光亮。