升级到 3.X 后 WooCommerce 自定义代码中断

WooCommerce custom code breaks after upgrade to 3.X

更新版本的 WooCommerce 3.X 之后,为 WoCommerce 2.X 编写的代码不再工作,并且在产品类型行上没有抛出错误。

function remove_bundled_items_from_cart( $cart_item_key, $instance ) {

 if ( ! empty( $instance->removed_cart_contents[$cart_item_key] ) ) {

    $product_id     = $instance->removed_cart_contents[$cart_item_key]['product_id'];
    $product_type   = $instance->removed_cart_contents[$cart_item_key]['data']->product_type;

    if ( $product_type == 'bundle' ) {
        if (is_array($instance->cart_contents) || is_object($instance->cart_contents)) {
         foreach ( $instance->cart_contents as $key => $cart_item ) {
            if ( isset( $cart_item['is_bundled_item'] ) && $cart_item['is_bundled_item'] == $product_id ) {
                WC()->cart->remove_cart_item( $key );
            }
         }
        }
    }
 }
}
add_action( 'woocommerce_cart_item_removed', 'remove_bundled_items_from_cart', 10, 2 );

有人知道我需要更改什么才能让 $product_type 停止抛出错误吗?

我仍然需要能够检查字符串是否为 "bundle",因此我需要以某种方式获取信息。

由于您代码中的主要错误来自:

$product_type = $instance->removed_cart_contents[$cart_item_key]['data']->product_type;

The $instance->removed_cart_contents[$cart_item_key]['data'] is the WC_Product Object instance and since WC versions 3+ WC_Product properties can't be accessed directly anymore.
Instead you will use the WC_Product method get_type() (or the conditional method is_type())

由于$instance->removed_cart_contents[$cart_item_key]['data']在简单的产品中是不存在的,所以您需要在第一个条件下进行测试。

这应该避免抛出错误(在产品类型行上……):

add_action( 'woocommerce_cart_item_removed', 'remove_bundled_items_from_cart', 10, 2 );
function remove_bundled_items_from_cart( $cart_item_key, $instance ) {

     if ( ! empty( $instance->removed_cart_contents[$cart_item_key]['data'] ) ) {

        $product_id = $instance->removed_cart_contents[$cart_item_key]['product_id'];
        $product    = $instance->removed_cart_contents[$cart_item_key]['data']; // The WC_Product object

        if ( $product->is_type( 'bundle' ) ) {
            if (is_array($instance->cart_contents) || is_object($instance->cart_contents)) {
                foreach ( $instance->cart_contents as $key => $cart_item ) {
                    if ( isset( $cart_item['is_bundled_item'] ) && $cart_item['is_bundled_item'] == $product_id ) {
                        WC()->cart->remove_cart_item( $key );
                    }
                }
            }
        }
    }
}

BUT I don't see in the raw cart data output any 'is_bundled_item' key…

Instead you can use in your code one of this available cart array keys:

  • bundled_by key (the parent WC_Bundle_Product cart item key)
  • bundled_item_id key (the child bundle item ID)

所以你可以在你的代码中替换 'is_bundled_item' 比如:

add_action( 'woocommerce_cart_item_removed', 'remove_bundled_items_from_cart', 10, 2 );
function remove_bundled_items_from_cart( $cart_item_key, $instance ) {

     if ( ! empty( $instance->removed_cart_contents[$cart_item_key]['data'] ) ) {
        $product    = $instance->removed_cart_contents[$cart_item_key]['data'];

        if ( $product->is_type( 'bundle' ) ) {
            if (is_array($instance->cart_contents) || is_object($instance->cart_contents)) {
                foreach ( $instance->cart_contents as $key => $cart_item ) {
                    if ( isset( $cart_item['bundled_item_id'] ) && $cart_item['bundled_by'] == $cart_item_key ) {
                        WC()->cart->remove_cart_item( $key );
                    }
                }
            }
        }
    }
}

这应该完全有效……