How to hide shipping method on Magento frontend but leave it on in admin area

hide-on-front-end

For some of you, this might come as a surprise, but Magento does not support “disabling” the shipping method on frontend but leaving it on in admin area. OK, thats not 100% correct since you can do some sort of a “tweak config” that would enable this effect. The thing is that although Magento supports “global/website/store” configs, shipping methods are turned on/off on a global and website level. On store level you can simply edit the title of a shipping method plus few other things, but usually you cannot enable/disable shipping method on a store level.

Now, imagine a case you only have one website defined in your Magento system, if you go to the admin “Sales > Orders” and click “Create New Order” button then the first next screen you see is the “please select a customer” grid where you choose a customer for which you want to create an order.

However if you have two or more websites defined in your Magento system and you go to the admin “Sales > Orders” and click “Create New Order” button then the first next screen you see is the “please select a website” after which you see the “please select a customer” grid. What this means is that Magento either uses default website to create order for customer or you get to choose one. Either way, it reads the website config and shipping data from website. Meaning there is no way to “tweak” the “show me the XYZ shipping method only in admin” with this kind of setup.

How do we bypass that? Easy, all it takes is two little rewrites of Mage_Shipping_Model_Config and Mage_Sales_Model_Quote_Address. Please note however, that this might not be the best or the most optimal approach. It is merely one possible approach.

app/code/local/Mycompany/Myextension/etc/config.xml

<models>
    <shipping>
        <rewrite>
            <config>Mycompany_Myextension_Model_Shipping_Config</config>
        </rewrite>                
    </shipping>
    <sales>
        <rewrite>
            <quote_address>Mycompany_Myextension_Model_Sales_Quote_Address</quote_address>
        </rewrite>
    </sales>
</models>

app/code/local/Mycompany/Myextension/Model/Adminhtml/System/Config/Source/Shipping/Methods.php

<?php
 
class Mycompany_Myextension_Model_Adminhtml_System_Config_Source_Shipping_Methods 
{
    protected $_options;
 
    public function toOptionArray()
    {
        $carriers = Mage::getSingleton('shipping/config')->getAllCarriers();
 
        $carriersActive = Mage::getSingleton('shipping/config')->getActiveCarriers();
        $carriersActive = array_keys($carriersActive);
 
        if (!$this->_options) {
            foreach ($carriers as $carrier) {
                $carrierCode = $carrier->getId();
                $carrierTitle = Mage::getStoreConfig('carriers/'.$carrierCode.'/title', Mage::app()->getStore()->getId());
                $carrierTitle = trim($carrierTitle);
 
                if (empty($carrierTitle)) {
                    continue;
                }
 
                if (in_array($carrierCode, $carriersActive)) {
                    $carrierTitle = sprintf('%s (currently active)', $carrierTitle);
                } else {
                    $carrierTitle = sprintf('%s (currently inactive)', $carrierTitle);
                }
 
                $this->_options[] = array('value'=>$carrierCode, 'label'=>$carrierTitle);
            }
        }
 
        $options = $this->_options;
 
        array_unshift($options, array('value'=>'', 'label'=> ''));
 
        return $options;
    }
}

This file gets called by system.xml “source_model” definition on the field.

app/code/local/Mycompany/Myextension/etc/system.xml

<fields>
    <frontend_hidden_methods>
        <label>Hide Shipping Methods on Frontend</label>
        <comment><![CDATA[If a shipping method has been enabled under its settings, you can choose to hide it on the frontend by selecting it here from the list. This way, the shipping method would be available from the admin area but not from the frontend.]]></comment>
        <frontend_type>multiselect</frontend_type>
        <source_model>mycompany_myextension/adminhtml_system_config_source_shipping_methods</source_model>
        <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>
    </frontend_hidden_methods>
</fields>

Please note that the above system.xml example is only partial, showing only the part for the actual config field definition.

app/code/local/Mycompany/Myextension/Helper/Data.php

<?php
 
class Mycompany_Myextension_Helper_Data extends Mage_Core_Helper_Abstract
{
    const CONFIG_PATH_HIDE_FRONTEND_SHIPPING_METHODS = 'some-path-to-system-xml-field';
 
    public function getHiddenFrontendShippingMethods()
    {
        $methods = Mage::getStoreConfig(self::CONFIG_PATH_HIDE_FRONTEND_SHIPPING_METHODS);
        $methods = explode(',', $methods);
 
        return $methods;
    }
}

app/code/local/Mycompany/Myextension/Model/Shipping/Config.php

<?php
 
class Mycompany_Myextension_Model_Shipping_Config extends Mage_Shipping_Model_Config
{
    public function getActiveCarriers($store = null)
    {
        $carriers = parent::getActiveCarriers($store);
 
        if (Mage::getDesign()->getArea() === Mage_Core_Model_App_Area::AREA_FRONTEND) {
 
            $carriersCodes = array_keys($carriers);
            $hiddenShippingMethods = Mage::helper('mycompany_myextension')->getHiddenFrontendShippingMethods();
 
            foreach ($carriersCodes as $carriersCode) {
                if (in_array($carriersCode, $hiddenShippingMethods)) {
                    unset($carriers[$carriersCode]);
                }
            }            
        }
 
        return $carriers;
    }
}

app/code/local/Mycompany/Myextension/Model/Sales/Quote/Address.php

<?php
 
class Mycompany_Myextension_Model_Sales_Quote_Address extends Mage_Sales_Model_Quote_Address
{
    public function getShippingRatesCollection()
    {
        parent::getShippingRatesCollection();
 
        $hiddenFrontendShippingMethods = Mage::helper('mycompany_myextension')->getHiddenFrontendShippingMethods();
 
        $removeRates = array();
 
        foreach ($this->_rates as $key => $rate) {
            if (in_array($rate->getCarrier(), $hiddenFrontendShippingMethods)) {
                $removeRates[] = $key;
            }   
        }
 
        foreach ($removeRates as $key) {
            $this->_rates->removeItemByKey($key);
        }
 
        return $this->_rates;
    }
}

And basically thats it, now you have an multi-select field somewhere under your admin where you can click the methods you want to specifically hide on the frontend while still being available on the admin. Also, keep in mind that the shipping method has to be enabled, do not confuse the standard enable/disable with this “hide on frontend”.


29 comments

    1. I’ve done this successfully by overriding the Mage_Shipping_Model_Carrier_Freeshipping module and adding the following in the collectRates function:

      if(!Mage::app()->getStore()->isAdmin()) {
      return false; // Only allow this to be used from the admin system
      }

  1. How to remove Shipping Method Product wise programmatically in magento

    i have UPS,USPS,FedEx. I have assign fedex_FEDEX_2_DAY in one product. when i cart or checkout(shipping method) this product then only show fedex_FEDEX_2_DAY shipping method. other method not show. How can i solve it. please any one help me.

  2. I Found a neat way (yes, it’s a shortcut) of doing this by just adding a code snippet in app/design/frontend/[package]/[theme]/template/checkout/onepage/shipping_method/available.phtml, at least if your intention are to hide ALL other shipping methods.

    1) Copy the file:
    From: app/design/frontend/base/default/template/checkout/onepage/shipping_method/available.phtml
    To: app/design/frontend/[your-package]/[your-theme]/template/checkout/onepage/shipping_method/available.phtml

    2) And add this code:
    $_shippingRateGroups['freeshipping']);
    }
    ?>

    3) Follow the guide on:
    Source: http://www.sanjeevhegde.com/magento-disable-other-shipping-methods-when-free-shipping-is-available/

    If you want to provide both “Free shipping” and for an example “Express Shipping” (via a third party), then you have to adjust the code a bit. It works for me. Hope it helps someone..

  3. hi master, how to do for remove shipping method in back end? from code?
    I try to disable sipping methods and create virtual producto, but in this last, when you create order, the customer is duplicate…

  4. in backend Multiselect option did not show,After make this extension i see my admin panel it did not show

  5. Easy way how to hide shipping method on frontend without any overwrite using just one observer function:

    1. config.xml file code:

    <frontend>
        <events>
            <sales_quote_collect_totals_before>
                <observers>
                    <frontend_shipping_rates_sales_quote_collect_totals_before>
                        <class>yourmodule/observer</class>
                        <method>hideShippingMethods</method>                    
                    </frontend_shipping_rates_sales_quote_collect_totals_before>
                </observers>                
            </sales_quote_collect_totals_before>
        </events>
    </frontend>

    2. Observer.php file code:

    public function hideShippingMethods( Varien_Event_Observer $observer )
    {
        if (Mage::getDesign()->getArea() === Mage_Core_Model_App_Area::AREA_FRONTEND)
        {
            $quote              = $observer->getEvent()->getQuote();
            $store              = Mage::app()->getStore($quote->getStoreId());
            $carriers           = Mage::getStoreConfig('carriers', $store);
    
            $hiddenMethodCode   = 'ups'; 
    
            foreach ($carriers as $carrierCode => $carrierConfig) 
            {
                if( $carrierCode == 'ups' )
                {
                    $store->setConfig("carriers/{$carrierCode}/active", '0');
                }
            }
        }
    }
  6. The script does not seem to work on onepage checkout. The shipping method is visible on frontend even if selected as not to show in the multiselect list. I’ve put together the script inside a shipping method called Excellence and the extension is Ship.

    http://speedy.sh/cxnvs/app.zip

  7. I have used above code,its very helpful to me.
    There is one correction needed to show Front-end Hidden shipping method in back-end order creation process.

    app/code/local/Mycompany/Myextension/Model/Sales/Quote/Address.php

    We have to add Front-end area condition to skip rates in below function:

    <?php
    class Mycompany_Myextension_Model_Sales_Quote_Address extends Mage_Sales_Model_Quote_Address
    {
        public function getShippingRatesCollection()
        {
            parent::getShippingRatesCollection();
            if (Mage::getDesign()->getArea() === Mage_Core_Model_App_Area::AREA_FRONTEND) { // Condition added to restrict hidden shipping methods
    	        $hiddenFrontendShippingMethods = Mage::helper('mycompany_myextension')->getHiddenFrontendShippingMethods();
    	        $removeRates = array();
    	        foreach ($this->_rates as $key => $rate) {
    	            if (in_array($rate->getCarrier(), $hiddenFrontendShippingMethods)) {
    	                $removeRates[] = $key;
    	            }
    	        }
    	        foreach ($removeRates as $key) {
    	            $this->_rates->removeItemByKey($key);
    	        }
            }
            return $this->_rates;
        }
    }
  8. Hi Michael,

    To resolve ‘Fatal error: Call to a member function toOptionArray()’ error, you need to do following changes in system.xml

    Instead of

     <source_model>mycompany_myextension/adminhtml_system_config_source_shipping_methods</source_model>

    You need to use

     <source_model>
    Mycompany_Myextension_Model_Adminhtml_System_Config_Source_Shipping_Methods</source_model>

    I hope it is helpful to you.

  9. I receive this error message:
    Fatal error: Call to a member function toOptionArray() on a non-object in …/app/code/core/Mage/Adminhtml/Block/System/Config/Form.php on line 463

  10. Would be really great if you could post this as a downloadable extension. I’m not a programmer and I can’t make it work like this.

  11. Works great ! thanks for sharing this with the community ! Now I just have to modify it a bit to match my custom needs.

  12. Quick followup, as the comment system stripped out some text that looked like HTML tags…

    3rd to last sentence should read as follows:

    In my case the data is in the “frontend_hidden_methods” field which is in the “option” group, which is in the “shipping” section of the admin interface, so the path is “shipping/option/frontend_hidden_methods’.

    Cheers!

  13. So far so good, except that I’m currently having trouble with the One Page Checkout telling me to set a shipping method if the method is set as hidden in the frontend (I’m setting the shipping method programmatically, which works when the method is visible). But I think I might of messed that up somewhere else myself…

    Anyway, I’m writing to help others with this part of the code:

    const CONFIG_PATH_HIDE_FRONTEND_SHIPPING_METHODS = 'some-path-to-system-xml-field';

    The “some-path…” should be set to an XML path, in my case as follows:

    const CONFIG_PATH_HIDE_FRONTEND_SHIPPING_METHODS = 'shipping/option/frontend_hidden_methods';

    In a nutshell, the path mimics the system.xml file, as it describes where to find the data in the config tree. Here’s a snippet from my custom module’s system.xml file:

    <config>
        <sections>
            <shipping>
                <groups>
                    <option>
                        <fields>
                            <frontend_hidden_methods>
                                ...
                            </frontend_hidden_methods>
                        </fields>
                    </option>
                </groups>
            </shipping>
        </sections>
    </config>

    In my case the data is in the field which is in the group, which is in the section of the admin interface, so the path is “shipping/option/frontend_hidden_methods’.

    I happened to have stuck my field in with the other shipping settings but you can put it anywhere that makes sense for your application.

    Hope this helps someone, and thanks for the article Branko!

    Goat

  14. Thank you for this!
    Can you elaborate on what exactly needs to go into Data.php instead of “some-path-to-system-xml-field”? Thanks!

  15. Any chance we can download the code? Or is it possible to download as an extension?! Very wanted! many thanks

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.