How to Create Custom Shipping Method in Magento 2

Magento 2 already has some built-in shipping methods. But in some cases, you may want to create your own shipping methods in Magento 2. It’s not a difficult process. You can create a new custom shipping method in Magento 2 very easily. Here is the blog which helps you to create your own custom shipping method in a short time.

Here the steps that involved to create a new custom shipping method in Magento 2,

  • Create a new module
  • Create a configuration file
  • Define shipping model
  • Create a shipping model
  • Module setup upgrade

Create a new module:

Create a PHP file named registration.php like a path given below to register your new module,

Sample File path: app/code/BlogTreat/CustomShipping/registration.php

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

Next, create a XML file named module.xml like a path given below to define the new module,

Sample File path: app/code/BlogTreat/CustomShipping/etc/module.xml

<?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="BlogTreat_CustomShipping" setup_version="1.0.0">
    </module>
</config>

Create a configuration file:

In Magento 2, every shipping method will have config options in the admin panel. You can create config options for your shipping method through the XML file named system.xml file.

Sample File path: app/code/BlogTreat/CustomShipping/etc/adminhtml/system.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <section id="carriers" translate="label" type="text" sortOrder="320" showInDefault="1" showInWebsite="1" showInStore="1">
            <group id="customshipping" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>Custom Shipping Method</label>
                <field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0" canRestore="1">
                    <label>Enabled</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                </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="name" translate="label" type="text" sortOrder="3" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1">
                    <label>Method Name</label>
                </field>
                <field id="sort_order" translate="label" type="text" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Sort Order</label>
                </field>
                <field id="title" translate="label" type="text" sortOrder="2" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1">
                    <label>Title</label>
                </field>
                <field id="sallowspecific" translate="label" type="select" sortOrder="90" showInDefault="1" showInWebsite="1" showInStore="0" canRestore="1">
                    <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>
                    <frontend_class>shipping-skip-hide</frontend_class>
                </field>
                <field id="specificerrmsg" translate="label" type="textarea" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1">
                    <label>Displayed Error Message</label>
                </field>
            </group>
        </section>
    </system>
</config>

Define shipping model:

Then create a XML file named config.xml like a file path given below, which is used to set the default configuration for your custom shipping method,

Sample File path: app/code/BlogTreat/CustomShipping/etc/config.xml

<?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>
            <customshipping>
                <active>0</active>
                <sallowspecific>0</sallowspecific>
                <price>0</price>
                <model>BlogTreat\CustomShipping\Model\Carrier\Customshipping</model>
                <name>Custom Shipping</name>
                <title>Custom Shipping</title>
                <specificerrmsg>This shipping method is not available. To use this shipping method, please contact us.</specificerrmsg>
            </customshipping>
        </carriers>
    </default>
</config>

Here,

  • <default> is a parent node and its child node is <carriers>
  • <customshipping> is a shipping method code.
  • <model> is the important one and within this <model> tag, you should define your shipping model class.

Create a shipping model:

After defining the shipping model on the config.xml, you need to create shipping model class by creating a PHP file named Customshipping.php like a file path given below,

Sample File path: app/code/BlogTreat/CustomShipping/Model/Carrier/Customshipping.php

<?php
namespace BlogTreat\CustomShipping\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 Customshipping extends AbstractCarrier implements CarrierInterface
{

    /**
     * @var string
     */
    protected $_code = 'customshipping';
 
    /**
     * @var bool
     */
    protected $_isFixed = true;
 
    /**
     * @var ResultFactory
     */
    protected $_rateResultFactory;
 
    /**
     * @var MethodFactory
     */
    protected $_rateMethodFactory;
 
    /**
     * @param ScopeConfigInterface $scopeConfig
     * @param ErrorFactory $rateErrorFactory
     * @param LoggerInterface $logger
     * @param ResultFactory $rateResultFactory
     * @param MethodFactory $rateMethodFactory
     * @param array $data
     */
    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);
    }
 
    /**
     * @return array
     * @api
     */
    public function getAllowedMethods()
    {
        return [$this->getCarrierCode() => __($this->getConfigData('name'))];
    }
 
    /**
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @param RateRequest $request
     * @return DataObject|bool|null
     * @api
     */
    public function collectRates(RateRequest $request)
    {
        /**
         * Make sure that shipping method is enabled
         */
        if (!$this->isActive()) {
            return false;
        }
 
        /** @var \Magento\Shipping\Model\Rate\Result $result */
        $result = $this->_rateResultFactory->create();
        $shippingPrice = $this->getConfigData('price');
        $method = $this->_rateMethodFactory->create();
 
        /**
         * Set carrier's method data
         */
        $method->setCarrier($this->getCarrierCode());
        $method->setCarrierTitle($this->getConfigData('title'));
 
        /**
         * Displayed as shipping method under Carrier
         */
        $method->setMethod($this->getCarrierCode());
        $method->setMethodTitle($this->getConfigData('name'));
        $method->setPrice($shippingPrice);
        $method->setCost($shippingPrice);
        $result->append($method);
        return $result;
    }
}

Some important things from the above code,

  • In Magento 2, Every shipping class should extend \Magento\Shipping\Model\Carrier\AbstractCarrier and implements the \Magento\Shipping\Model\Carrier\CarrierInterface class.
  • The value of $_code should be the same name as the group id in the system.xml.
  • The two functions getAllowedMethods and collectRates are required by the abstract class and interface.
  • In the function collectRates, you have to implement all logic for your custom shipping calculation.

Module setup upgrade:

Finally, you have to enable your extension and install it. For that, go to [magento_root]/bin directory and run the below command in CLI,

php magento module:enable BlogTreat_CustomShipping

Then, run the below command in CLI to upgrade the setup,

php magento setup:upgrade

Then, clear the cache using the below CLI command,

php magento c:c

Now, Log in to your Magento 2 admin panel and navigate to STORES > Configuration, expand the SALES section from the left panel and click Shipping Methods. You can see your custom shipping method configuration page as follows,

How to Create Custom Shipping Method in Magento 2

Here, you can enable your custom shipping method and set the configuration values according to your need.

After completing the configuration of your shipping method, the shipping calculation will be shown on the checkout page as follow,

How to Create Custom Shipping Method in Magento 2

Finally, the shipping method will be applied on the checkout page and the result will be shown as follows,

How to Create Custom Shipping Method in Magento 2

Hope this helps.

Leave a Reply

Your email address will not be published. Required fields are marked *