How to Magento 2 Create Custom Shipping Method

by Juvia

We all know that it’s necessary to Magento 2 create custom shipping method. Especially, when eCommerce becomes popular, the market needs more advanced features in shipping methods. Thus, we write this article to give you instructions on how to create custom shipping method in Magento 2. Don’t worry too much if your tech knowledge is limited, we provide you with an optimal solution in the last part.

How to create custom shipping method in Magento 2 programmatically

Step 1: Create a new module

To Magento 2 create custom shipping method, we need to create a new module. 

Create registration.php file in the following address – app/code/BSS/CustomShipping/registration.php

<?php
declare(strict_types=1);
use Magento\Framework\Component\ComponentRegistrar;
ComponentRegistrar::register(
    ComponentRegistrar::MODULE,
    'BSS_CustomShipping',
    __DIR__
);

Then, create composer.json in app/code/BSS/CustomShipping/composer.json with following code:

{
    "name": "BSS/module-custom-shipping",
    "description": "Custom shipping module",
    "require": {
        "php": "~7.4.0||~8.1.0",
        "magento/framework": "102.0.*",
        "magento/module-backend": "101.0.*",
        "magento/module-catalog": "103.0.*",
        "magento/module-config": "101.1.*",
        "magento/module-directory": "100.3.*",
        "magento/module-quote": "101.1.*",
        "magento/module-sales": "102.0.*",
        "magento/module-sales-rule": "101.1.*",
        "magento/module-shipping": "100.3.*",
        "magento/module-store": "101.0.*"
    },
    "type": "magento2-module",
    "license": [
        "OSL-3.0",
        "AFL-3.0"
    ],
    "autoload": {
        "files": [
            "registration.php"
        ],
        "psr-4": {
            "BSS\\CustomShipping\\": ""
        }
    }
}

In the next step to complete create a new module, we must create the module.xml file in app/code/BSS/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="BSS_CustomShipping"/>
</config>

<?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="BSS_CustomShipping"/>
</config>

Step 2: Add the carrier configuration

After having the folders, we need to set the configuration for our module. And to add a module configuration use the following code snippets.

Firstly, we need to create system.xml file to declare custom shipping module options (Enabled, Title, Method Name, Shipping Cost, Ship to Applicable Countries, Ship to Specific Countries, Show Method if Not Applicable, Sort Order). 

In app/code/BSS/CustomShipping/etc/adminhtml/system.xml, use the following code to create system.xml file:

<?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">
            <group id="customshipping" translate="label" type="text" sortOrder="0" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>Custom Shipping Module</label>
                <field id="active" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1">
                    <label>Enabled</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                </field>
                <field id="title" translate="label" type="text" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1">
                    <label>Title</label>
                </field>
                <field id="name" translate="label" type="text" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1">
                    <label>Method Name</label>
                </field>
                <field id="shipping_cost" translate="label" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1">
                    <label>Shipping Cost</label>
                    <validate>validate-number validate-zero-or-greater</validate>
                </field>
                <field id="sallowspecific" translate="label" type="select" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1" 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="60" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1">
                    <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="70" showInDefault="1" showInWebsite="1" showInStore="1">
                    <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="sort_order" translate="label" type="text" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1">
                    <label>Sort Order</label>
                </field>
            </group>
        </section>
    </system>
</config>

In the source app/code/BSS/CustomShipping/etc/config.xml, we have to create config.xml file specifies default values for custom shipping module options and the shipping module model, BSS\CustomShipping\Model\Carrier\Customshipping:

<?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>
                <title>Custom Shipping Title</title>
                <name>Custom Shipping Method Name</name>
                <shipping_cost>10</shipping_cost>
                <sallowspecific>0</sallowspecific>
                <sort_order>15</sort_order>
                <model>BSS\CustomShipping\Model\Carrier\Customshipping</model>
            </customshipping>
        </carriers>
    </default>
</config>

Step 3: Create the carrier model

Next step, it’s necessary to create the carrier model. In this example, the BSS\CustomShipping\Model\Carrier\Customshipping class is a skeleton of a carrier model. You can also extend it to fit your needs.

The carrier-class implements the CarrierInterface interface and retrieves all available shipping methods in the getAllowedMethods function. If the carrier method is available on checkout, the collectRates function returns the \Magento\Shipping\Model\Rate\Result object. On the other hand, when the carrier method does not apply to the shopping cart,  it returns false

Use the following command in app/code/BSS/CustomShipping/Model/Carrier/Customshipping.php

<?php
declare(strict_types=1);
namespace BSS\CustomShipping\Model\Carrier;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Quote\Model\Quote\Address\RateRequest;
use Magento\Quote\Model\Quote\Address\RateResult\Method;
use Magento\Quote\Model\Quote\Address\RateResult\MethodFactory;
use Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory;
use Magento\Shipping\Model\Carrier\AbstractCarrier;
use Magento\Shipping\Model\Carrier\CarrierInterface;
use Magento\Shipping\Model\Rate\Result;
use Magento\Shipping\Model\Rate\ResultFactory;
use Psr\Log\LoggerInterface;
class Customshipping extends AbstractCarrier implements CarrierInterface
{
    protected string $_code = 'customshipping';
    protected bool $_isFixed = true;
    private ResultFactory $rateResultFactory;
    private MethodFactory $rateMethodFactory;
    public function __construct(
        ScopeConfigInterface $scopeConfig,
        ErrorFactory $rateErrorFactory,
        LoggerInterface $logger,
        ResultFactory $rateResultFactory,
        MethodFactory $rateMethodFactory,
        array $data = []
    ) {
        parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data);
        $this->rateResultFactory = $rateResultFactory;
        $this->rateMethodFactory = $rateMethodFactory;
    }
    /**
     * Custom Shipping Rates Collector
     *
     * @param RateRequest $request
     * @return \Magento\Shipping\Model\Rate\Result|bool
     */
    public function collectRates(RateRequest $request)
    {
        if (!$this->getConfigFlag('active')) {
            return false;
        }
        /** @var Method $method */
        $method = $this->rateMethodFactory->create();
        $method->setCarrier($this->_code);
        $method->setCarrierTitle($this->getConfigData('title'));
        $method->setMethod($this->_code);
        $method->setMethodTitle($this->getConfigData('name'));
        $shippingCost = (float) $this->getConfigData('shipping_cost');
        $method->setPrice($shippingCost);
        $method->setCost($shippingCost);
        /** @var Result $result */
        $result = $this->rateResultFactory->create();
        $result->append($method);
        return $result;
    }
    public function getAllowedMethods(): array
    {
        return [$this->_code => $this->getConfigData('name')];
    }
}

Step 4: Enable the module

We are almost complete Magento 2 create custom shipping method. To enable the module, run this command:

bin/magento module:enable BSS_CustomShipping

Now, check your change in backend.

Best solution to Magento 2 create custom shipping method: Magento 2 Custom Shipping Method Extension

custom_shipping_methodAs I revealed at the beginning, besides the custom shipping method in Magento 2 solution programmatically, I introduce to you the Magento 2 Custom Shipping Method Extension. With this extension, you can easily create a custom shipping method in Magento 2 stores to manage and control all custom methods wherever your country and region. Besides, not only developing the defaut features that Magento provides, our extensions also can customize advanced features to better support the shipping process. 

With affordable price and comprehensive support, we believe that this extension is the best solution for your Magento store‘s shipping issues.

Wrap-up 

Above are detailed instructions on Magento 2 create custom shipping method in 2 ways. Hopefully, with our instructions, you can easily Magento 2 create custom shipping method.

Besides the Magento 2 Custom Shipping Method Extension solution, BSS Commerce also brings many other solutions for your Magento stores here. Please explore and ask us questions at any time to receive the best support.

Next Reading Suggestions

© 2019 BSS Commerce owned by THANH CONG INTER ., JSC. All Rights Reserved.
Business registration certificate no. 0106064469 issued by Hanoi Department of Planning and Investment on 19 December 2019.
Legal Representative: Mr. Nguyen Quang Trung.