WRITE A CUSTOM SHIPPING PLUGIN IN MAGENTO 2

Shipping is a key process in e-commerce. There are several built-in Shipping Methods available in Magento 2 for managing Order Delivery. Magento 2 provides an easy way to create our own Custom Shipping Method.

Our intention to write this module is to help you understand how you can start coding on Magento 2 and learn how to write a shipping or any other module. This tutorial can be helpful for anyone who is new to Magento 2 or is already an experienced programmer in Magento 1 moving to Magento 2.

Let’s go step by step to create a custom shipping method. Following are the steps to be taken:

  1. Creating and registering a new Custom Shipping Module
  2. Defining Custom Shipping Method Details
  3. Adding a new section of Custom Shipping Method in Admin Panel
  4. Creating Custom Shipping Model
  5. Running Magento Commands

Step 1: Create And Register A New Custom Shipping Module

To create a custom module, the first step is to create a file, module.xml in folder, <Magento Root Folder>/app/code/<Vendor Name>/<Module Name>/etc/ folder. Let’s take the path

/app/code/Bizspice/Shippingmodule/etc/module.xml

and paste the following code into this file:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
        <module name="Bizspice_Shippingmodule" setup_version="1.0.1"></module>
</config>

Now, create a file registration.php in /app/code/Bizspice/Shippingmodule/ folder with the following code:

<?php \Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
      'Bizspice_Shippingmodule',
       __DIR__
); 

Step 2:  Define Custom Shipping Method Details

Creata a file config.xml in /app/code/Bizspice/Shippingmodule/etc/ folder with the following code:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
       <default>
           <carriers>
                 <shippingmodule>
                       <active>0</active> 
                       <sallowspecific>0</sallowspecific>
                       <price>0</price>
                       <model>Bizspice/Shippingmodule\Model\Carrier\Shippingmodule</model>
                       <name>Shipping Module</name>
                       <title>BIZSPICE Shipping</title>
                       <specificerrmsg>This shipping method is not available. To use this shipping method, please contact us.</specificerrmsg>
                </shippingmodule>
           </carriers>
      </default>
</config> 

Here, in the config.xml file, the parent tag is the default, and the child tag is a carrier that has the details of our custom module. shippingmodule tag is added under the carriers tag. shippingmodule is a code of our custom shipping method. This will be used in the model file (defined under the model tag in config.xml).

Step 3:   Adding A New Section Of Custom Shipping Method In Admin Panel

There will be some configuration options for our custom shipping module in the admin panel. To manage these options, create a file system.xml in /app/code/Bizspice/Shippingmodule/etc/adminhtml/ folder with the following code:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../Magento/Config/etc/system_file.xsd">
       <system>
            <section id="carriers" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
                 <group id="shippingmodule" translate="label" type="text" sortOrder="2" showInDefault="1" showInWebsite="1" showInStore="1">
                      <label>BIZSPICE Shipping</label>
                      <field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0">
                           <label>Enabled</label> 
                           <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                      </field>
                      <field id="title" translate="label" type="text" sortOrder="2" showInDefault="1" showInWebsite="1" showInStore="1">
                            <label>Title</label>
                      </field>
                      <field id="name" translate="label" type="text" sortOrder="3" showInDefault="1" showInWebsite="1" showInStore="1">
                            <label>Method Name</label> 
                      </field>
                      <field id="price" translate="label" type="text" sortOrder="4" showInDefault="1" showInWebsite="1" showInStore="0">
                            <label>Shipping Cost</label>
                            <validate>validate-number validate-zero-or-greater</validate>
                     </field>
                     <field id="specificerrmsg" translate="label" type="textarea" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="1">
                            <label>Displayed Error Message</label>
                     </field>
                     <field id="sallowspecific" translate="label" type="select" sortOrder="90" showInDefault="1" showInWebsite="1" showInStore="0">
                            <label>Ship to Applicable Countries</label>
                            <frontend_class>shipping-applicable-country</frontend_class>
                            <source_model>Magento\Shipping\Model\Config\Source\Allspecificcountries</source_model>
                    </field>
                    <field id="specificcountry" translate="label" type="multiselect" sortOrder="91" showInDefault="1" showInWebsite="1" showInStore="0">
                           <label>Ship to Specific Countries</label>
                           <source_model>Magento\Directory\Model\Config\Source\Country</source_model>
                           <can_be_empty>1</can_be_empty>
                    </field>
                    <field id="showmethod" translate="label" type="select" sortOrder="92" showInDefault="1" showInWebsite="1" showInStore="0">
                           <label>Show Method if Not Applicable</label>
                           <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                    </field>
                    <field id="sort_order" translate="label" type="text" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="0">
                            <label>Sort Order</label>
                    </field>
               </group>
         </section>
    </system> 
</config>

Step 4:  Creating Custom Shipping Model

As you can see under the model tag in config.xml file, the following path has been specified:

Bizspice/Shippingmodule\Model\Carrier\Shippingmodule

So, now, a model file Shippingmodule.php will be created in Bizspice/Shippingmodule\Model\Carrier\ folder with the following code:

<?php
namespace Bizspice\Shippingmodule\Model\Carrier;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\DataObject;
use Magento\Shipping\Model\Carrier\AbstractCarrier;
use Magento\Shipping\Model\Carrier\CarrierInterface;
use Magento\Shipping\Model\Config;
use Magento\Shipping\Model\Rate\ResultFactory;
use Magento\Store\Model\ScopeInterface;
use Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory;
use Magento\Quote\Model\Quote\Address\RateResult\Method;
use Magento\Quote\Model\Quote\Address\RateResult\MethodFactory;
use Magento\Quote\Model\Quote\Address\RateRequest;
use Psr\Log\LoggerInterface;
class Shippingmodule extends AbstractCarrier implements CarrierInterface
{
      protected $_code = 'shippingmodule';
      protected $_isFixed = true;
      protected $_rateResultFactory;
      protected $_rateMethodFactory;
      public function __construct( ScopeConfigInterface $scopeConfig, ErrorFactory $rateErrorFactory,
     LoggerInterface $logger,
     ResultFactory $rateResultFactory,
     MethodFactory $rateMethodFactory,
     array $data = []
     ) {
            $this->_rateResultFactory = $rateResultFactory;
            $this->_rateMethodFactory = $rateMethodFactory;             parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data);
     }
     public function getAllowedMethods() {
         return [$this->getCarrierCode() => __($this->getConfigData('name'))];
     }
     public function collectRates(RateRequest $request) {
         if (!$this->isActive())
         {
             return false;
         }
         $result = $this->_rateResultFactory->create();
         $shippingPrice = $this->getConfigData('price');
         $method = $this->_rateMethodFactory->create();
         $method->setCarrier($this->getCarrierCode());
         $method->setCarrierTitle($this->getConfigData('title'));
         $method->setMethod($this->getCarrierCode());
         $method->setMethodTitle($this->getConfigData('name'));
         $method->setPrice($shippingPrice);
         $method->setCost($shippingPrice);
         $result->append($method);
            return $result;
      }
}

This model class has the code to set the carrier and add a custom shipping method to the Checkout page. In Magento 2, all Shipping Method classes extend Magento\Shipping\Model\Carrier\AbstractCarrier and implement Magento\Shipping\Model\Carrier\CarrierInterface class. Therefore, it is required to define the $_code variable to assign a unique code to our Custom Module which is shippingmodule.

For a custom shipping module, the following 2 methods are required:

• getAllowedMethods: This method returns the custom shipping code to Magento for showing on the Checkout page.• CollectRates: This method handles setting and assigning the values to required options. It has a parameter $request, which is an instance of Magento\Quote\Model\Quote\Address\RateRequest. This class contains details about the current order, including cart items detail, quote details, etc. $request can be used to fetch order details and implement our own logic.

Step 5:  Running Magento Commands:

Custom Shipping Method has been created, and now the last step is to install this module and clear the cache (if enabled in Magento) for using this module. Run the following commands:

#rm -rf pub/static/* var/* generated/*;
#chmod 0777 var/ pub/ generated/;
#chmod 0777 -R var/ generated/ pub/;
#php bin/magento setup:upgrade
#php bin/magento setup:di:compile
#php bin/magento setup:static-content:deploy -f
#php bin/magento indexer:reindex
#php bin/magento cache:clean
#php bin/magento cache:flush

Now, Custom Shipping Method is ready to configure and use. To enable and configure it, go to –

Magento 2 Admin panel > STORES > Configuration > SALES > Shipping Methods. Here, you will see that our Custom Shipping Method is listed there –

Now, expand the section of this Custom Shipping Method and you will see the following:

If everything has been set correctly then Checkout Page will be having this Custom Shipping Module: