WooCommerce中购物车全为指定配送类商品时取消配送费率
Let me walk you through fixing this WooCommerce shipping rate logic issue.
The Problem
Your original requirement was: Only remove specific shipping rates if EVERY item in the cart belongs to the targeted shipping class. But the initial code was removing those rates as long as any item in the cart matched the class — which didn't align with what you needed.
Original (Incorrect) Code
Here's the code that wasn't working as intended:
//ROYAL MAIL ONLY FOR SPECIFIC PRODUCTS add_filter( 'woocommerce_package_rates', 'hide_table_shipping_for_shipping_class', 10, 2 ); function hide_table_shipping_for_shipping_class( $rates, $package ) { $shipping_class_target = 137; $in_cart = false; foreach( WC()->cart->cart_contents as $key => $values ) { if( $values[ 'data' ]->get_shipping_class_id() === $shipping_class_target ) { $in_cart = true; break; } } if( $in_cart ) { unset( $rates['mh_wc_table_rate_plus_85'] ); unset( $rates['mh_wc_table_rate_plus_1' ] ); // 省略其余与原代码一致的unset语句 unset( $rates['mh_wc_table_rate_plus_77' ] ); } return $rates; }
The issue here is that it stops checking as soon as it finds one item with the target class, then removes the rates — which is the opposite of your requirement.
Fixed Code (Using LoicTheAztec's Solution)
After testing different approaches, this revised code gets the logic right:
add_filter( 'woocommerce_package_rates', 'hide_table_shipping_for_shipping_class', 10, 2 ); function hide_table_shipping_for_shipping_class( $rates, $package ) { $targeted_class = 137; // <== Your targetted shipping class // Loop through cart items to check if any item doesn't have the targetted shipping class foreach( WC()->cart->cart_contents as $key => $values ) { // If we find even one item without the target class if( $values[ 'data' ]->get_shipping_class_id() != $targeted_class ) { // Keep all original rates (we don't remove anything here) return $rates; // <== Exit early, return full rate list } } // All shipping instance IDs to be removed (fill in your full list) $instance_ids = array( '1', '2', ..., '103' ); foreach( $instance_ids as $instance_id ) unset( $rates["mh_wc_table_rate_plus_$instance_id"] ); return $rates; }
How This Fixed Logic Works
- Check for non-target items first: We loop through every cart item. If we find any item that doesn't belong to the target shipping class, we immediately return the full set of shipping rates (no changes made).
- Only remove rates if all items qualify: If the loop completes without finding any non-target items, that means every item is in the target class. We then iterate through our list of rate IDs to remove and unset them all at once.
This way, the shipping rates are only removed when your cart meets the "all items in target class" condition — exactly what you needed.
内容的提问来源于stack exchange,提问作者Maria

