如何通过WooCommerce插件重写结账页面的配送与账单地址区块
重写WooCommerce结账地址区块的纯PHP稳定方案
针对本国特殊地址格式需求,以下是完全基于WooCommerce官方PHP钩子的解决方案,不依赖DOM元素,避免JS方案的兼容性问题,且不受用户使用的主题影响:
1. 替换账单地址区块
通过移除WooCommerce默认的账单地址输出动作,替换为自定义的地址表单渲染逻辑:
// 移除默认账单地址输出 remove_action('woocommerce_checkout_billing', 'woocommerce_checkout_billing'); // 添加自定义账单地址输出 add_action('woocommerce_checkout_billing', 'custom_woocommerce_checkout_billing'); function custom_woocommerce_checkout_billing() { $checkout = WC()->checkout; ?> <div id="customer_details"> <div class="col-1"> <h3><?php esc_html_e('Billing Details', 'your-plugin-text-domain'); ?></h3> <div class="woocommerce-billing-fields"> <?php do_action('woocommerce_before_billing_fields', $checkout); ?> <!-- 自定义账单地址字段,按本国格式排列 --> <p class="form-row form-row-wide"> <label for="billing_full_name"><?php esc_html_e('Full Name', 'your-plugin-text-domain'); ?> <span class="required">*</span></label> <input type="text" class="input-text" name="billing_full_name" id="billing_full_name" value="<?php echo esc_attr($checkout->get_value('billing_full_name')); ?>" required /> </p> <p class="form-row form-row-wide"> <label for="billing_address_line1"><?php esc_html_e('Address Line 1', 'your-plugin-text-domain'); ?> <span class="required">*</span></label> <input type="text" class="input-text" name="billing_address_line1" id="billing_address_line1" value="<?php echo esc_attr($checkout->get_value('billing_address_line1')); ?>" required /> </p> <p class="form-row form-row-wide"> <label for="billing_district"><?php esc_html_e('District', 'your-plugin-text-domain'); ?> <span class="required">*</span></label> <input type="text" class="input-text" name="billing_district" id="billing_district" value="<?php echo esc_attr($checkout->get_value('billing_district')); ?>" required /> </p> <p class="form-row form-row-wide"> <label for="billing_postcode"><?php esc_html_e('Postcode', 'your-plugin-text-domain'); ?> <span class="required">*</span></label> <input type="text" class="input-text" name="billing_postcode" id="billing_postcode" value="<?php echo esc_attr($checkout->get_value('billing_postcode')); ?>" required /> </p> <!-- 保留WooCommerce默认的邮箱、电话字段(按需调整) --> <?php woocommerce_form_field('billing_email', array( 'type' => 'email', 'class' => array('form-row-wide'), 'label' => __('Email Address', 'your-plugin-text-domain'), 'required' => true, ), $checkout->get_value('billing_email')); woocommerce_form_field('billing_phone', array( 'type' => 'tel', 'class' => array('form-row-wide'), 'label' => __('Phone', 'your-plugin-text-domain'), 'required' => true, ), $checkout->get_value('billing_phone')); ?> <?php do_action('woocommerce_after_billing_fields', $checkout); ?> </div> </div> </div> <?php }
2. 替换配送地址区块
采用与账单地址相同的逻辑,替换配送地址的输出:
// 移除默认配送地址输出 remove_action('woocommerce_checkout_shipping', 'woocommerce_checkout_shipping'); // 添加自定义配送地址输出 add_action('woocommerce_checkout_shipping', 'custom_woocommerce_checkout_shipping'); function custom_woocommerce_checkout_shipping() { $checkout = WC()->checkout; if (!WC()->cart->needs_shipping()) { return; } ?> <div class="col-2"> <h3><?php esc_html_e('Shipping Details', 'your-plugin-text-domain'); ?></h3> <div class="woocommerce-shipping-fields"> <?php do_action('woocommerce_before_shipping_fields', $checkout); ?> <!-- 自定义配送地址字段,按本国格式排列 --> <p class="form-row form-row-wide"> <label for="shipping_full_name"><?php esc_html_e('Full Name', 'your-plugin-text-domain'); ?> <span class="required">*</span></label> <input type="text" class="input-text" name="shipping_full_name" id="shipping_full_name" value="<?php echo esc_attr($checkout->get_value('shipping_full_name')); ?>" required /> </p> <p class="form-row form-row-wide"> <label for="shipping_address_line1"><?php esc_html_e('Address Line 1', 'your-plugin-text-domain'); ?> <span class="required">*</span></label> <input type="text" class="input-text" name="shipping_address_line1" id="shipping_address_line1" value="<?php echo esc_attr($checkout->get_value('shipping_address_line1')); ?>" required /> </p> <p class="form-row form-row-wide"> <label for="shipping_district"><?php esc_html_e('District', 'your-plugin-text-domain'); ?> <span class="required">*</span></label> <input type="text" class="input-text" name="shipping_district" id="shipping_district" value="<?php echo esc_attr($checkout->get_value('shipping_district')); ?>" required /> </p> <p class="form-row form-row-wide"> <label for="shipping_postcode"><?php esc_html_e('Postcode', 'your-plugin-text-domain'); ?> <span class="required">*</span></label> <input type="text" class="input-text" name="shipping_postcode" id="shipping_postcode" value="<?php echo esc_attr($checkout->get_value('shipping_postcode')); ?>" required /> </p> <?php do_action('woocommerce_after_shipping_fields', $checkout); ?> </div> </div> <?php }
3. 验证自定义地址字段
确保必填字段在结账时通过验证:
add_action('woocommerce_after_checkout_validation', 'custom_address_fields_validation', 10, 2); function custom_address_fields_validation($data, $errors) { // 验证账单地址字段 if (empty($data['billing_full_name'])) { $errors->add('billing_full_name_error', __('Please enter your full billing name.', 'your-plugin-text-domain')); } if (empty($data['billing_address_line1'])) { $errors->add('billing_address_line1_error', __('Please enter your billing address line 1.', 'your-plugin-text-domain')); } if (empty($data['billing_district'])) { $errors->add('billing_district_error', __('Please enter your billing district.', 'your-plugin-text-domain')); } if (empty($data['billing_postcode'])) { $errors->add('billing_postcode_error', __('Please enter your billing postcode.', 'your-plugin-text-domain')); } // 验证配送地址字段(仅当需要配送时) if (WC()->cart->needs_shipping()) { if (empty($data['shipping_full_name'])) { $errors->add('shipping_full_name_error', __('Please enter your full shipping name.', 'your-plugin-text-domain')); } if (empty($data['shipping_address_line1'])) { $errors->add('shipping_address_line1_error', __('Please enter your shipping address line 1.', 'your-plugin-text-domain')); } if (empty($data['shipping_district'])) { $errors->add('shipping_district_error', __('Please enter your shipping district.', 'your-plugin-text-domain')); } if (empty($data['shipping_postcode'])) { $errors->add('shipping_postcode_error', __('Please enter your shipping postcode.', 'your-plugin-text-domain')); } } }
4. 保存地址数据到订单
将自定义字段的值保存到订单的元数据中,并同步到WooCommerce默认的地址字段(确保订单系统兼容):
add_action('woocommerce_checkout_create_order', 'custom_address_fields_save', 10, 2); function custom_address_fields_save($order, $data) { // 保存账单地址数据 $order->set_billing_first_name($data['billing_full_name']); $order->set_billing_address_1($data['billing_address_line1']); $order->update_meta_data('_billing_district', sanitize_text_field($data['billing_district'])); $order->set_billing_postcode(sanitize_text_field($data['billing_postcode'])); // 保存配送地址数据 if (WC()->cart->needs_shipping()) { $order->set_shipping_first_name($data['shipping_full_name']); $order->set_shipping_address_1($data['shipping_address_line1']); $order->update_meta_data('_shipping_district', sanitize_text_field($data['shipping_district'])); $order->set_shipping_postcode(sanitize_text_field($data['shipping_postcode'])); } }
5. 调整订单详情与邮件中的地址显示
确保自定义地址字段在订单页面和邮件中正确展示:
// 修改账单地址格式化输出 add_filter('woocommerce_order_get_formatted_billing_address', 'custom_formatted_billing_address', 10, 2); function custom_formatted_billing_address($address, $order) { $district = $order->get_meta('_billing_district'); $formatted_address = array( $order->get_billing_first_name(), $order->get_billing_address_1(), $district, $order->get_billing_postcode(), ); // 过滤空值 $formatted_address = array_filter($formatted_address); return implode(', ', $formatted_address); } // 修改配送地址格式化输出 add_filter('woocommerce_order_get_formatted_shipping_address', 'custom_formatted_shipping_address', 10, 2); function custom_formatted_shipping_address($address, $order) { if (!$order->needs_shipping()) { return $address; } $district = $order->get_meta('_shipping_district'); $formatted_address = array( $order->get_shipping_first_name(), $order->get_shipping_address_1(), $district, $order->get_shipping_postcode(), ); // 过滤空值 $formatted_address = array_filter($formatted_address); return implode(', ', $formatted_address); }
注意事项
- 将上述代码添加到你的插件主文件中,替换
your-plugin-text-domain为你的插件文本域,用于国际化支持。 - 根据本国地址格式,调整字段的数量、名称和排列顺序。
- 若需要添加更多字段(如省份、城市),可在表单中添加对应输入框,并同步更新验证和保存逻辑。
内容的提问来源于stack exchange,提问作者Daniel Eisenhardt
相关产品推荐
相关产品推荐

