前幾篇我們做了結帳欄位、金流、發票、物流,但都是零散的程式碼片段。今天把它們整合成一個能提供給別人安裝的外掛。
該把功能放在外掛還是佈景主題只要問下面這個問題就能判斷:
換掉佈景主題之後,這個功能該不該繼續存在?
用這條判準結帳欄位(訂單資料)、金流、發票、物流,全部都應該放進外掛,至於檔案結構以下是 AI 建議的架構,我自己的話檔名的命名方式會用 CamelCase 來處理比較精簡:
my-shop-extensions/
├── my-shop-extensions.php # 主檔:標頭、相依檢查、載入
├── includes/
│ ├── class-checkout-fields.php # Day 34:結帳欄位
│ ├── class-gateway-newebpay.php # Day 36:金流
│ ├── class-invoice.php # Day 38:發票
│ └── class-shipping-cvs.php # Day 39:物流
├── src/
│ └── newebpay-blocks.js # Day 37:區塊結帳整合
├── build/ # wp-scripts 產物
├── languages/
├── tests/
└── readme.txt
一個功能一個類別就拆成一個獨立的檔案,然後把共用的部分用抽象類別或是 Interface 來解耦,如果是重複的程式碼可以用 Trait。
外掛依賴 WooCommerce 才能作用,需要再程式碼檢查客戶網站是否有啟用 WooCommerce 可以從下面幾個地方做設定:
一、外掛標頭的 Requires Plugins(WordPress 6.5 起)
<?php
/**
* Plugin Name: My Shop Extensions
* Description: 金流、發票、物流與結帳欄位客製。
* Version: 1.0.0
* Requires at least: 6.5
* Requires PHP: 8.0
* Requires Plugins: woocommerce
* Text Domain: my-shop-extensions
*
* @package My_Shop_Extensions
*/
Requires Plugins 讓 WordPress 幫你把關:WooCommerce 沒裝或沒啟用時,這個外掛的啟用按鈕會直接停用,並顯示缺少哪個相依,這比自己寫檢查友善得多,因為它發生在啟用之前。

二、程式碼裡的防禦性檢查
標頭那層在舊版 WordPress 上沒作用,所以還是要有:
add_action(
'plugins_loaded',
function () {
if ( ! class_exists( 'WooCommerce' ) ) {
add_action(
'admin_notices',
function () {
echo '<div class="notice notice-error"><p>';
esc_html_e( 'My Shop Extensions 需要 WooCommerce 才能運作。', 'my-shop-extensions' );
echo '</p></div>';
}
);
return;
}
My_Shop_Extensions::instance()->init();
}
);
重點是不要在檔案最上層就 new 你的類別,WooCommerce 還沒載入時去繼承 WC_Payment_Gateway 會直接白畫面,所有繼承 WooCommerce 類別的程式碼都要延後到確認它存在之後。
三、向 WooCommerce 宣告相容性
WooCommerce 有兩個功能需要外掛主動宣告支援,沒宣告的話後台會出現「這個外掛可能不相容」的警告,客戶看到會來問你:
add_action(
'before_woocommerce_init',
function () {
if ( ! class_exists( \Automattic\WooCommerce\Utilities\FeaturesUtil::class ) ) {
return;
}
// HPOS(高效能訂單儲存).
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility(
'custom_order_tables',
__FILE__,
true
);
// 區塊版購物車與結帳.
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility(
'cart_checkout_blocks',
__FILE__,
true
);
}
);
兩個 feature id 是 custom_order_tables 與 cart_checkout_blocks,掛在 before_woocommerce_init 上。
但宣告之前先確認你真的相容,HPOS 的相容性重點是不要直接操作 wp_postmeta:
// ❌ HPOS 開啟後讀不到.
update_post_meta( $order_id, '_invoice_number', $number );
$number = get_post_meta( $order_id, '_invoice_number', true );
// ✅ 走 CRUD.
$order->update_meta_data( '_invoice_number', $number );
$order->save(); // save 不要忘記
$number = $order->get_meta( '_invoice_number' );
在之前的程式碼範例 AI 用的都是 $order->update_meta_data() 而不是 update_post_meta() 就是為了這件事MHPOS 把訂單搬到自訂資料表之後,用 post meta 存的資料會讀不到,而這種錯誤在沒開 HPOS 的開發環境完全測不出來。
測試時記得把 HPOS 打開**,** 在 WooCommerce → 設定 → 進階 → 功能裡可以切換:

外掛的品質關跟主題完全一樣,四關一個都不能少:
{
"scripts": {
"phpcs": "phpcs",
"phpstan": "phpstan analyse",
"test": "phpunit",
"make-pot": "wp i18n make-pot . languages/my-shop-extensions.pot --domain=my-shop-extensions --exclude=build,node_modules,vendor"
}
}
電商外掛有幾個特別該測的地方,優先順序比一般外掛高:
這三個都是「壞掉不會有人發現,直到出事才發現」的類型,而且它們都不需要真的連到金流商,你自己組加密資料打自己的處理函式就好。
i18n 這邊多一個提醒:金流與物流的顯示名稱是客人看得到的。method_title、title 這些設定的預設值都要包 __(),不然客戶把網站改成英文版時會出現半中半英的結帳頁。
如果是客製給單一客戶,交付前的清單:
readme.txt 或交接文件寫明依賴的外部服務與帳號在誰手上如果要上架到 WordPress.org,還要多注意:外部 API 呼叫要在 readme.txt 揭露(哪些資料送到哪裡、隱私政策連結)、不能包含混淆過的程式碼、金鑰不能有預設值,這些規則每年會微調,送審前查一次官方指南比較保險。
從 WooCommerce 的前台搬到區塊與 API 之後,「畫面」與「訂單」變成兩邊的邏輯:
搞混這兩者,就會出現「照著文章改了半天沒反應」;分清楚之後,你會發現需要重學的其實只有畫面一層。這也呼應了整個系列從一直在強調的事:WordPress 的新技術多半是能用舊知識來理解的,找到新舊之間的對應關係學習成本會低很多。
再加上有了強大的 AI 幫忙,能夠把自己想要學習的事物用自己熟悉的方式解釋給自己聽,只要能夠好好運用 AI,它絕對是最強大也最有耐心的老師。
謝謝你跟我一起完成這四十天的挑戰,我們明年見!
文章目錄:https://oberonlai.blog/category/2026-ithome/