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