Are you someone who is running your online store? OR are you someone who is planning to Hire Woocommerce Developers to launch an online store on the WooCommerce platform? If your answer to any of these questions is YES, then you must be knowing that one of the things that annoy you while setting up an E-Commerce store is Shipping, isn’t it?

Many E-Commerce store owners get agitated when they hear anything related to shipping. The reason for that is, they face a lot of problems in setting up Shipping. There are many Shipping Plugins in WooCommerce that can seal the deal for you.

WooCommerce has brought great ease in setting up online stores with its key attributes. WooCommerce can be made much more easier to implement in your online store development by hiring Indian programmers as they possess proficiency in it and can add great value to your expectations.

According to a survey carried out by BigCommerce, the top three factors which determine whether people shop or not are: price (87%), shipping cost (80%) & discount offers (71%). According to research conducted by SmallBizTrends, 28% of shoppers will abandon the shopping cart if the shipping costs are too high.

After looking at the above statistics, you can conclude two significant things:

  • Most of Shoppers analyze the shipping costs before making any purchasing decision.
  • E-Commerce owners are missing out on customer acquisition opportunities due to high shipping costs.

Therefore, as an E-Commerce store owner, you need to give prime importance to the shipping functionality. WooCommerce platform provides you with default shipping functionality which makes the job of store owners very easy.

However, there are some situations where the default shipping method won’t work. For those situations, you need to set up Custom Shipping In WooCommerce store.

In this blog, we’re going to provide you with an in-depth guide on how to Create A Custom Shipping Method For a WooCommerce store which will ease out all your problems.

So, let’s get the things underway.

There are some prerequisites that you need to satisfy before proceeding further. They are as follows:

  • WordPress
  • WooCommerce Plugin Installed & Activated
  • Editor Of Your Choice

Shipping Rules For The Shipping Methods

To understand the concept of Customs Shipping In WooCommerce in a better way, let us take an example. In this section, we will define our shipping rules based on which we will develop a custom shipping method right through this blog.

Here’s how our shipping method will work

The cost of shipping will be calculated based on the weights as well as the zone. A zone will be a number assigned to a particular country as well as its prices. The higher the number, the longer the shipping distance will be.
Suppose our company is providing shipping services in the following countries:

  • USA
  • Canada
  • Germany
  • United Kingdom
  • Italy
  • Spain
  • Croatia

Here, we have assumed that our company is located in Croatia, and therefore, it will be assigned zone 0, and based on that rest of the values will be decided.

They are as follows:

  • Croatia: 0
  • Italy: 1
  • Germany: 1
  • United Kingdom: 2
  • Spain: 2
  • Canada: 3
  • USA: 3

Now, it’s time to decide the prices based on the zones we have decided in the previous step.

  • Zone 0: $10
  • Zone 1: $30
  • Zone 2: $50
  • Zone 3: $70

Last but not least is to decide the price based on weight. They are as follows:

  • 0-10 kg: $0
  • 11-30 kg: $5
  • 31-50 kg: $10
  • 51-100 kg: $20

Introduction To WooCommerce Shipping API

In the previous section, we have decided the shipping rules. In this section, we’re going to explore the WooCommerce Shopping API by which you can create a custom shipping method for your WooCommerce store.

For knowing the practical use of WooCommerce Shopping API, you should contact and Hire WooCommerce Developer from a well-known firm.

Now, to create a shipping method, you need to extend the class from WC_Shipping_Method. The attributes associated with this class are as follows:

$id: ID (slug, keyword) of our shipping

$number: Integer ID

$method_title: Name of shipping shown in admin

$method_description: Short description of shipping

$enabled: String Boolean (“yes” or “no”) whether our shipping method is enabled or not

$title: Used to display shipping name
$availability: Defines if the shipping is available or not

$countries: Countries for you can use this method

$tax_status: Default value is taxable. If it is taxable, then the tax will be charged

$fee: Default value is 0. Fees for the method.

$minimum_fee: The minimum fee for the method. The default value is null.

$has_settings: Defines if this method has any settings. The default value is true.

$supports: Array containing features this method supports

$rates: Array of rates for shipping

The methods associated with WC_Shipping_Method class are as follows:

is_taxable(): Returns whether or not we need to calculate tax for the shipping rate

add_rate( $args = array() ): Pushes a shipping rate defined in the parameter $args into the attribute $rates.

has_settings(): Returns the value of the attribute $has_settings.

is_available(): Returns if the shipping is available for a particular country or not

get_title(): Returns the title of this shipping

get_fee( $fee, $total ): Returns fee value for this shipping based on the parsed $fee and $total

supports( $feature ): Returns if this shipping method is supporting a feature or not

There are also some other methods which we will utilize for calculating the shipping cost. They are as follows:

init(): Creates the form fields as well as the settings

calculate_shipping( $package ): This is the method used to calculate the cost for this shipping

In the calculate_shipping method, we will add the rate with the help of add_rate method. Now, the add_rate method accepts an array which comprises of various options. They are as follows:

id: ID of the rate

label: Label for the rate

cost: Amount of shipping

taxes: It accepts an array of taxes or nothing for calculating the tax

calc_tax: Accepts per_order or per_item.

To register the shipping method, we need to add our shipping method in the array of the registered way by passing the name of our class. By doing this, we will get access to the array after which we’ll send the modified back using a WordPress filter – woocommerce_shipping_methods which are inside the WooCommerce plugin.

Creating A New Shipping Class

So far, we have defined the shipping rules for our custom shipping method and also analyzed the WooCommerce Shipping API. In this section, we will develop our shipping method in the form of a plugin.

For that purpose, we need to create a new folder named my-shipping under wp-content/plugins and also create a file with the same name my-shipping.php. In this file, you should add the following code as shown below in the snippet.

<?php
 
if ( ! defined( 'WPINC' ) ) {
 
    die;
 
}
 
/*
 * Check if WooCommerce is active
 */
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
 
    function my_shipping_method() {
        if ( ! class_exists( 'My_Shipping_Method' ) ) {
            class My_Shipping_Method extends WC_Shipping_Method {
               
                public function __construct() {
                    $this->id                 = “my”; 
                    $this->method_title       = __( 'My Shipping', 'my' );  
                    $this->method_description = __( 'Custom Shipping Method for My Shipping', 'my' ); 
 
                    $this->init();
 
                    $this->enabled = isset( $this->settings['enabled'] ) ? $this->settings['enabled'] : 'yes';
                    $this->title = isset( $this->settings['title'] ) ? $this->settings['title'] : __( 'My Shipping', 'my' );
                }
 
  
              function init() {
                    // Load the settings API
                    $this->init_form_fields(); 
                    $this->init_settings(); 
 
                    // Save settings in admin if you have any defined
                    add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
                }
 
           
                function init_form_fields() { 
 
                    // We will add our settings here
 
                }
 
                /**
                 * This function is used to calculate the shipping cost. Within this function we can check for weights, dimensions and other parameters.   */
              
             
                public function calculate_shipping( $package ) {
                    
                    // We will add the cost, rate and logics in here
                    
                }
            }
        }
    }
 
    add_action( 'woocommerce_shipping_init', 'my_shipping_method' );
 
    function add_my_shipping_method( $methods ) {
        $methods[] = 'My_Shipping_Method';
        return $methods;
    }
 
    add_filter( 'woocommerce_shipping_methods', 'add_my_shipping_method' );
}

Now, let’s understand how the above code works. It may sound complicated, but we’re here to help you out. First of all, we check if the constant WPINC is defined or not. By The reason behind that is, by checking this, you will be able to know whether someone is trying to access the file directly or from a location outside of WordPress.

Once you’re sure that you’re accessing the file from WordPress, you can proceed further. The next step is to make sure that WooCommerce is active, as only after that you can start creating your customized shipping method.

After you’re sure that WooCommerce is working well, you need to check if the file woocommerce.php is in the array of plugins that are saved under the database named as active_plugins. The next step is to create a my_shipping_method which you need to add in woocommerce_shipping_init which is the primary action for the WooCommerce shipping.

By utilizing this process, you make sure that your shipping method is included in WooCommerce. You can use __construct method for some general attributes.

Setting Country Availability

As we have discussed earlier, that, our shipping is limited to a few countries. So, in this section, we will set available countries in the shipping method just before the init() method inside a __construct method. Add the following code in the __construct method as shown below in the snippet.

<?php
//...
$this->method_description = __( 'Custom Shipping Method for My Custom Shipping', 'my' ); 
 
// Availability & Countries
$this->availability = 'including';
$this->countries = array(
    'US', // United States of America
    'CA', // Canada
    'DE', // Germany
    'GB', // United Kingdom
    'IT', // Italy
    'ES', // Spain
    'HR' // Croatia
    );
 
$this->init();
//…

Here, the attribute availability is set to ‘including’ which means that shipping is available for the countries included in the attribute countries. Now, when WooCommerce wants to display the available shopping to the customers, it will check if the shipping country is there in the attribute countries for shipping.

Creating Settings

If you’ve closely analyzed our code for the __construct method, you can see that we’re checking settings for enabled & title properties. In this section, we will create fields which can help us to change the properties. For that purpose, you should paste the following code in init_form_fields.

<?php
 
  function init_form_fields() { 
 
        $this->form_fields = array(
 
         'enabled' => array(
              'title' => __( 'Enable', 'my' ),
              'type' => 'checkbox',
              'description' => __( 'Enable this shipping.', 'my' ),
              'default' => 'yes'
              ),
 
         'title' => array(
            'title' => __( 'Title', 'my' ),
              'type' => 'text',
              'description' => __( 'Title to be display on site', 'my' ),
              'default' => __( 'My Shipping', 'my' )
              ),
 
         );
 
    }

Now, you can go to the WordPress Admin & change the settings by following this path – WooCommerce->Settings->Shipping->My Custom Shipping as shown in the screenshot:

1 16
In addition to all these, we have also stated that our shipping method will calculate weight up to 100 kg. Suppose, this rule changes in the future, know what you can do? So, for that purpose, we have devised a code which enables us to edit the settings. We have added that setting in the method init_form_fields as shown in the coding snippet.

<?php
 
 function init_form_fields() { 
 
    $this->form_fields = array(
 
     'enabled' => array(
          'title' => __( 'Enable', 'my' ),
          'type' => 'checkbox',
          'description' => __( 'Enable this shipping.', 'my' ),
          'default' => 'yes'
          ),
 
     'title' => array(
        'title' => __( 'Title', 'my' ),
          'type' => 'text',
          'description' => __( 'Title to be display on site', 'my shipping' ),
          'default' => __( 'My Custom Shipping', 'my' )
          ),
 
     'weight' => array(
        'title' => __( 'Weight (kg)', 'my' ),
          'type' => 'number',
          'description' => __( 'Maximum allowed weight', 'my' ),
          'default' => 100
          ),
 
     );
 
}

Now, you can customize everything, right from maximum weight to country to zones & everything else as per your shipping requirement.

Calculating The Shipping Cost

You’ve set up everything, except the last step. In this section, we will complete that final step by devising a code for calculating the shipping cost after which you can utilize the custom shipping method. For that purpose, we’re going to update the calculate_shipping method in 3 phases so that you can understand easily.

Phase 1: Get The Cost By Weight

For this purpose, you can utilize the code as shown below in the snippet.

<?php
//...
public function calculate_shipping( $package ) {
                   
   $weight = 0;
   $cost = 0;
   $country = $package["destination"]["country"];
 
   foreach ( $package['contents'] as $item_id => $values ) 
   { 
       $_product = $values['data']; 
       $weight = $weight + $_product->get_weight() * $values['quantity']; 
   }
 
   $weight = wc_get_weight( $weight, 'kg' );
 
   if( $weight <= 10 ) {
 
       $cost = 0;
 
   } elseif( $weight <= 30 ) {
 
       $cost = 5;
 
   } elseif( $weight <= 50 ) {
 
       $cost = 10;
 
   } else {
 
       $cost = 20;
 
   }
    
}

Now, let’s try to dissect this code. Here, we have defined a few variables – $weight, $cost, and $country. $weight holds the total weight of all the products, $cost holds the cost of shipping & $country holds the ISO code for a particular country.

Here, we have opted for the WooCommerce Weight Based Shipping approach, and therefore, we will get the total weight by analyzing the cart & then, adding the weight for each product in the variable $weight. Once we have the total weight, you can utilize wc_get_weight to convert weight into kilograms since we have set our weight in kilograms in the shipping method.

The last step is to calculate the shipping cost based on total weight. Here, we have not set the limit for the maximum weight, i.e., 100 kg for our shipping method. We will fix those restrictions later on when the checkout process happens.

Phase 2: Get The Cost By Shipping Country

Here, we will calculate the shipping cost based on the shipping country. For that purpose, you can utilize the following code snippet.

<?php
//...
public function calculate_shipping( $package ) {
     
    //...
     
    $countryZones = array(
        'HR' => 0,
        'US' => 3,
        'GB' => 2,
        'CA' => 3,
        'ES' => 2,
        'DE' => 1,
        'IT' => 1
        );
 
    $zonePrices = array(
        0 => 10,
        1 => 30,
        2 => 50,
        3 => 70
        );
 
    $zoneFromCountry = $countryZones[ $country ];
    $priceFromZone = $zonePrices[ $zoneFromCountry ];
 
    $cost += $priceFromZone;
     
}

Here, the array $countryZones holds the zone for each country and the array $zonePrices holds the price for each of these zones. Once we have both the array set, we can get the shipping cost by:

  • Passing ISO code to array $countryZones to get the zone
  • Pass the zone to array $zonePrices to get the price
  • Add the return cost to the $cost variable

Phase 3: Registering The Rate

We have calculated the cost by total weights as well as by shipping country. Now, the last step is to register the rate. For that purpose, you can utilize the following coding snippet.

<?php
 
//...
public function calculate_shipping( $package ) {
    //...
    $rate = array(
        'id' => $this->id,
        'label' => $this->title,
        'cost' => $cost
    );
     
    $this->add_rate( $rate );
}
//... 

Here’s the whole code for calculating the shipping cost.

<?php
 
//...
 
public function calculate_shipping( $package ) {
                    
    $weight = 0;
    $cost = 0;
    $country = $package["destination"]["country"];
 
    foreach ( $package['contents'] as $item_id => $values ) 
    { 
        $_product = $values['data']; 
        $weight = $weight + $_product->get_weight() * $values['quantity']; 
    }
 
    $weight = wc_get_weight( $weight, 'kg' );
 
    if( $weight <= 10 ) {
 
        $cost = 0;
 
    } elseif( $weight <= 30 ) {
 
        $cost = 5;
 
    } elseif( $weight <= 50 ) {
 
        $cost = 10;
 
    } else {
 
        $cost = 20;
 
    }
 
    $countryZones = array(
        'HR' => 0,
        'US' => 3,
        'GB' => 2,
        'CA' => 3,
        'ES' => 2,
        'DE' => 1,
        'IT' => 1
        );
 
    $zonePrices = array(
        0 => 10,
        1 => 30,
        2 => 50,
        3 => 70
        );
 
    $zoneFromCountry = $countryZones[ $country ];
    $priceFromZone = $zonePrices[ $zoneFromCountry ];
 
    $cost += $priceFromZone;
 
    $rate = array(
        'id' => $this->id,
        'label' => $this->title,
        'cost' => $cost
    );
 
    $this->add_rate( $rate );
    
}

Now, if you try to view your cart or go to the checkout page and select a country that is available for shipping, you will get the shipping cost as per your customization. Here’s how you can calculate a shipping cost for zone 3 as per our custom shipping method.

2 16

Adding Restrictions

So far, we have set up our custom shipping method and also got the result. However, we have defined the maximum weight limit for our shipping cart, but have not added that restrictions in our shipping methods. By adding the restriction, you can notify the customers that they can’t ship the order due to the weight.

Restriction Function

Now, for adding the restriction, we will make the use of My_Shipping_Method, we will check its weight limit and total weight in the cart, and if weight exceeds the maximum limit, then we will send a notification message to the customer. After the filter woocommerce_shipping_methods, add the following code.

<?php
 
function my_validate_order( $posted )   {
 
    $packages = WC()->shipping->get_packages();
     
    $chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
     
    if( is_array( $chosen_methods ) && in_array( 'my', $chosen_methods ) ) {
         
        foreach ( $packages as $i => $package ) {
     
            if ( $chosen_methods[ $i ] != "my" ) {
                         
                continue;
                         
            }
     
            $My_Shipping_Method = new My_Shipping_Method();
            $weightLimit = (int) $My_Shipping_Method->settings['weight'];
            $weight = 0;
     
            foreach ( $package['contents'] as $item_id => $values ) 
            { 
                $_product = $values['data']; 
                $weight = $weight + $_product->get_weight() * $values['quantity']; 
            }
     
            $weight = wc_get_weight( $weight, 'kg' );
            
            if( $weight > $weightLimit ) {
     
                    $message = sprintf( __( 'Sorry, %d kg exceeds the maximum weight of %d kg for %s', 'my' ), $weight, $weightLimit, $My_Shipping_Method->title );
                         
                    $messageType = "error";
     
                    if( ! wc_has_notice( $message, $messageType ) ) {
                     
                        wc_add_notice( $message, $messageType );
                  
                    }
            }
        }       
    } 
}

Notifying On Order Update

Each time when a customer changes something in the checkout page, the order update happens. We will add the function my_validate_order to the action woocommerce_review_order_before_cart_contents. You need to call this action after you set up everything so that we can get custom shipping methods & packages.

To notify on the order update, add the following code after my_validate_order.

<?php
 
add_action( 'woocommerce_review_order_before_cart_contents', 'my_validate_order' , 10 );

Notifying On Checkout

Whenever any customer clicks on the button to place the order or buy it, WooCommerce will process all the billing & shipping data alongside the cart. If there is an error from the WooCommerce, then the checkout process will stop. The action which triggers just before the WooCommerce checks if any error notice arrives is woocommerce_after_checkout_validation.

Now, to notify on the checkout, add the function to the woocommerce_after_checkout_validation action as shown below.

<?php
 
add_action( 'woocommerce_after_checkout_validation', 'my_validate_order' , 10 );

Full Code For Custom Shipping

Finally, we put together the full code for the custom shipping in front of you so that it becomes easy for you to implement it for your WooCommerce store.

<?php
 
if ( ! defined( 'WPINC' ) ) {
 
    die;
 
}
 
/*
 * Check if WooCommerce is active
 */
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
 
    function my_shipping_method() {
        if ( ! class_exists( 'My_Shipping_Method' ) ) {
            class My_Shipping_Method extends WC_Shipping_Method {
               
                public function __construct() {
                    $this->id                 = ‘my’'; 
                    $this->method_title       = __( 'TMy Shipping', 'my' );  
                    $this->method_description = __( 'Custom Shipping Method', 'my' ); 
 
                    // Availability & Countries
                    $this->availability = 'including';
                    $this->countries = array(
                        'US', // United States of America
                        'CA', // Canada
                        'DE', // Germany
                        'GB', // United Kingdom
                        'IT',   // Italy
                        'ES', // Spain
                        'HR'  // Croatia
                        );
 
                    $this->init();
 
                    $this->enabled = isset( $this->settings['enabled'] ) ? $this->settings['enabled'] : 'yes';
                    $this->title = isset( $this->settings['title'] ) ? $this->settings['title'] : __( 'MyShipping', 'my' );
                }
 
           
              function init() {
                    // Load the settings API
                    $this->init_form_fields(); 
                    $this->init_settings(); 
 
                    // Save settings in admin if you have any defined
                    add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
                }
 
            
                function init_form_fields() { 
 
                    $this->form_fields = array(
 
                     'enabled' => array(
                          'title' => __( 'Enable', 'my' ),
                          'type' => 'checkbox',
                          'description' => __( 'Enable this shipping.', 'my' ),
                          'default' => 'yes'
                          ),
 
                     'title' => array(
                        'title' => __( 'Title', 'my' ),
                          'type' => 'text',
                          'description' => __( 'Title to be display on site', 'my' ),
                          'default' => __( 'MyShipping', 'my' )
                          ),
 
                     'weight' => array(
                        'title' => __( 'Weight (kg)', 'my' ),
                          'type' => 'number',
                          'description' => __( 'Maximum allowed weight', 'my' ),
                          'default' => 100
                          ),
 
                     );
 
                }
 
                /**
                 * This function is used to calculate the shipping cost. Within this function we can check for weights, dimensions and other parameters.
               
                public function calculate_shipping( $package ) {
                    
                    $weight = 0;
                    $cost = 0;
                    $country = $package["destination"]["country"];
 
                    foreach ( $package['contents'] as $item_id => $values ) 
                    { 
                        $_product = $values['data']; 
                        $weight = $weight + $_product->get_weight() * $values['quantity']; 
                    }
 
                    $weight = wc_get_weight( $weight, 'kg' );
 
                    if( $weight <= 10 ) {
 
                        $cost = 0;
 
                    } elseif( $weight <= 30 ) {
 
                        $cost = 5;
 
                    } elseif( $weight <= 50 ) {
 
                        $cost = 10;
 
                    } else {
 
                        $cost = 20;
 
                    }
 
                    $countryZones = array(
                        'HR' => 0,
                        'US' => 3,
                        'GB' => 2,
                        'CA' => 3,
                        'ES' => 2,
                        'DE' => 1,
                        'IT' => 1
                        );
 
                    $zonePrices = array(
                        0 => 10,
                        1 => 30,
                        2 => 50,
                        3 => 70
                        );
 
                    $zoneFromCountry = $countryZones[ $country ];
                    $priceFromZone = $zonePrices[ $zoneFromCountry ];
 
                    $cost += $priceFromZone;
 
                    $rate = array(
                        'id' => $this->id,
                        'label' => $this->title,
                        'cost' => $cost
                    );
 
                    $this->add_rate( $rate );
                    
                }
            }
        }
    }
 
    add_action( 'woocommerce_shipping_init', 'my_shipping_method' );
 
    function add_my_shipping_method( $methods ) {
        $methods[] = 'My_Shipping_Method';
        return $methods;
    }
 
    add_filter( 'woocommerce_shipping_methods', 'add_my_shipping_method' );
 
    function my_validate_order( $posted )   {
 
        $packages = WC()->shipping->get_packages();
 
        $chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
         
        if( is_array( $chosen_methods ) && in_array( 'my', $chosen_methods ) ) {
             
            foreach ( $packages as $i => $package ) {
 
                if ( $chosen_methods[ $i ] != "my" ) {
                             
                    continue;
                             
                }
 
                $My_Shipping_Method = new My_Shipping_Method();
                $weightLimit = (int) $My_Shipping_Method->settings['weight'];
                $weight = 0;
 
                foreach ( $package['contents'] as $item_id => $values ) 
                { 
                    $_product = $values['data']; 
                    $weight = $weight + $_product->get_weight() * $values['quantity']; 
                }
 
                $weight = wc_get_weight( $weight, 'kg' );
                
                if( $weight > $weightLimit ) {
 
                        $message = sprintf( __( 'Sorry, %d kg exceeds the maximum weight of %d kg for %s', 'my' ), $weight, $weightLimit, $My_Shipping_Method->title );
                             
                        $messageType = "error";
 
                        if( ! wc_has_notice( $message, $messageType ) ) {
                         
                            wc_add_notice( $message, $messageType );
                      
                        }
                }
            }       
        } 
    }
 
    add_action( 'woocommerce_review_order_before_cart_contents', 'my_validate_order' , 10 );
    add_action( 'woocommerce_after_checkout_validation', 'my_validate_order' , 10 );
}

Conclusion

Shipping is an integral part of an online storefront, as it determines the success or the failure of your business. Therefore, it becomes important for any E-Commerce store owners to have the right kind of shipping method as per their requirements.

Here, we have tried to provide you with an in-depth guide on creating a custom shipping method for WooCommerce store which will e life of a Woocommerce Developer easier than ever before so that purpose you need to hire WooCommerce Developer.

If you’ve any question or suggestion regarding this subject, then do write to us in our comment section. We will try to respond to each of your queries as per our knowledge. Thank You!

Harikrishna Kundariya

CEO, eSparkBiz

Harikrishna Kundariya, a marketer, developer, IoT, chatbot and blockchain savvy, designer, co-founder, Director of eSparkBiz @Software Development Company where you can Hire Software Developers. His 12+ experience enables him to provide digital solutions to new start-ups based on Web app development.