skip to Main Content

I am trying to get woocommerce to remove all shipping classes and charge for just the two highest charges found within the cart but my function is not working. It is removing all the shipping charges and setting the shipping cost to zero.

EDIT: There is default functionality within a shipping zone to charge shipping classes set as "Per order: Charge shipping for the most expensive shipping class" but I need this to be "Per order: Charge shipping for the two most expensive shipping classes"

I have commented each step to show my understanding.

function charge_for_two_highest_shipping_classes( $rates ) {
    // Sort rates by cost, in ascending order
    usort( $rates, function( $a, $b ) {
        return $a->cost - $b->cost;
    } );

    // Remove all shipping rates except the two highest
    $highest_rates = array_slice( $rates, -2 );

    // Set all other rates to zero
    foreach ( $rates as $rate ) {
        if ( ! in_array( $rate, $highest_rates, true ) ) {
            $shipping_class_id = 0;
            foreach ( $rate->get_meta_data() as $meta ) {
                if ( 'shipping_class_id' === $meta->key ) {
                    $shipping_class_id = (int) $meta->value;
                    break;
                }
            }
            $rate->cost = 0;
            $rate->taxes = array();
            $rate->set_meta_data( 'shipping_class_id', $shipping_class_id );
        }
    }

    return $highest_rates;
}
add_filter( 'woocommerce_package_rates', 'charge_for_two_highest_shipping_classes', 10, 1 );

2

Answers


  1. What you are trying to achieve is not as simple as you think.
    The woocommerce_package_rates hook is wrong because all shipping class calculations are already done at this point.
    The WooCommerce code you are looking for is here:

    wp-content/plugins/woocommerce/includes/shipping/flat-rate/class-wc-shipping-flat-rate.php

    See in the calculate_shipping function and look for the $highest_class_cost.

    You could patch this function, but I wouldn’t recommend it. There is no hook for this, you could only create new flat rates programmatically and do your logic there.

    Login or Signup to reply.
  2. To sorts the rates in descending order and takes the first two elements (the two highest rates) and removes all other rates from the array. you can use this modification, Hope it might helpful to you 🙂 Thanks

    function charge_for_two_highest_shipping_classes( $rates ) {
        // Sort rates by cost, in descending order
        usort( $rates, function( $a, $b ) {
            return $b->cost - $a->cost;
        } );
    
        // Remove all shipping rates except the two highest
        $highest_rates = array_slice( $rates, 0, 2 );
        foreach ( $rates as $key => $rate ) {
            if ( ! in_array( $rate, $highest_rates, true ) ) {
                unset( $rates[$key] );
            }
        }
    
        return $highest_rates;
    }
    add_filter( 'woocommerce_package_rates', 'charge_for_two_highest_shipping_classes', 10, 1 );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search