Magento Custom Shipping Part 1: Build a Custom Shipping Module
I am developing an ecommerce site in Magento, when I ran into a wall with the built-in shipping system. To be fair, Magento's shipping is incredibly robust, with a lot of add-on plugins to provide any missing requirements. However, like many small businesses, my client has some very unique needs and business logic, which means there is no off-the-shelf solution for their particular scenario. In this case, they needed a custom shipping solution. The product is delivered in bulk by semi truck, and different local delivery areas have different pricing structures. Naturally, hooking into Fedex or UPS shipping systems would not fit the bill.
Read on for a tutorial on how to build a custom shipping module.
Before we get started, there are a few key strings you'll need to define. I'll do my best to call out in the code where they should be used
- Namespace - this is usually the name of the developer, and must start with a capital letter. I will be using AMC
- Module Name - this is the name of custom module you are building. I will be using Shipping
- Group Alias - This groups some XML config options making them easier to access in PHP. I will be using amcshipping
- Method Name - LocalDelivery
Setup file structure for your new module
The first step is to create a custom module. Add the following folder structure to your Magento installation (replace AMC with your own unique namespace):
It is important that all folder and file names are case-sensitive, so make sure things stay consistent.
Add module specification file
Next, you need to create the Module Specification File, which tells Magento that your module exists and what it is dependent on. This file should be your namespace plus the module name. So in my case, it is AMC_Shipping.xml (Note that if you were to take the folder name structure and replace the / with _ you get this file.).
This XML file defines the existence of the AMC_Shipping module by that unique name string. Also notice that I added a tag in the <depends> section that makes my module dependent on the built-in Mage_Shippng module.
Add a module configuration file
This XML file will define the various parameters and options for your new module. It should go in:
0.1.0 AMC_Shipping_Model AMC_Shipping 1 delivery delivery 0 AMC_Shipping_Model_Carrier_LocalDelivery AMC Custom Shipping Local Delivery This shipping method is currently unavailable. If you would like to ship using this shipping method, please contact us. F
This file defines a few things including the version, the display name of the module, and also a shipping carrier with the id "customrate" which uses the PHP class Carrier_Customrate.
Add an admin configuration file
Like the config.xml, we also need a file that defines the options available to the system administrator:
text 13 1 1 1 select adminhtml/system_config_source_yesno 1 1 1 1 text 100 1 1 1 text 2 1 1 1 text 2 1 1 1 text 12 1 1 1 select shipping/source_handlingType 10 1 1 0 select 90 shipping-applicable-country adminhtml/system_config_source_shipping_allspecificcountries 1 1 1 multiselect 91 adminhtml/system_config_source_country 1 1 1 textarea 80 1 1 1
Add a class to define the shipping carrier business logic
Now we create a PHP class that will allow us to build our custom logic for however our shipping method needs to be calculated. We add another file:
_code.'/active')) return false; $result = Mage::getModel('shipping/rate_result'); $handling = 0; if(Mage::getStoreConfig('carriers/'.$this->_code.'/handling') >0) $handling = Mage::getStoreConfig('carriers/'.$this->_code.'/handling'); if(Mage::getStoreConfig('carriers/'.$this->_code.'/handling_type') == 'P' && $request->getPackageValue() > 0) $handling = $request->getPackageValue()*$handling; $method = Mage::getModel('shipping/rate_result_method'); $method->setCarrier($this->_code); $method->setCarrierTitle(Mage::getStoreConfig('carriers/'.$this->_code.'/title')); /* Use method name */ $method->setMethod('delivery'); $method->setMethodTitle(Mage::getStoreConfig('carriers/'.$this->_code.'/methodtitle')); $method->setCost($handling); $method->setPrice($handling); $result->append($method); return $result; } }
Again, make sure to replace AMC with your namespace. Notice the function and filename match the XML tag we created in the config.xml file. You can add multiple carriers this way relatively easily by simply adding a XML node and PHP class for each one.
This PHP class does a few things. First, it extends the built-in Mage Shipping classes for Carriers, and it provides two important functions, collectRates() and getAllowedMethods. These override the default behaviors from the built-in classes so that we can return different results. We currently are getting the shipping price from a configuration option. We'll change that in a later tutorial.
If you were to now clear your caches and proceed to the checkout, you would see a new shipping carrier available called "AMC Shipping". Within that carrier, you would have one shipping method, with a $5 price (or 5 of whatever your currency unit is).