Custom shipping method in Magento

Featured Image

In this article I will demonstrate how to write custom shipping method in Magento commerce.
First we need to write our shipping method, it’s a class in folder app/code/core/Mage/Shipping/Model/Carrier/.
I called it Inchoocustom.php and it’s based on Flat rate shipping method but you can developed your own class.

< ?php

class Mage_Shipping_Model_Carrier_Inchoocustom
    extends Mage_Shipping_Model_Carrier_Abstract
    implements Mage_Shipping_Model_Carrier_Interface
{

    protected $_code = 'inchoocustom';

    public function collectRates(Mage_Shipping_Model_Rate_Request $request)
    {
        if (!$this->getConfigFlag('active')) {
            return false;
        }

        $freeBoxes = 0;
        if ($request->getAllItems()) {
            foreach ($request->getAllItems() as $item) {
                if ($item->getFreeShipping() && !$item->getProduct()->isVirtual()) {
                    $freeBoxes+=$item->getQty();
                }
            }
        }
        $this->setFreeBoxes($freeBoxes);

        $result = Mage::getModel('shipping/rate_result');
        if ($this->getConfigData('type') == 'O') { // per order
            $shippingPrice = $this->getConfigData('price');
        } elseif ($this->getConfigData('type') == 'I') { // per item
            $shippingPrice = ($request->getPackageQty() * $this->getConfigData('price')) - ($this->getFreeBoxes() * $this->getConfigData('price'));
        } else {
            $shippingPrice = false;
        }

        $shippingPrice = $this->getFinalPriceWithHandlingFee($shippingPrice);

        if ($shippingPrice !== false) {
            $method = Mage::getModel('shipping/rate_result_method');

            $method->setCarrier('inchoocustom');
            $method->setCarrierTitle($this->getConfigData('title'));

            $method->setMethod('inchoocustom');
            $method->setMethodTitle($this->getConfigData('name'));

            if ($request->getFreeShipping() === true || $request->getPackageQty() == $this->getFreeBoxes()) {
                $shippingPrice = '0.00';
            }

            $method->setPrice($shippingPrice);
            $method->setCost($shippingPrice);

            $result->append($method);
        }

        return $result;
    }

    public function getAllowedMethods()
    {
        return array('inchoocustom'=>$this->getConfigData('name'));
    }

}

Pay attention on following lines:

$method->setCarrier('inchoocustom');
$method->setCarrierTitle($this->getConfigData('title'));

$method->setMethod('inchoocustom');
$method->setMethodTitle($this->getConfigData('name'));

They determine how we will set up our method. Keyword is ‘inchoocustom’.
In folder app/code/core/Mage/Shipping/etc/ we need to edit
system.xml and config.xml in order to enable our new shipping method.

system.xml:

                <inchoocustom translate="label">
                    <label>Inchoo Custom Shipping Method</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>
                    <fields>
                        <active translate="label">
                            <label>Enabled</label>
                            <frontend_type>select</frontend_type>
                            <source_model>adminhtml/system_config_source_yesno</source_model>
                            <sort_order>1</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </active>
                        <name translate="label">
                            <label>Method name</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>3</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                        </name>
                        <price translate="label">
                            <label>Price</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>5</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </price>
                        <handling_type translate="label">
                            <label>Calculate Handling Fee</label>
                            <frontend_type>select</frontend_type>
                            <source_model>shipping/source_handlingType</source_model>
                            <sort_order>7</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </handling_type>
                        <handling_fee translate="label">
                            <label>Handling Fee</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>8</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </handling_fee>
                        <sort_order translate="label">
                            <label>Sort order</label>
                            <frontend_type>text</frontend_type>
                            </sort_order><sort_order>100</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>

                        <title translate="label">
                            <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>
                        </title>
                        <type translate="label">
                            <label>Type</label>
                            <frontend_type>select</frontend_type>
                            <source_model>adminhtml/system_config_source_shipping_flatrate</source_model>
                            <sort_order>4</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </type>
                        <sallowspecific translate="label">
                            <label>Ship to applicable countries</label>
                            <frontend_type>select</frontend_type>
                            <sort_order>90</sort_order>
                            <frontend_class>shipping-applicable-country</frontend_class>
                            <source_model>adminhtml/system_config_source_shipping_allspecificcountries</source_model>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </sallowspecific>
                        <specificcountry translate="label">
                            <label>Ship to Specific countries</label>
                            <frontend_type>multiselect</frontend_type>
                            <sort_order>91</sort_order>
                            <source_model>adminhtml/system_config_source_country</source_model>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </specificcountry>
                        <showmethod translate="label">
                            <label>Show method if not applicable</label>
                            <frontend_type>select</frontend_type>
                            <sort_order>92</sort_order>
                            <source_model>adminhtml/system_config_source_yesno</source_model>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </showmethod>
                        <specificerrmsg translate="label">
                            <label>Displayed Error Message</label>
                            <frontend_type>textarea</frontend_type>
                            <sort_order>80</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                        </specificerrmsg>
                    </fields>
                </inchoocustom>

config.xml:

	<inchoocustom>
                <active>0</active>
                <sallowspecific>0</sallowspecific>
                <model>shipping/carrier_inchoocustom</model>
                <name>Inchoo Custom Shipping Method</name>
                <price>5.00</price>
                <title>Inchoo Custom Shipping Method</title>
                <type>I</type>
                <specificerrmsg>This shipping method is currently unavailable. If you would like to ship using this shipping method, please contact us.</specificerrmsg>
                <handling_type>F</handling_type>
        </inchoocustom>

Now we need to enable our new shipping method in admin panel (System->Configuration->Shipping Methods)
And we have our custom shipping method.
Enjoy coding.

47
Top

Enjoyed this post?

Subscribe to our RSS Feed, Follow us on Twitter and spread it to your friends!

Author

Vedran Subotic

Ex. Inchooer

Vedran worked in Inchoo from 2009 to 2012 as a Senior backend developer and as a team leader.

Other posts from this author

Discussion 47 Comments

Add Comment
  1. Tobeyt23

    Can this be made into a local module so as to not get overridden during upgrades?

  2. Tobeyt23

    I keep getting an error on this

  3. @Tobeyt23

    Not much info provided on your side!

    What is the error you are getting? Check the SmallCaps cases in config.xmlf files. Our color syntax app has the tendency to lowercase attribute names in XML files so you might be getting some config errors?

  4. @Tobeyt23

    “Can this be made into a local module so as to not get overridden during upgrades?” => Yes it can.

  5. Tobeyt23

    @Branko Ajzele

    I found the error:

    Sort order
    text
    100
    1
    1
    0

    should be:

    Sort order
    text
    100
    1
    1
    0

  6. @Tobeyt23 Vedran is the author of this post :) I guess this one goes to him.

  7. Tobeyt23

    @ Branko Ajzele

    Woops didn’t see that the code got messed up. In the system.xml on line 54 the sortorder is closed before it should be once I fixed that it worked.

  8. Vedran Subotic

    Well done Tobeyt23,
    ceep tracing Magento code!!

  9. It does not work in the newest version of Magento … it is visible in System->Configuration->Shipping Methods, but if it is active shopping chart drops errors, and the checkout does not let to pass to shipping methods. or did I missed something in
    Pay attention on following lines:

    1. $method->setCarrier(‘inchoocustom’);
    2.$method->setCarrierTitle($this->getConfigData(‘title’));
    3.
    4.$method->setMethod(‘inchoocustom’);
    5.$method->setMethodTitle($this->getConfigData(‘name’));

    gimme more info to what should I pay attention to

    thanx best wishes

    Jozef

  10. Vedran Subotic

    @Jozef

    I’m sorry, I should highlight that the code above is tested in Magento version 1.3.2.1.
    But if you followed the instructions (not just copy-paste) and tried to make your own shipping method with new magento version I belive that you would achieve your goal.

  11. Hi, you have shown how to add shipping module in Core/Mage. Is there any way I can add shipping module in Local/

  12. Sirvash Sharma

    try this one, hopefully working.

    Inchoo Custom Shipping Method
    text
    5
    1
    1
    1

    Enabled
    select
    adminhtml/system_config_source_yesno
    1
    1
    1
    0

    Method name
    text
    3
    1
    1
    1

    Price
    text
    5
    1
    1
    0

    Calculate Handling Fee
    select
    shipping/source_handlingType
    7
    1
    1
    0

    Handling Fee
    text
    8
    1
    1
    0

    Sort order
    text
    100
    1
    1
    0

    Title
    text
    2
    1
    1
    1

    Type
    select
    adminhtml/system_config_source_shipping_flatrate
    4
    1
    1
    0

    Ship to applicable countries
    select
    90
    shipping-applicable-country
    adminhtml/system_config_source_shipping_allspecificcountries
    1
    1
    0

    Ship to Specific countries
    multiselect
    91
    adminhtml/system_config_source_country
    1
    1
    0

    Show method if not applicable
    select
    92
    adminhtml/system_config_source_yesno
    1
    1
    0

    Displayed Error Message
    textarea
    80
    1
    1
    1

  13. HaNguyen

    I found the error:

    Sort order
    text
    100
    1
    1
    0
    should be:

    Sort order
    text
    100
    1
    1
    0

  14. HaNguyen

    i found error:

    052. Sort order
    053. text
    054. 100
    055. 1
    056. 1
    057. 0
    should be:

    052. Sort order
    053. text
    054. 100
    055. 1
    056. 1
    057. 0
    058.

  15. HaNguyen

    i found error at line 054

  16. Can you offer opensource EMS shipment model?

  17. Great! Our store is based in one currency and displays in another ($). That works fine. The problem is with shipping. You see we want to have a flat fixed shipping rate in $ – but it gets converted from our base currency. Any ideas?

    Thanks

  18. Gurvinder singh

    Hey please correct the section
    Sort order
    text
    100
    1
    1
    0

    Instead of blindly copy paste this in system.xml:

    Sort order
    text
    100
    1
    1
    0

  19. Error was in line: 54
    Xml tag wasn’t properly closed.

    Please check the link provided:

    fixed solution

    Point was that You spend some time to trace the error so you can get that feeling how is like to be Magento developer.

  20. Great tutorial! You should be namespacing this code into /local, especially if it is a tutorial, and you are telling others best practices in Magento programming.

  21. How can I add a minimum shipping amount to the flat rate %. For example:

    I want to charge $6.50 or 8% depending on which is greater.

    Thanks!

  22. Jaime

    Hello… I have made it local, but I saw thay the model class is never called. the system insists in calle Mage_Shipping model class.

    My module is called Newshipping, and the carrier is regionfreeshipping. Can you show me how to configure system.xml and config.xml files?

    Thanks
    Jaime

  23. MagentoPycho

    HI,
    I tried to make the following fields dynamic so that it’s data come from some table.

    for example

    foreach($multiple_methods as $method){
    ...
    $method->setMethod($method['code']);
    $method->setMethodTitle($method[''name]);
    ..
    
    }
    

    But in the frontend i get the methods but with ‘US’ title and all divs ids were same.

    Can anybody has some idea

  24. MMan

    Pay attention on shipping/carrier_inchoocustom without correct model you we unable to see custom shipping in the frontend list

  25. John

    While this module works quite fine.. when I go to Sales>Orders and click on Invoice, it throws up an error.

    Do you have any fix for that?

    Using Magento 1.1.4

  26. John

    Hello,

    Due to the errors being thrown up, I disabled your module (meaning: retraced the methods you mentioned to install this module)

    But now when I click on Sales>orders>view and click on Invoice or Ship, I get the error message: Invalid model for shipping method: inchoocustom

    How do i fix this?

  27. John

    Sorry for the spam… but it’s kind of frustrating.. When I do use the module, then when creating promotions and New Rule action is set to Shipping Method, it throws up a bunch of errors again.

    getConfigFlag('active')) { return false; } $freeBoxes = 0; if ($request->getAllItems()) { foreach ($request->getAllItems() as $item) { if ($item->getFreeShipping() && !$item->getProduct()->isVirtual()) { $freeBoxes+=$item->getQty(); } } } $this->setFreeBoxes($freeBoxes); $result = Mage::getModel('shipping/rate_result'); if ($this->getConfigData('type') == 'O') { // per order $shippingPrice = $this->getConfigData('price'); } elseif ($this->getConfigData('type') == 'I') { // per item $shippingPrice = ($request->getPackageQty() * $this->getConfigData('price')) - ($this->getFreeBoxes() * $this->getConfigData('price')); } else { $shippingPrice = false; } $shippingPrice = $this->getFinalPriceWithHandlingFee($shippingPrice); if ($shippingPrice !== false) { $method = Mage::getModel('shipping/rate_result_method'); $method->setCarrier('inchoocustom'); $method->setCarrierTitle($this->getConfigData('title')); $method->setMethod('inchoocustom'); $method->setMethodTitle($this->getConfigData('name')); if ($request->getFreeShipping() === true || $request->getPackageQty() == $this->getFreeBoxes()) { $shippingPrice = '0.00'; } $method->setPrice($shippingPrice); $method->setCost($shippingPrice); $result->append($method); } return $result; } public function getAllowedMethods() { return array('inchoocustom'=>$this->getConfigData('name')); } }
    Fatal error: Call to a member function setId() on a non-object in /public_html/app/code/core/Mage/Shipping/Model/Config.php on line 118
    
  28. John

    Hi,

    It’s me again (for the last time). I figured out the errors.. even after disabling this module, when clicking on invoices, the error throws up. This is because of the path in core_config_data

    Each of the records have to be deleted and it works fine.

    Perhaps you might want to mention this and others might find it useful.

  29. @John

    This example is more than 1 year old.
    Install new Magento, follow step by step and code it from scratch.

    Thanks for reply

  30. Umut

    I can get the above to work on Magento 1.5 but when I try to create a shopping cart price rule using something like if shipping method is Custom Method, it just throws me back to the dashboard
    I assume we need to add the custom method to the database or mage somewhere else in the program?
    Any thoughts?

  31. Its work fine for me but i want to know is it proper way to use, what if a new version of magento comes and somebody runs upgrade over system everything will be vanished then, is it possible to override this system.xml and config.xml, i can override shipping model but confused with the xml files.

  32. i had use this code it is correct and complete thanks for that.but now i want to need shipping charge based on total which is manage from admin.shipping charge will be 2% of total and if total>400 then shipping charge will be free so please help me for that i m new in magento.
    thanks in advance.

  33. ramesh

    informations in this site are very very useful for everyone in the world.

    My suggestion is to please change coding background color in your site. because now it very dark.
    site take some high loading time. reduce it if possible.

    informations in this site are very valuable.

  34. zaid

    how may i add region in shipping method?

    http://stackoverflow.com/questions/6355409/magento-get-region-list-for-country-in-admin-shipping-module

    i flow this ling but it is not working when i select country and then region what can i do?

  35. Hello

    i have to develop a new shipping method for MaltaPost in magento. Please let me know whether it is possible

  36. Ivo Barbosa

    I need some example to make shipping module in Magento 1.5, anybody can help me?
    Thanks.

  37. James

    can I set up multiple prices for rates
    ex
    10.00
    5.00
    15.00
    ?
    in the config.xml

  38. Daniel

    Thanx, very nice and almost working example(using magento 1.5.1).
    You have forgotten to end the

    <sort-order  translate="label">

    tag:

    <sort_order translate="label">
    			    <label>Sort Order</label>
    			    <frontend_type>text</frontend_type>
    			    <sort_order>100</sort_order>
    			    <show_in_default>1</show_in_default>
    			    <show_in_website>1</show_in_website>
    			    <show_in_store>0</show_in_store>
                            </sort_order> <- This is missing in the above code, but easy to spot and fix.
    

    Besides that it works great and shows up in the store as well.

    DO NOTE!! You can not use special chars like åäö in the xml. Use the html equivalent instead. If you do use it the admin page will not display any of the shipping modules instead.

  39. Daniel

    EDIT:
    The code example is a complete working version, I just noticed that the original code did include the end tag but that it is placed wrong.

  40. Max

    Please John, you said “This is because of the path in core_config_data. Each of the records have to be deleted and it works fine” I would be very grateful you tell what you realy mean because i am having the problem. In this core_config_data table, there are many paths, which one do i delete? Please please, i need your help. Keep all good work alive.

  41. Hey man, is there a way I could use this tutorial to create a shipping mode that applies only to certain categories of products?

  42. Chris Stanton

    This works fine in Magento CE 1.5 except that after a customer has used the method I created there is no reorder button on the customers dashboard under that specific order, all other shipping methods allow for reorder.

    Only thing I did different from the tutorial is that I based my shipping method on the Free Shipping default method included in Magento.

    Anyone else have this issue or know why and how to fix it?

    Cheers,
    Chris

  43. Peter

    Hi I followed your example but i get this error.

    getConfigFlag(‘active’)) { return false; } $freeBoxes = 0; if ($request->getAllItems()) { foreach ($request->getAllItems() as $item) { if ($item->getFreeShipping() && !$item->getProduct()->isVirtual()) { $freeBoxes+=$item->getQty(); } } } $this->setFreeBoxes($freeBoxes); $result = Mage::getModel(‘shipping/rate_result’); if ($this->getConfigData(‘type’) == ‘O’) { // per order $shippingPrice = $this->getConfigData(‘price’); } elseif ($this->getConfigData(‘type’) == ‘I’) { // per item $shippingPrice = ($request->getPackageQty() * $this->getConfigData(‘price’)) – ($this->getFreeBoxes() * $this->getConfigData(‘price’)); } else { $shippingPrice = false; } $shippingPrice = $this->getFinalPriceWithHandlingFee($shippingPrice); if ($shippingPrice !== false) { $method = Mage::getModel(‘shipping/rate_result_method’); $method->setCarrier(‘G4S’); $method->setCarrierTitle($this->getConfigData(‘title’)); $method->setMethod(‘G4S’); $method->setMethodTitle($this->getConfigData(‘name’)); if ($request->getFreeShipping() === true || $request->getPackageQty() == $this->getFreeBoxes()) { $shippingPrice = ’0.00′; } $method->setPrice($shippingPrice); $method->setCost($shippingPrice); $result->append($method); } return $result; } public function getAllowedMethods() { return array(‘G4S’=>$this->getConfigData(‘name’)); } }
    Fatal error: Call to a member function setStore() on a non-object in /home/covertas/public_html/supa/magento/app/code/core/Mage/Shipping/Model/Shipping.php on line 247

    any help?

  44. John

    I am trying to create this, in magento 1.6.1 using LOCAL folder, and it never appears …
    does anybody knows why? maybe magento is not checking my system.xml file?

  45. Alberto

    Is there any way to apply a specific shipping costs for each category?

  46. This is great! But I’m also wondering how to add my custom parcel tracking to this.

    Can you demonstrate a simple case?

    When the shipment is booked, the tracking URL should end up in the email to the customer.

  47. Rinku

    when we apply the above code then the shipping method and shipping price are not see in admin->config. why

Add Your Comment

Please wrap all source codes with [code][/code] tags.
Top