本外掛仍處於測試階段,同時還有若干已知問題,目前停止更新中。
因為公司的專案 applemint lab 需要,所以調查了一些限制內容的外掛。
當初針對「約期授權 (Subscription)」、「限制內容 (Content Restriction)」等關鍵字搜尋後,發現了兩款名稱相近的外掛 Paid Membership Pro (PMPro) 與 Paid Member Subscriptions (PMS)。試用一下之後,發現 PMS 蠻符合 applemint lab 的需求,因此就決定使用該款外掛來建立限制內容。
目前這類外掛都是由外國開發,因此串接的金流主要都是 PayPal 或是 Stripe 這類海外金流服務。為了能夠在台灣使用,因此嘗試串接了綠界的金流,作為主要的支付方式。
這篇文章主要是記錄當初是如何摸索串接的方法,跟 PMS 有關的相關設定,以及留下目前仍須解決的待辦事項。
首先,先來分享一下為了公司開發的專案 Paid Member Subscriptions Taiwan Gateways。有興趣的話,歡迎大家建立分支版本 (fork),協助讓這個套件更好用。
內容目錄
快速入門:安裝擴充套件 Paid Member Subscriptions Taiwan Gateways
如果是一般使用者,可以前往這個 GitHub 專案,點擊 [Code] > [Download ZIP]。

在你的網站中,安裝 Paid Member Subscriptions。
最後再按照一般安裝外掛的流程,將剛才從 GitHub 下載的 .zip 檔上傳並安裝就好。
啟用綠界支付
到 Paid Member Subscriptions 的 Settings 中,選擇 Payments 的分頁,便可以勾選綠界的支付管道「ECPay」了。

接著填入特店的編號、Hash Key 與 Hash IV。(目前 Return URL 功能尚未啟用)

客製化流程
如果你有些功能想要自己加入,或是想要將原本的 GitHub 專案分支出去,一起參與這款擴充套件的開發,接下來的內容會提供你一些 Paid Member Subscriptions 的細節,幫助你進一步了解串接的流程。
使用 pms_payment_gateways 註冊後台選項
為了要在後台可以選擇支付方式,需要先註冊一個支付選項。
這裡除了需要包含註冊的支付管道名稱外,需要注意 class_name 這個值,這裡需要定義的是實際執行支付的物件類別 (Class)。
if ( !function_exists( 'pms_custom_gateway' ) ) {
function pms_custom_gateway( $arr ){
$arr['ECPay'] = array(
'display_name_user' => __( 'ECPay', 'pms-taiwan-gateways' ),
'display_name_admin' => __( 'ECPay', 'pms-taiwan-gateways' ),
'class_name' => 'PMS_Payment_Gateway_TW_ECPay'
);
return $arr;
}
}
add_filter( 'pms_payment_gateways', 'pms_custom_gateway', 101, 1 );定義 PMS_Payment_Gateway_TW_ECPay
從 0 開始串接實在是風險太大了,因此我先從外掛中,將 PayPal 的串接方式複製出來,並針對寫法進行分析,將相關的設定改為綠界支付所需要的資訊。
在延伸物件類別時,需要特別注意,為了避免找不到上層類別 (Parent Class) 造成繼承的錯誤,我是透過 plugins_loaded 這個勾點作為防護機制,但是並非其他外掛都可以用這種方法,所以遇到其他外掛時,建議先嘗試看看。
add_action( 'plugins_loaded', 'pms_ecpay_extend' );
//把 Class 的順序降低,等到其他外掛載入完之後再繼承 Class,不然會炸裂
function pms_ecpay_extend() {
if ( class_exists( 'PMS_Payment_Gateway' ) ) {
Class PMS_Payment_Gateway_TW_ECPay extends PMS_Payment_Gateway {
//...
// 定義綠界的參數
$ecpay_args = array();
// 開始執行
try {
//把綠界 SDK 執行交易的流程套用到這裡
}
}
}透過 process_sign_up 設定主要交易過程
在這個步驟中,需要設定 $notify_url 變數,主要目的是用來接收 Webhook 回傳的資料 (綠界串接文件中的 Notify URL)。
設定交易的驗證機制
參考了其他的支付管道後,發現都會建立一個 PMS_xx_Verifier 的物件,來檢查資料是否正確。
驗證完畢後,為了要變更交易狀態,因此需要透過 pms_ecpay_payment_data 這個勾點,帶入綠界回傳的資料。在這我把 subscription_id 這個選項,傳到綠界的自訂欄位 (CustomField2) 中,這樣回頭才能夠確認是不是與購入的方案相符。
$payment_data = apply_filters( 'pms_ecpay_payment_data', array(
'payment_id' => $payment_id,
'user_id' => $user_id,
'type' => $post_data['PaymentType'],
'status' => $post_data['RtnCode'] == 1 ? 'completed' : 'failed',
'transaction_id' => $post_data['MerchantTradeNo'],
'amount' => $post_data['TradeAmt'],
'date' => $post_data['PaymentDate'],
'subscription_id'=> $post_data['CustomField2']
), $post_data );定期定額
PMS 後台提供了定期定額的選項 recurring,可以用來判斷是否要串接綠界的定期定額功能。
$settings = get_option( 'pms_payments_settings' );
if( !empty( $settings['recurring'] ) ) {
$ecpay_args['PeriodAmount'] = $this->amount;
$ecpay_args['PeriodType'] = 'M';
$ecpay_args['Frequency'] = 1;
$ecpay_args['ExecTimes'] = 99;
$ecpay_args['PeriodReturnURL'] = $ecpay_args['return_url'] ?: '';
}PMS 的相關方法與函式
| 方法/函式名稱 | 功能 |
|---|---|
pms_is_payment_test_mode() | 當後台設定勾選 [Test Mode] 時,會回傳 true,用來判斷是否是測試狀態。 |
$payment = pms_get_payment() | 用來取得當前支付的交易細節。 |
$payment -> log_data( '名稱', $data ) | 可以將目前支付的狀態紀錄到資料庫中進行偵錯。 |
待辦事項
- 新增其他金流
- 新增後台選項,增加外掛的彈性
- 讓交易編號可自訂命名規則
附錄
附錄一:版本更新紀錄
2022-01-18
- 加入定期定額支付
- 將支付方式鎖定為信用卡 (未來版本將改為可選)
附錄二:外掛分析
這裡與 WordPress 外掛學習者分享一個我自己分析外掛的方式,很陽春,但我自己覺得很實用。
首先,到後台找到設定支付管道的設定頁面,並複製關鍵字,用這個關鍵字搜尋到相關檔案。

搜尋後發現是在 view-page-settings-payments.php 這個檔案中。進一步查到下面這段程式碼:
// PMS 版本: 2.5.6
$payment_gateways = pms_get_payment_gateways();
if( count( $payment_gateways ) > 1 ) :
// Checkboxes to select active Payment Gateways
echo '<div class="pms-form-field-wrapper pms-form-field-active-payment-gateways">';
echo '<label class="pms-form-field-label">' . esc_html__( 'Active Payment Gateways', 'paid-member-subscriptions' ) . '</label>';
foreach( $payment_gateways as $payment_gateway_slug => $payment_gateways_details ) {
echo '<label>';
echo '<input type="checkbox" name="pms_payments_settings[active_pay_gates][]" value="' . esc_attr( $payment_gateway_slug ) . '" ' . ( !empty( $this->options['active_pay_gates'] ) && in_array( $payment_gateway_slug, $this->options['active_pay_gates'] ) ? 'checked="checked"' : '' ) . '/>';
echo esc_html( $payment_gateways_details['display_name_admin'] );
echo '</label><br>';
}
echo '</div>';得知是透過 pms_get_payment_gateways 這個函式去取得所有的支付管道,接著再度搜尋所有檔案,發現了這個函式的原始定義。
/**
* Function that returns an array with all payment gateways
*
* @param $only_slugs - returns an array with the payment gateways slugs
*
* @return array
*
*/
function pms_get_payment_gateways( $only_slugs = false ) {
$payment_gateways = apply_filters( 'pms_payment_gateways', array(
'manual' => array(
'display_name_user' => __( 'Manual/Offline', 'paid-member-subscriptions' ),
'display_name_admin' => __( 'Manual/Offline', 'paid-member-subscriptions' ),
'class_name' => 'PMS_Payment_Gateway_Manual'
),
'paypal_standard' => array(
'display_name_user' => __( 'PayPal', 'paid-member-subscriptions' ),
'display_name_admin' => __( 'PayPal Standard', 'paid-member-subscriptions' ),
'class_name' => 'PMS_Payment_Gateway_PayPal_Standard'
)
));
if( $only_slugs )
$payment_gateways = array_keys( $payment_gateways );
return $payment_gateways;
}這篇文章的其他函式也都是透過這個方法逐個分析出來的。
如果是使用整合編輯器 (IDE),通常會提供套件,可以讓你更快的尋找到函式與方法的定義。