You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:21:36