Skip to content
Advertisement

Custom shipping rates programmatically in Woocommerce

I Want to calculate custom shipping rates based on cart amount for woocommerce, My requirement as follows,

Cart amount

  1. 0-10 => £4.99 (shipping_rate_id = flat_rate:12),
  2. 10-20 => £3.99 (shipping_rate_id = flat_rate:13),
  3. 20-30 => £2.99 (shipping_rate_id = flat_rate:14),
  4. 30-40 => £1.99 (shipping_rate_id = flat_rate:15),
  5. over 40 => Free Shipping (shipping_rate_id = flat_rate:17)

Note : We Do not calculate shipping charge for tobacco category. If someone buy tobacco item, Tobacco item price do not use for shipping charge calculation. To accomplish this all the tobacco items added to free shipping class (id = 150).

Setup custom query to accomplish above requirement, but it does not work as I expected

add_filter('woocommerce_package_rates', 'custom_shipping_rates_based_on_shipping_class', 11, 2);

function custom_shipping_rates_based_on_shipping_class($rates, $package) {
  if (is_admin() && !defined('DOING_AJAX'))
    return;

  // HERE define your shipping class to find
  $class = array(150);

  // HERE define the shipping method to change rates for
  $shipping_rate_ids = array('flat_rate:12', 'flat_rate:13', 'flat_rate:14', 'flat_rate:15');

  // Initialising
  $item_price = $item_qty = $item_total = 0;

  // Loop through cart items
  foreach($package['contents'] as $cart_item_key => $cart_item) {
    $item_shipping_class_id = $cart_item['data'] - > get_shipping_class_id();

    if (!in_array($item_shipping_class_id, $class)) {
      $item_price += $cart_item['data'] - > get_price(); // Sum line item prices that have target shipping class
      $item_qty += $cart_item['quantity']; // Sum line item prices that have target shipping class
      $item_total = $item_price * $item_qty;
    }
  }

  // Loop through shipping rates
  foreach($rates as $rate_key => $rate) {
    if (in_array($rate_key, $shipping_rate_ids)) {
      if ($item_total > 0 && $item_total < 10) {
        $rates[$rate_key] - > cost = 4.99;
        unset($rates['flat_rate:13']);
        unset($rates['flat_rate:14']);
        unset($rates['flat_rate:15']);
        unset($rates['flat_rate:17']);
      }
      elseif($item_total > 10.01 && $item_total < 20) {
        $rates[$rate_key] - > cost = 3.99;
        unset($rates['flat_rate:12']);
        unset($rates['flat_rate:14']);
        unset($rates['flat_rate:15']);
        unset($rates['flat_rate:17']);
      }
      elseif($item_total > 20.01 && $item_total < 30) {
        $rates[$rate_key] - > cost = 2.99;
        unset($rates['flat_rate:12']);
        unset($rates['flat_rate:13']);
        unset($rates['flat_rate:15']);
        unset($rates['flat_rate:17']);
      }
      elseif($item_total > 30.01 && $item_total < 40) {
        $rates[$rate_key] - > cost = 1.99;
        unset($rates['flat_rate:12']);
        unset($rates['flat_rate:13']);
        unset($rates['flat_rate:14']);
        unset($rates['flat_rate:17']);
      } else {
        $rates[$rate_key] - > cost = 0;
        unset($rates['flat_rate:12']);
        unset($rates['flat_rate:13']);
        unset($rates['flat_rate:14']);
        unset($rates['flat_rate:15']);
      }
    }
  }
  return $rates;
}

Above code not perfect for all the scenarios, please help me.

Advertisement

Answer

If you know the value of shipping_rate_id for each shipping method it means that in the WooCommerce plugin (WooCommerce > Settings > Shipping > Shipping Zones > Edit > Shipping Methods) you have already created and assigned a shipping cost (or free) for each individual shipping method.

So you don’t need to change the cost of each one again.

Also for free shipping the shipping rate id will be free_shipping:17 instead of flat_rate:17.
Unless you have created a zero cost shipping method (flat rate instead free shipping).

The working code will be:

add_filter('woocommerce_package_rates', 'change_shipping_method_based_on_cart_total', 11, 2);
function change_shipping_method_based_on_cart_total( $rates, $package ) {

    // set the shipping class id to exclude
    $shipping_class_id = 150;

    // initializes the total cart of products
    $total_cart = 0;

    foreach ( WC()->cart->get_cart() as $cart_item ) {
        $product = $cart_item['data'];
        // if the product has the shipping class id equal to "$shipping_class_id" it is excluded from the count
        if ( $product->get_shipping_class_id() == $shipping_class_id ) {
            continue;
        }
        $qty = $cart_item['quantity'];
        $price = $cart_item['data']->get_price();
        // add the product line total to the total
        $total_cart += $price * $qty;

    }

    switch ( true ) {
        case $total_cart < 10: // £4.99
            // only the "flat_rate:12" shipping method will be enabled
            unset($rates['flat_rate:13']);
            unset($rates['flat_rate:14']);
            unset($rates['flat_rate:15']);
            unset($rates['flat_rate:17']); // or "unset( $rates['free_shipping:17'] );"
            break;
        case $total_cart >= 10 && $total_cart < 20: // £3.99
            // only the "flat_rate:13" shipping method will be enabled
            unset($rates['flat_rate:12']);
            unset($rates['flat_rate:14']);
            unset($rates['flat_rate:15']);
            unset($rates['flat_rate:17']); // or "unset( $rates['free_shipping:17'] );"
            break;
        case $total_cart >= 20 && $total_cart < 30: // £2.99
            // only the "flat_rate:14" shipping method will be enabled
            unset($rates['flat_rate:12']);
            unset($rates['flat_rate:13']);
            unset($rates['flat_rate:15']);
            unset($rates['flat_rate:17']); // or "unset( $rates['free_shipping:17'] );"
            break;
        case $total_cart >= 30 && $total_cart < 40: // £1.99
            // only the "flat_rate:15" shipping method will be enabled
            unset($rates['flat_rate:12']);
            unset($rates['flat_rate:13']);
            unset($rates['flat_rate:14']);
            unset($rates['flat_rate:17']);
            break;
        case $total_cart >= 40: // free
            // only the "flat_rate:17" or "free_shipping:17" shipping method will be enabled
            unset($rates['flat_rate:12']);
            unset($rates['flat_rate:13']);
            unset($rates['flat_rate:14']);
            unset($rates['flat_rate:15']);
            break;
    }
    
    return $rates;
}

The code has been tested and works. The code goes into your theme’s functions.php file.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement