Anthony McLin

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
				
				
					core_setup
				
			
		
	
	
		
			
				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
						
						
							<label>Title</label>
							<frontend_type>text</frontend_type>
							<sort_order>2</sort_order>
							<show_in_default>1</show_in_default>
							<show_in_website>1</show_in_website>
							<show_in_store>1</show_in_store>
						
						
							
							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).

Categories: 

Comments

it's not app/etc/models/AMC_Shipping.xml

it is app/etc/modules/AMC_Shipping.xml

- Kevin (not verified)

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.

- Anthony McLin

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.

- Chanjay (not verified)

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!

- Chanjay (not verified)

I have fixed the problem in my shipping module. Thanks

Magento Developer

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 specific shipping costs for each category?

- Alberto (not verified)

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?

- Arjan (not verified)

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 :-)

- rishu (not verified)

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.

mage_shipping is the default Magento shipping module. If you've somehow disabled or removed it, that could explain your error.

- Anthony McLin

Try Mage_Shipping

- David (not verified)

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.

- Anthony McLin

I also get the same error. Not sure how I can enable mage_shipping

- Marvin (not verified)

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.

- Anthony McLin

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.

- Dinesh (not verified)

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.

- Anthony McLin

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