WooCommerce按重量计算运费及免运费类失效问题求助
Fix WooCommerce Weight-Based Shipping with Free Shipping Class Priority
Let's fix your free shipping class issue while honoring your core rule: if there's at least one paid shipping item in the cart, weight-based rates apply; only when all items are free shipping do we show the free option.
The Problem with Your Original Code
Your current code only checks the total cart weight, but it doesn't account for the free_shipping class on individual products. It always hides the free shipping option whenever the weight falls into either tier, which is why the free shipping class never triggers.
Fixed Code
Replace your existing custom_tiered_shipping_rates function with this updated version:
add_filter( 'woocommerce_package_rates', 'custom_tiered_shipping_rates_with_free_class', 9999, 2 ); function custom_tiered_shipping_rates_with_free_class( $rates, $package ) { // Check if any item in the cart requires paid shipping (not free_shipping class) $has_paid_shipping_items = false; foreach ( $package['contents'] as $item ) { $product = $item['data']; $shipping_class_slug = $product->get_shipping_class(); // Flip the flag if we find a non-free-shipping item if ( $shipping_class_slug !== 'free_shipping' ) { $has_paid_shipping_items = true; break; } } // Scenario 1: Cart has paid shipping items – use weight-based rates if ( $has_paid_shipping_items ) { $total_weight = WC()->cart->get_cart_contents_weight(); // Show only <19kg rate if weight is under 19kg if ( $total_weight < 19 ) { if ( isset( $rates['flat_rate:21'] ) ) { unset( $rates['flat_rate:22'], $rates['flat_rate:24'] ); } } // Show only >19kg rate if weight exceeds 19kg (matches your original $300 rule) elseif ( $total_weight > 19 ) { if ( isset( $rates['flat_rate:22'] ) ) { unset( $rates['flat_rate:21'], $rates['flat_rate:24'] ); } } // Optional: Handle exact 19kg (adjust if you want a specific rate here) else { unset( $rates['flat_rate:21'], $rates['flat_rate:22'] ); } } // Scenario 2: All items are free shipping – only show free option else { if ( isset( $rates['flat_rate:24'] ) ) { unset( $rates['flat_rate:21'], $rates['flat_rate:22'] ); } } return $rates; }
Key Changes Explained
- Paid Shipping Check: We loop through every item in the cart to check if any product doesn't have the
free_shippingclass. If so, we stick strictly to weight-based pricing. - Free Shipping Only for All-Free Carts: Only when every single item is marked with
free_shippingdo we hide the paid rates and show the free shipping option. - Weight Rule Alignment: I adjusted the weight check to
>19to match your original rule (over 19kg = $300). If you meant to use 20kg as the threshold, just change that value to>20.
Important Checks to Ensure It Works
- Verify Shipping Class Slug: Go to WooCommerce > Products > Shipping Classes and confirm your free shipping class has the slug
free_shipping. If it's different, update the value in the code. - Confirm Rate IDs: Double-check that
flat_rate:21,flat_rate:22, andflat_rate:24match the actual IDs of your shipping methods. You can find these by editing a shipping method and looking at the URL (look for therate_idparameter). - Clear WooCommerce Cache: After adding the code, go to WooCommerce > Settings > Shipping, make a tiny change (like toggling a setting off/on), and save. This clears the shipping rate cache so your new rules take effect.
内容的提问来源于stack exchange,提问作者Victor S.
相关产品推荐
相关产品推荐

