In this post we’ll display methods to create Magento 2 module with a shipping method. If you might be already aware of Magento 1, all examples will probably be very clear. Creating shipping method is fairly straightforward, so let’s go along with an example.
First of all, you will have to create a Magento module. You ought to create directory structure like in a screen-shot under:
After creating a module, it’s best to enable module with a shell script:
php -f /bin/magento module:enable simplemagento_Shipping
Also, you’ll be able to test is module enabled or not with a command (this script will print a list of all enabled modules):
php -f /bin/magento module:status
Let’s start with a class which handles shipping method. First of all, shipping method must be outlined in file config.xml, like in a screen-shot under. Without it, it could’t work. The main node in xml is “default” and child of node “carriers” ought to have the identical name as property $_code in shipping class “simplemagentoShippingModelCarrierExample“.
<?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>
<example>
<active>1</active>
<sallowspecific>0</sallowspecific>
<model>simplemagentoShippingModelCarrierExample</model>
<name>simplemagento Example Shipping</name>
<price>15.00</price>
<title>simplemagento Example</title>
<type>I</type>
<specificerrmsg>This shipping method is not available. To use this shipping method, please contact us.</specificerrmsg>
</example>
</carriers>
</default>
</config>
In our config.xml you will discover XML node “model” which define php class “simplemagentoShippingModelCarrierExample“. This model class is charged for shipping method. In this class must be carried out all logic for shipping calculation.
Also each shipping method ought to have config choices in admin. You can add shipping method choices by means of system.xml file. Example is under:
<?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="example" translate="label" type="text" sortOrder="0" showInDefault="1" showInWebsite="1" showInStore="1">
<label>simplemagento Example</label>
<field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" presentInWebsite="1" showInStore="0">
<label>Enabled</label>
<source_model>MagentoConfigModelConfigSourceYesno</source_model>
</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="5" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Price</label>
<validate>validate-number validate-zero-or-greater</validate>
</field>
<field id="handling_type" translate="label" type="select" sortOrder="7" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Calculate Handling Fee</label>
<source_model>MagentoShippingModelSourceHandlingType</source_model>
</field>
<field id="handling_fee" translate="label" type="text" sortOrder="8" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Handling Fee</label>
<validate>validate-number validate-zero-or-greater</validate>
</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">
<label>Title</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>MagentoShippingModelConfigSourceAllspecificcountries</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>MagentoDirectoryModelConfigSourceCountry</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>MagentoConfigModelConfigSourceYesno</source_model>
</field>
<field id="specificerrmsg" translate="label" type="textarea" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Displayed Error Message</label>
</field>
</group>
</section>
</system>
</config>
Shipping class ought to appear like the example under:
<?php
namespace simplemagentoShippingModelCarrier;
use MagentoQuoteModelQuoteAddressRateRequest;
use MagentoShippingModelRateResult;
class Example extends MagentoShippingModelCarrierAbstractCarrier implements
MagentoShippingModelCarrierCarrierInterface
{
/**
* @var string
*/
protected $_code = 'example';
/**
* @param MagentoFrameworkAppConfigScopeConfigInterface $scopeConfig
* @param MagentoQuoteModelQuoteAddressRateResultErrorFactory $rateErrorFactory
* @param PsrLogLoggerInterface $logger
* @param MagentoShippingModelRateResultFactory $rateResultFactory
* @param MagentoQuoteModelQuoteAddressRateResultMethodFactory $rateMethodFactory
* @param array $data
*/
public function __construct(
MagentoFrameworkAppConfigScopeConfigInterface $scopeConfig,
MagentoQuoteModelQuoteAddressRateResultErrorFactory $rateErrorFactory,
PsrLogLoggerInterface $logger,
MagentoShippingModelRateResultFactory $rateResultFactory,
MagentoQuoteModelQuoteAddressRateResultMethodFactory $rateMethodFactory,
array $data = []
)
/**
* @return array
*/
public function getAllowedMethods()
{
return (*2*);
}
/**
* @param RateRequest $request
* @return bool|Result
*/
public function collectRates(RateRequest $request)
{
if (!$this->getConfigFlag('active')) {
return false;
}
/** @var MagentoShippingModelRateResult $result */
$result = $this->_rateResultFactory->create();
/** @var MagentoQuoteModelQuoteAddressRateResultMethod $method */
$method = $this->_rateMethodFactory->create();
$method->setCarrier('example');
$method->setCarrierTitle($this->getConfigData('title'));
$method->setMethod('example');
$method->setMethodTitle($this->getConfigData('name'));
/*you can fetch shipping price from different sources over some APIs, we used price from config.xml - xml node price*/
$amount = $this->getConfigData('price');
$method->setPrice($amount);
$method->setCost($amount);
$result->append($method);
return $result;
}
}
In order to correctly write php class for shipping method, it’s best to respect some Magento 2 guidelines. Every Magento 2 shipping class ought to extend “MagentoShippingModelCarrierAbstractCarrier” and implement “MagentoShippingModelCarrierCarrierInterface“.
In shipping model you need to create at least two php methods: “getAllowedMethods” and “collectRates“. This methods are required by abstract class and interface. Also, you should define property $_code with value. In our case, that is “example“. It’s related to config.xml and node structure.
Php method “collectRates” accepts parameter “$request” which is instance of class “MagentoQuoteModelQuoteAddressRateRequest“. This class accommodates all details about gadgets in cart/quote, weight, shipping tackle and so forth. In this method you’ll be able to implement all logic for shipping calculation. From this method you’ll be able to call different providers for shipping price calculation however it relies upon about your integration.
You can see extra information in screen-shot under.
If you carried out everything as I wrote, you will be capable to see shipping method on checkout.
This could be very easy example I hope that will probably be helpful for you 🙂
However, when you’re having questions or need assistance relating to Magento development, we might be glad that can assist you out by creating a detailed custom report based on our technical audit. Feel free to get in contact!