iT邦幫忙

2026 iThome 鐵人賽

0

前幾篇我們做了結帳欄位、金流、發票、物流,但都是零散的程式碼片段。今天把它們整合成一個能提供給別人安裝的外掛。

為什麼是外掛不是主題?

該把功能放在外掛還是佈景主題只要問下面這個問題就能判斷:

換掉佈景主題之後,這個功能該不該繼續存在?

  • 客戶明年把網站改版、換一套新主題 → 金流不能跟著消失 → 外掛
  • 商品卡片的圓角、間距、字級 → 換主題本來就該跟著換 → 主題

用這條判準結帳欄位(訂單資料)、金流、發票、物流,全部都應該放進外掛,至於檔案結構以下是 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 才能作用,需要再程式碼檢查客戶網站是否有啟用 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_tablescart_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"
  }
}

電商外掛有幾個特別該測的地方,優先順序比一般外掛高:

  1. **金流的驗章邏輯:**丟正確簽章、錯誤簽章、空值進去,斷言只有第一種放行
  2. **冪等:**同一筆通知資料連續處理三次,斷言訂單狀態只變一次、發票只開一張
  3. **金額比對:**送一個金額不符的通知,斷言訂單狀態沒有變成已付款

這三個都是「壞掉不會有人發現,直到出事才發現」的類型,而且它們都不需要真的連到金流商,你自己組加密資料打自己的處理函式就好。

i18n 這邊多一個提醒:金流與物流的顯示名稱是客人看得到的method_titletitle 這些設定的預設值都要包 __(),不然客戶把網站改成英文版時會出現半中半英的結帳頁。

交付與上架

如果是客製給單一客戶,交付前的清單:

  • [ ] 四關全綠(PHPCS、PHPStan、PHPUnit、POT 是最新的)
  • [ ] HPOS 打開測過一輪
  • [ ] 區塊結帳頁與傳統結帳頁都測過(如果兩種都要支援)
  • [ ] 金流用測試環境完整走過一次,含背景通知
  • [ ] 所有 API 金鑰都在設定頁,沒有寫死在程式碼裡
  • [ ] readme.txt 或交接文件寫明依賴的外部服務與帳號在誰手上

如果要上架到 WordPress.org,還要多注意:外部 API 呼叫要在 readme.txt 揭露(哪些資料送到哪裡、隱私政策連結)、不能包含混淆過的程式碼、金鑰不能有預設值,這些規則每年會微調,送審前查一次官方指南比較保險。

結語

從 WooCommerce 的前台搬到區塊與 API 之後,「畫面」與「訂單」變成兩邊的邏輯:

  • 畫面那一側(結帳欄位、付款方式顯示)換了新 API,舊教學全部失效
  • 訂單那一側(金流處理、發票、物流、狀態機)幾乎沒變,你原本會的還是能用

搞混這兩者,就會出現「照著文章改了半天沒反應」;分清楚之後,你會發現需要重學的其實只有畫面一層。這也呼應了整個系列從一直在強調的事:WordPress 的新技術多半是能用舊知識來理解的,找到新舊之間的對應關係學習成本會低很多。

再加上有了強大的 AI 幫忙,能夠把自己想要學習的事物用自己熟悉的方式解釋給自己聽,只要能夠好好運用 AI,它絕對是最強大也最有耐心的老師。

謝謝你跟我一起完成這四十天的挑戰,我們明年見!

文章目錄:https://oberonlai.blog/category/2026-ithome/


上一篇
WooCommerce 物流串接:超商取貨整合區塊結帳
系列文
從一句話到一個網站:用 Vibe Coding 開發 WordPress Block Theme 的 30 天40
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言