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

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

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”.

11
Top

Enjoyed this post?

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

Author

CTO / Magento Certified Developer Plus @inchoo. Father, husband!

Other posts from this author

Discussion 11 Comments

Add Comment
  1. snh

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

  2. 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!

  3. This is my question also

  4. jagat

    please also let me know what will be come “some-path-to-system-xml-field”

  5. Well I am using a pure css approach now, works just fine for me. Thanks anyway!

  6. snh

    You mean you turn it on. But hide in frontend?

    Simpel solution. Can you share the code?

  7. Goat

    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

  8. Goat

    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!

  9. magento_guy

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

  10. Wim

    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. Michael

    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

Add Your Comment

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