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):
- app/code/local/AMC/
- app/code/local/AMC/Shipping/
- app/code/local/AMC/Shipping/etc/
- app/code/local/AMC/Shipping/Model/
- app/code/local/AMC/Shipping/Model/Carrier/
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.).
app/etc/modules/AMC_Shipping.xml
true local
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:
app/code/local/AMC/Shipping/etc/config.xml
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:
app/local/AMC/Shipping/etc/system.xml
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:
app/code/local/AMC/Shipping/Model/LocalDelivery.php
_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).
Comments
it's not app/etc/models/AMC
it's not app/etc/models/AMC_Shipping.xml
it is app/etc/modules/AMC_Shipping.xml
Thanks Kevin, that's a great
Thanks Kevin, that's a great catch and the article is now fixed. But next time don't try using this site for link spam farming.
This is great! I had tried
This is great! I had tried several tutorials about how to create custom shipping module and this is the only code that shows up on the backend. However at checkout page, after clicking "Continue" button at "Billing Information" stage, it displays blank white page upon loading "Shipping Information" stage.
I use Magento 1.6 and I copied and pasted exactly the codes above. Any idea?
Thanks.
Hi,I just fixed the problem.
Hi,
I just fixed the problem. It was missing a "Carrier" directory after "Model" directory to place the "LocalDelivery.php" file. It is all good now! Thanks for the tutorial!
I have written a very
I have fixed the problem in
Great post. I found what I
Great post. I found what I was looking for. Do you mind if I post this on my website and give you credit? If not, it’s ok.
Is there any way to apply a
Is there any way to apply a specific shipping costs for each category?
Hi, I'm using magneto 1.6.1.0
Hi, I'm using magneto 1.6.1.0 and after following your tutorial it almost worked. But I encountered this:
Fatal error: Call to a member function setStore() on a non-object in C:\wamp\www\magento\app\code\core\Mage\Shipping\Model\Shipping.php on line 247
Does anybody know a solution?
Hi, arjan i dont know about
Hi, arjan i dont know about your exact problem but it seems that you are trying to call a method that is not defined anywhere or it might not getting the proper values . I have not used the code so i cant tell more on this. You just need to check your reference configuration file where you have declared the classes that instantiates the setStore() . I hope it help :-)
Errror
Hi,
Thank you for the tutorial; but, when I have tried this, it shows an error for me ""AMC_shipping" requires module "mage_shipping".............."
Any idea?
Thanks,
Iqbal.
requires mage_shipping
mage_shipping is the default Magento shipping module. If you've somehow disabled or removed it, that could explain your error.
Try Mage_Shipping
Try Mage_Shipping
case-sensitivity
Good call David. Depending on your system, PHP or the filesystem may be case-sensitive. So using Mage_Shipping in the XML manifest instead of mage_shipping might solve this.
requires mage_shipping
I also get the same error. Not sure how I can enable mage_shipping
You can remove the
You can remove the requirement for mage shipping by deleting that chunk from the XML manifest. Don't be surprised if things don't work though.
You should be able to enable Magento's core shipping module in the system configuration.
I am using UPS method for
I am using UPS method for shipping. I want to make a logic that if countryt is US(Local) it shows the normal estimation otherwise it shows message" Shipping cost is not available" for non US countries.
UPS shipping module
Dinesh, you should be able to do that with just the built-in UPS shipping module and region settings. This article is about creating an entirely new shipping module from scratch.
Handling Fee
I was checking different tutorials and it appears to regarding the handling cost to use the Magento Method i.e. $this->getFinalPriceWithHandlingFee($price); found internal /app/code/core/Mage/Shipping/Model/Carrier/Abstract.php.
Thanks anyway
Add new comment