Search code examples
phpwordpresswoocommercecheckoutshipping-method

Customize specific shipping method costs not being applied to WooCommerce totals


With the following code, I have got the correct displayed shipping method cost based on a subsidy (see this thread):

add_filter( 'woocommerce_cart_shipping_method_full_label', 'custom_shipping_method_full_label', 10, 2 );
function custom_shipping_method_full_label( $label, $method ) {
    if ( !in_array( $method->get_method_id(), array( 'free_shipping', 'local_pickup' ), true ) && 0 < $method->cost ) {
        $label    = $method->get_label(); // Get shipping label without cost
        $new_cost = $method->cost - get_total_subsidies( WC()->cart->get_cart() );

        if ( $new_cost > 0 ) {
            $method->cost = $new_cost;
            $label .= ': ' . wc_price( $new_cost );
        } else {
            $method->cost = 0;
            $label .= ': ' .' <span class="free-cost">' . __('Free!', 'woocommerce').'</span>';
        }
    }
    return $label;
}

But it doesn't get extended to the totals calculations, taking into account the original shipping method cost.

I need the new cost to be the current cost for totals calculations from cart and checkout pages.


Solution

  • To handle the shipping costs and totals recalculations (+ handle those shipping methods display), you need to replace your current code with the following:

    // Utility function: Reset shipping taxes
    function zero_taxes( $tax ) {
        return 0;
    }
    
    // Set new shipping rate costs
    add_filter('woocommerce_package_rates', 'custom_shipping_rates_cost', 10, 2);
    function custom_shipping_rates_cost( $rates, $package ) {
        $total_subsidies = get_total_subsidies( $package['contents'] );
        
        if ( ! $total_subsidies ) {
            return $rates;
        }
    
        // Loop through shipping rates
        foreach ($rates as $rate_key => $rate) {
            if( ! in_array( $rate->method_id, array( 'free_shipping', 'local_pickup' ), true ) && $rate->cost > 0 ) {
                $new_cost = $rate->cost - $total_subsidies;
    
                if ( $new_cost > 0 ) {
                    $rates[$rate_key]->cost = $new_cost; // Set the new cost
                } else {
                    $rates[$rate_key]->cost   = 0; // Null the cost
                    $rates[$rate_key]->taxes  = array_map('zero_taxes', $rate->taxes);  // Null shipping costs taxes
                    $rates[$rate_key]->label .= ': <span class="free-cost">' . __('Free!', 'woocommerce') . '</span>'; // Custom displayed label
                }
            }
        }
        return $rates;
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). It should work.

    Important: Empty your cart to refresh the shipping methods cached data.

    Related:
    Display total subsidy amount based on WooCommerce cart items shipping class and quantity