之前開發的 WooCommerce 推播通知外掛有客人反應說在設定多個工作流程時,符合特定訂單狀態但規則不符合時依舊會進行推播。譬如我設定了兩個工作流程,觸發時機皆為訂單狀態變為保留,然後第一個工作流程是當付款方式等於 ATM 櫃員機,第二個工作流程是超商代碼,假設有一張新訂單付款方式為綠界信用卡,結果竟然會收到這兩個工作流程的推播,即使訂單的付款方式不符合:
問題出在規則的取得,我是先用 WP_Query
去撈出所有工作流程的 CPT,然後把訂單物件傳進去做條件的比對,像是判斷訂單狀態以及付款方式,當條件符合時會寫入 yes 到一個 $result
陣列,不符合的話寫 no,然後再用 array_unique
去刪除重複的值,如果最後$reuslt
的數量為一,那麼就將這個工作流程的文章 ID 寫進準備要推播的陣列。
$reuslt = array( 'yes', 'yes');
$result_count = array_unique( $result ); // 變成 array('yes')
if ( $result_count && count( $result_count ) === 1 ) {
$notify_ids[] = get_the_ID();
}
而問題發生在寫入 no 的狀態,如果兩個工作流程都不符合,那麼經過 array_unique
的 $result
的數量一樣會是一,因而造成兩個不符合條件的工作流程都加進去準備要推播 ID 的陣列,進而產生重複推播的問題:
$reuslt = array( 'no', 'no');
$result_count = array_unique( $result ); // 變成 array('no')
if ( $result_count && count( $result_count ) === 1 ) {
$notify_ids[] = get_the_ID();
}
修改的方向是除了要檢查 $result_count
的數量外,還要確保第一個值是 yes,但我的操作介面只提供 AND 的條件,因此當條件不符合時我直接把 $result
給清空,確保在多個條件有一個不成立的情況下,$result
就會是空陣列。
但我覺得比較好的做法是還是要提供 OR 的選項,但由於 PHP 的運算子無法使用變數來處理,也就是說我無法用變數來決定是 &&
還是 ||
,但有查到 switch
的寫法,這部分找時間再來重構,目前版本的程式碼如下:
if ( $wc_notify_trigger_rule ) {
foreach ( $wc_notify_trigger_rule as $rule ) {
$order_by = $rule['wc_notify_trigger_rule_order_by'];
$is = $rule['wc_notify_trigger_rule_is'];
$gateway = $rule['wc_notify_trigger_rule_gateway'];
$shipping = $rule['wc_notify_trigger_rule_shipping'];
if ( 'by_gateway' === $order_by ) {
if ( ( 'is' === $is && $order->get_payment_method() === $gateway ) || ( 'isnot' === $is && $order->get_payment_method() !== $gateway ) ) {
$result[] = 'yes';
} else {
$result = array();
}
}
if ( 'by_shipping' === $order_by ) {
if ( ( 'is' === $is && $shipping_data_method_id === $shipping ) || ( 'isnot' === $is && $shipping_data_method_id !== $shipping ) ) {
$result[] = 'yes';
} else {
$result = array();
}
}
}
$result_count = array_unique( $result );
if ( $result_count && count( $result_count ) === 1 ) {
$notify_ids[] = get_the_ID();
}
}