自定义WooCommerce配送方法init中获取配送类报错求助
解决WooCommerce自定义配送方法中WC()->shipping为null的问题
这个问题我之前也碰到过,核心原因就是代码执行时机太早——WooCommerce的WC_Shipping实例还没完成初始化,你就在配送方法的init里调用WC()->shipping->get_shipping_classes()了,自然会触发致命错误。
为什么Flat Rate能正常工作?
Flat Rate配送方法并没有在init阶段直接调用WC()->shipping,而是把获取配送类的逻辑延迟到了实际需要用到的场景(比如后台设置表单渲染、运费计算时),这时候WC_Shipping已经完成初始化了。
具体解决方案
这里有两种可靠的修复方式,你可以根据自己的需求选择:
方案1:延迟到需要时再获取配送类
不要在init或__construct里提前获取配送类,而是在实际用到它的地方(比如渲染设置字段、计算运费)再调用WC()->shipping->get_shipping_classes():
class WC_Custom_Shipping_Method extends WC_Shipping_Method { public function __construct() { $this->id = 'custom_shipping'; $this->method_title = __('自定义配送', 'your-text-domain'); $this->method_description = __('自定义配送方法描述', 'your-text-domain'); // 初始化设置和表单字段 $this->init_form_fields(); $this->init_settings(); // 绑定设置保存钩子 add_action('woocommerce_update_options_shipping_' . $this->id, array($this, 'process_admin_options')); } public function init_form_fields() { // 在这里获取配送类(后台设置页加载时,WC()->shipping已初始化) $shipping_classes = WC()->shipping->get_shipping_classes(); $class_options = array('' => __('无配送类', 'your-text-domain')); foreach ($shipping_classes as $class) { $class_options[$class->term_id] = $class->name; } // 构建表单字段 $this->form_fields = array( 'enabled' => array( 'title' => __('启用', 'your-text-domain'), 'type' => 'checkbox', 'default' => 'yes' ), 'target_class' => array( 'title' => __('目标配送类', 'your-text-domain'), 'type' => 'select', 'options' => $class_options ) ); } // 计算运费时获取配送类 public function calculate_shipping($package = array()) { $shipping_classes = WC()->shipping->get_shipping_classes(); // 你的运费计算逻辑... $rate = array( 'id' => $this->id, 'label' => $this->title, 'cost' => '10.00', 'calc_tax' => 'per_item' ); $this->add_rate($rate); } }
方案2:用WooCommerce钩子延迟初始化
如果需要提前缓存配送类数据,可以绑定woocommerce_shipping_init钩子——这个钩子会在WC_Shipping实例初始化完成后触发:
class WC_Custom_Shipping_Method extends WC_Shipping_Method { private $cached_shipping_classes = array(); public function __construct() { $this->id = 'custom_shipping'; $this->method_title = __('自定义配送', 'your-text-domain'); $this->init_settings(); // 绑定钩子,在WC_Shipping初始化后加载配送类 add_action('woocommerce_shipping_init', array($this, 'load_shipping_classes')); add_action('woocommerce_update_options_shipping_' . $this->id, array($this, 'process_admin_options')); } public function load_shipping_classes() { $this->cached_shipping_classes = WC()->shipping->get_shipping_classes(); } // 使用时直接调用缓存的数据,兜底避免空值 public function calculate_shipping($package = array()) { $shipping_classes = !empty($this->cached_shipping_classes) ? $this->cached_shipping_classes : WC()->shipping->get_shipping_classes(); // 你的运费计算逻辑... $rate = array( 'id' => $this->id, 'label' => $this->title, 'cost' => '15.00', 'calc_tax' => 'per_order' ); $this->add_rate($rate); } }
关键原理
WooCommerce的WC()->shipping实例是在woocommerce_shipping_init钩子中完成初始化的,而自定义配送方法的注册(通常通过woocommerce_shipping_methods钩子)和__construct/init方法的执行,都早于这个钩子的触发时机。所以直接在init里调用WC()->shipping自然会得到null。
内容的提问来源于stack exchange,提问作者rmbits
相关产品推荐
相关产品推荐

