本篇文章更新時間:2021/05/25
如有資訊過時或語誤之處,歡迎使用 Contact 功能通知。
一介資男的 LINE 社群開站囉!歡迎入群聊聊~
如果本站內容對你有幫助,歡迎使用 BFX Pay 加密貨幣新台幣 贊助支持。


針對 WooCommerce 結帳欄位相關的議題,過去寫過不少:

... 等等,還有其他應用上變化的筆記文章沒列出來(站上文章關鍵字標籤可以點一點逛一下)。

原本最早就是結帳欄位這機制比較常有客製化需求,先是整理了一個在「台灣」銷售行為發生時,大家比較習慣的結帳欄位「樣版」。

但畢竟還算是「樣板」,多多少少都會有要調整的地方,於是乎研究過一輪又筆記一篇「調整結帳欄位的終極指南」。

然後開始了一連串與這結帳表單的互動,像是根據物流改變、根據金流改變,甚至是根據下單的商品做出結帳頁面的改變等。

直到今天要解決一個「隱藏」、「必填改選填」、「移除」欄位的需求時,又覺得筆記不夠力了XD

WooCommerce 一直有持續改版是好事,但如果維護網站的數量一多,跨版本之間的兼容就會越來越不容易,考驗對整個架構設計的理解。

本篇需求來自網友對綠界超商取貨物流外掛套用後產生的

既然都用超商取貨了,能不能讓地址欄位不用填寫也能結帳?

這問題的「不用填寫」其實可以拆成:

  1. 從必填到選填的改變
  2. 眼不見為淨,欄位隱藏
  3. 完整移除這欄位

會要分開操作面也是因為選擇不同作法在經營與開發上,意義是不同的,所以不建議思考方向過於單調進而喪失其他可能性。

寫在開始前

由於 WordPress 有一套很有彈性的 Hooks 機制設計,這意味著不只有你可以改變內容與事件的型態與結果,還包含你正在使用的外掛與主題也可以!(反過來說,你也可以因此去改變外掛或主題的行為)

寫任何 Hooks 機制會使用 action 或是 filter 方法,分別對應:

  1. Action: 觸發活動事件,個別作用不影響,不用回傳資料。
  2. 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);

確認預設的資料流出來的欄位 requiredfalse

如果是選填要改必填,就是把 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);

然後也確認結帳欄位輸出的資料也是 requiredfalse

特別注意

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 影響。

而「隱藏」這件事主要是那個 hiddenclass 影響。

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 陣列元素的修改方式,確定好需求,將上述提到的運作情境程式碼稍作調整就容易多囉~


Share:

作者: Chun

資訊愛好人士。主張「人人都該為了偷懶而進步」。期許自己成為斜槓到變進度條 100% 的年輕人。[///////////____36%_________]

發佈留言

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


文章
Filter
Apply Filters
Mastodon