Physical Address

304 North Cardinal St.
Dorchester Center, MA 02124

替 Paid Member Subscriptions 串接綠界金流

本外掛仍處於測試階段,同時還有若干已知問題,目前停止更新中。

因為公司的專案 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),通常會提供套件,可以讓你更快的尋找到函式與方法的定義。

Eric Chuang
Eric Chuang

正職是廣告行銷人員,因為 Google Tag Manager 的關係開始踏入網站製作的領域,進一步把 WordPress 當成 PHP + HTML + CSS + JavaScript 的學習教材。此外,因為工作的關係,曾經用 Automattic 的 Underscores (_s) 替客戶與公司官網進行全客製化佈景主題開發。

1 則留言

  1. 版主您好,感謝您開發了這個外掛!
    想詢問 ECPay Execution Time(s) 設定為 12 的話,是用戶在 12 個月後就會自動停止訂閱的意思嗎?
    以及 return URL 的用途是什麼呢?
    謝謝版主

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料