How to Create Custom Shipping Method in Magento 2

Magento 2 already has some built-in shipping methods. But in some cases, we may want to create our own shipping methods in Magento 2. It’s not a difficult process. We can create a 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.

Steps to Create a Custom Shipping Method:

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

Create a new module:

Create a “registration.php” file in the below file path to register our new module,

File path: <Magento_2_Root>/app/code/BlogTreat/CustomShipping/registration.php

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

Next, create a “module.xml” file in the below file path to define the module,

File path: <Magento_2_Root>/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 should have config options in the admin panel. We can create config options for our shipping method through the system.xml file.

File path: <Magento_2_Root>/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:

Now create a “config.xml” file in the below path and set the default configuration for our custom shipping method,

File path: <Magento_2_Root>/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 our shipping method code. <model> is the important one and within this <model> tag, we should define our shipping model class.

Create a shipping model:

After defining the shipping model on the “config.xml”, we need to create shipping model class “Customshipping.php” in the below file path,

File path: <Magento_2_Root>/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;
    }
}

Note:

  • 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, we have to implement all logic for our custom shipping calculation.

Module setup upgrade:

Finally, we have to enable our 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, navigate to STORES > Configuration, expand the SALES section from the left panel and click Shipping Methods. You can see our custom shipping method configuration page as follows,

How to Create Custom Shipping Method in Magento 2

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

After completing the configuration of our 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 *