本篇文章更新時間:2021/05/25
如有資訊過時或語誤之處,歡迎使用 Contact 功能通知。
一介資男的 LINE 社群開站囉!歡迎入群聊聊~
如果本站內容對你有幫助,歡迎使用 BFX Pay 加密貨幣 或 新台幣 贊助支持。
針對 WooCommerce 結帳欄位相關的議題,過去寫過不少:
- [WordPress] 調整適合 WooCommerce 在台銷售結帳頁欄位(含地址郵遞區號選擇)
- [WooCommerce] 調整結帳欄位的終極指南
- [WooCommerce] 程式客製化結帳欄位紀錄方法(Session)
- [WooCommerce] 片段(fragments)互動程式設計要點
... 等等,還有其他應用上變化的筆記文章沒列出來(站上文章關鍵字標籤可以點一點逛一下)。
原本最早就是結帳欄位這機制比較常有客製化需求,先是整理了一個在「台灣」銷售行為發生時,大家比較習慣的結帳欄位「樣版」。
但畢竟還算是「樣板」,多多少少都會有要調整的地方,於是乎研究過一輪又筆記一篇「調整結帳欄位的終極指南」。
然後開始了一連串與這結帳表單的互動,像是根據物流改變、根據金流改變,甚至是根據下單的商品做出結帳頁面的改變等。
直到今天要解決一個「隱藏」、「必填改選填」、「移除」欄位的需求時,又覺得筆記不夠力了XD
WooCommerce 一直有持續改版是好事,但如果維護網站的數量一多,跨版本之間的兼容就會越來越不容易,考驗對整個架構設計的理解。
本篇需求來自網友對綠界超商取貨物流外掛套用後產生的
既然都用超商取貨了,能不能讓地址欄位不用填寫也能結帳?
這問題的「不用填寫」其實可以拆成:
- 從必填到選填的改變
- 眼不見為淨,欄位隱藏
- 完整移除這欄位
會要分開操作面也是因為選擇不同作法在經營與開發上,意義是不同的,所以不建議思考方向過於單調進而喪失其他可能性。
內容目錄
寫在開始前
由於 WordPress 有一套很有彈性的 Hooks 機制設計,這意味著不只有你可以改變內容與事件的型態與結果,還包含你正在使用的外掛與主題也可以!(反過來說,你也可以因此去改變外掛或主題的行為)
寫任何 Hooks 機制會使用 action
或是 filter
方法,分別對應:
- Action: 觸發活動事件,個別作用不影響,不用回傳資料。
- Filter: 資料流,事件執行要注意先後順序,前面處理過的資料會傳遞給後面的方法繼續處理,方法會回傳資料。
會使用這機制開發、處理與改變網站呈現的結果,正是因為要讓網站有足夠彈性擴充,不至於發生問題時更新網站會連帶之前的修正被一起清除。
所謂「符合 WordPress 開發方式」正是在講此機制!而不建議對任何既有的程式碼進行直接修改的寫死(Hard Code)作業。
WooCommerce 結帳欄位資料流
WooCommerce v3.3
後版本加入了 countries
的多元性,用意也是希望能「本地化」打入市場。
對於不管「台灣」有沒有加入對應國家「預設」的欄位組合,它先定義了一個 woocommerce_default_address_fields
filter 來處理對應國家預設欄位,結帳欄位的資料從這邊開始。
其後就是到結帳頁面的欄位 woocommerce_checkout_fields
filter。
所以從預設欄位,到結帳欄位,要掌控就是這兩個 Filter 都要覆寫過,確保操作上不會被干擾。
WooCommerce 結帳欄位必填改選填
function mxp_woocommerce_default_address_fields($fields) {
$fields = array(
'first_name' => array(
'label' => __('First name', 'woocommerce'),
'required' => false,
'class' => array('form-row-first'),
'autocomplete' => 'given-name',
'priority' => 10,
),
'last_name' => array(
'label' => __('Last name', 'woocommerce'),
'required' => false,
'class' => array('form-row-last'),
'autocomplete' => 'family-name',
'priority' => 20,
),
'company' => array(
'label' => __('Company name', 'woocommerce'),
'class' => array('form-row-wide'),
'autocomplete' => 'organization',
'priority' => 30,
'required' => 'required' === get_option('woocommerce_checkout_company_field', 'optional'),
),
'country' => array(
'type' => 'country',
'label' => __('Country / Region', 'woocommerce'),
'required' => false,
'class' => array('form-row-wide', 'address-field', 'update_totals_on_change'),
'autocomplete' => 'country',
'priority' => 40,
),
'address_1' => array(
'label' => __('Street address', 'woocommerce'),
/* translators: use local order of street name and house number. */
'placeholder' => esc_attr__('House number and street name', 'woocommerce'),
'required' => false,
'class' => array('form-row-wide', 'address-field'),
'autocomplete' => 'address-line1',
'priority' => 50,
),
'address_2' => array(
'placeholder' => esc_attr($address_2_placeholder),
'class' => array('form-row-wide', 'address-field'),
'autocomplete' => 'address-line2',
'priority' => 60,
'required' => 'required' === get_option('woocommerce_checkout_address_2_field', 'optional'),
),
'city' => array(
'label' => __('Town / City', 'woocommerce'),
'required' => false,
'class' => array('form-row-wide', 'address-field'),
'autocomplete' => 'address-level2',
'priority' => 70,
),
'state' => array(
'type' => 'state',
'label' => __('State / County', 'woocommerce'),
'required' => false,
'class' => array('form-row-wide', 'address-field'),
'validate' => array('state'),
'autocomplete' => 'address-level1',
'priority' => 80,
),
'postcode' => array(
'label' => __('Postcode / ZIP', 'woocommerce'),
'required' => false,
'class' => array('form-row-wide', 'address-field'),
'validate' => array('postcode'),
'autocomplete' => 'postal-code',
'priority' => 90,
),
);
return $fields;
}
add_filter('woocommerce_default_address_fields', 'mxp_woocommerce_default_address_fields', 999, 1);
確認預設的資料流出來的欄位 required
是 false
。
如果是選填要改必填,就是把 false 改成 true !
function mxp_custom_override_checkout_fields($fields) {
// 讓欄位變成選填的方法
$fields['billing']['billing_state']['required'] = false;
$fields['billing']['billing_city']['required'] = false;
$fields['billing']['billing_address_1']['required'] = false;
$fields['billing']['billing_postcode']['required'] = false;
$fields['shipping']['shipping_state']['required'] = false;
$fields['shipping']['shipping_city']['required'] = false;
$fields['shipping']['shipping_address_1']['required'] = false;
return $fields;
}
add_filter('woocommerce_checkout_fields', 'mxp_custom_override_checkout_fields', 999, 1);
然後也確認結帳欄位輸出的資料也是 required
為 false
。
特別注意
add_filter 方法內有個「權重」參數 int $priority = 10
預設是 10
,這邊我寫 999
只是一種確保可以是排最後才執行,但如果有其他人寫這方法,權重數字又大於 999
的話,你的執行結果可能就會不如預期。(add_action 亦同)
而上述預設欄位裡看到的 priority
參數與方法執行順序無關,是欄位呈現上的順序參數。
WooCommerce 結帳欄位隱藏
function mxp_custom_override_checkout_fields($fields) {
// 讓欄位變成選填的方法
$fields['billing']['billing_state']['required'] = false;
$fields['billing']['billing_city']['required'] = false;
$fields['billing']['billing_address_1']['required'] = false;
$fields['billing']['billing_postcode']['required'] = false;
$fields['shipping']['shipping_state']['required'] = false;
$fields['shipping']['shipping_city']['required'] = false;
$fields['shipping']['shipping_address_1']['required'] = false;
// 隱藏欄位的方法
$fields['billing']['billing_state']['class'] = array('hidden');
$fields['billing']['billing_city']['class'] = array('hidden');
$fields['billing']['billing_address_1']['class'] = array('hidden');
$fields['billing']['billing_address_2']['class'] = array('hidden');
$fields['billing']['billing_postcode']['class'] = array('hidden');
$fields['shipping']['shipping_state']['class'] = array('hidden');
$fields['shipping']['shipping_city']['class'] = array('hidden');
$fields['shipping']['shipping_address_1']['class'] = array('hidden');
return $fields;
}
add_filter('woocommerce_checkout_fields', 'mxp_custom_override_checkout_fields', 9999, 1);
function mxp_woocommerce_default_address_fields($fields) {
$fields = array(
'first_name' => array(
'label' => __('First name', 'woocommerce'),
'required' => false,
'class' => array('hidden'),
'autocomplete' => 'given-name',
'priority' => 10,
),
'last_name' => array(
'label' => __('Last name', 'woocommerce'),
'required' => false,
'class' => array('hidden'),
'autocomplete' => 'family-name',
'priority' => 20,
),
'company' => array(
'label' => __('Company name', 'woocommerce'),
'class' => array('hidden'),
'autocomplete' => 'organization',
'priority' => 30,
'required' => 'required' === get_option('woocommerce_checkout_company_field', 'optional'),
),
);
return $fields;
}
add_filter('woocommerce_default_address_fields', 'mxp_woocommerce_default_address_fields', 9999, 1);
要隱藏欄位的話,也是要注意欄位是不是設定為「非必填」,不然看不到哪裡可以填寫,又一直過不了結帳,感覺肯定很差!
這邊在「預設」欄位的部分拿掉了「地址」相關的避免前端 JavaScript 影響。
而「隱藏」這件事主要是那個 hidden
的 class
影響。
WooCommerce 刪除結帳欄位
function mxp_custom_override_checkout_fields($fields) {
// 移除欄位選填的方法
unset($fields['billing']['billing_state']);
unset($fields['billing']['billing_city']);
unset($fields['billing']['billing_address_1']);
unset($fields['billing']['billing_postcode']);
unset($fields['shipping']['shipping_state']);
unset($fields['shipping']['shipping_city']);
unset($fields['shipping']['shipping_address_1']);
return $fields;
}
add_filter('woocommerce_checkout_fields', 'mxp_custom_override_checkout_fields', 9999, 1);
function mxp_woocommerce_default_address_fields($fields) {
return [];
}
add_filter('woocommerce_default_address_fields', 'mxp_woocommerce_default_address_fields', 9999, 1);
清空預設欄位,然後再 woocommerce_checkout_fields
結帳欄位的資料流中把欄位移除即可。
結語
上述舉例修改欄位的操作動到了兩個 Hook,寫法上沒有順序問題,只要注意權重先後。 修改的程式碼片段可以使用 Code Snippets 外掛新增或是對(子)主題目錄下的 functions.php
檔案修改新增程式碼片段。
再來是範例中使用的欄位名稱可以注意到是特殊關鍵字,這部分可以到 WooCommerce 這份 Customizing checkout fields using actions and filters 文件裡找到!
至於欄位中的屬性,可以參考本站終極指南一文,裡頭有提到。
範例中的修改絕對不適合直接套用
,要使用的話建議先了解 PHP 陣列元素的修改方式,確定好需求,將上述提到的運作情境程式碼稍作調整就容易多囉~