17
votes

I'm writing a quick-and-dirty module to restrict shipping methods based on products in the cart. For example, if the customer adds food, I only want overnight shipping methods to be selected. Some of the commercial extensions are just overkill and have way more functionality that I need.

Each product will have a dropdown attribute called "Shipping Class". The admin will be able to create these Shipping Classes in the backend. They will give it a name and choose which methods are allowed.

When it comes time to get shipping quotes, we'll only show allowed methods based on the Shipping Class.

My main question is: how can I retrieve a list of all the shipping methods for the admin to select from when creating these shipping classes?

And as a secondary question, does it make sense to do the filtering of allowed methods inside of Mage_Sales_Model_Quote_Address::requestShippingRates? (I will be overriding this method of course)


EDIT:

Thanks to @BrianVPS, I was able to come up with the code below. It displays all individual methods from the carriers using optgroups. Works great with multiselect! I don't think it checks if the methods are actually enabled though.

public function getAllShippingMethods()
{
    $methods = Mage::getSingleton('shipping/config')->getActiveCarriers();

    $options = array();

    foreach($methods as $_ccode => $_carrier)
    {
        $_methodOptions = array();
        if($_methods = $_carrier->getAllowedMethods())
        {
            foreach($_methods as $_mcode => $_method)
            {
                $_code = $_ccode . '_' . $_mcode;
                $_methodOptions[] = array('value' => $_code, 'label' => $_method);
            }

            if(!$_title = Mage::getStoreConfig("carriers/$_ccode/title"))
                $_title = $_ccode;

            $options[] = array('value' => $_methodOptions, 'label' => $_title);
        }
    }

    return $options;
}
3
Clarify shipping class vs shipping methods. - aziz punjani
A shipping class is just a collection of allowed shipping methods which can be assigned to a product. For example, I could create a class named "Food" which is associated with all overnight shipping methods. All food products will be assigned the "Food" shipping class. When it comes time to get the shipping quotes, Magento will check to see if any products in the cart have a shipping class. If one of our products is a cake, Magento should hide all shipping methods that aren't overnight. - Colin O'Dell

3 Answers

24
votes

Here is a block of code I have in a source_model for a shipping extension I wrote. Hopefully this is what you're looking for.

...as for your second question, not sure....

public function toOptionArray($isMultiSelect = false)
{
    $methods = Mage::getSingleton('shipping/config')->getActiveCarriers();

    $options = array();

    foreach($methods as $_code => $_method)
    {
        if(!$_title = Mage::getStoreConfig("carriers/$_code/title"))
            $_title = $_code;

        $options[] = array('value' => $_code, 'label' => $_title . " ($_code)");
    }

    if($isMultiSelect)
    {
        array_unshift($options, array('value'=>'', 'label'=> Mage::helper('adminhtml')->__('--Please Select--')));
    }

    return $options;
}
9
votes

Taking @BrianVPS's answer, I'm using the code segment below (with structure shown) to help in my situation, where I wanted a simple human label from the shipping code.

$methods = Mage::getSingleton('shipping/config')->getActiveCarriers();
$shipping = array();
foreach($methods as $_ccode => $_carrier) {
    if($_methods = $_carrier->getAllowedMethods())  {
        if(!$_title = Mage::getStoreConfig("carriers/$_ccode/title"))
            $_title = $_ccode;
        foreach($_methods as $_mcode => $_method)   {
            $_code = $_ccode . '_' . $_mcode;
            $shipping[$_code]=array('title' => $_method,'carrier' => $_title);
        }
    }
}
echo "\n";print_r($shipping);
/*
[flatrate_flatrate] => Array
        [title] => Will-call
        [carrier] => Pickup At Ca Cycleworks
[freeshipping_freeshipping] => Array
        [title] => Economy
        [carrier] => Free Ground Shipping
[ups_11] => Array
        [title] => UPS Standard
        [carrier] => United Parcel Service
[ups_12] => Array
        [title] => UPS Three-Day Select
        [carrier] => United Parcel Service
[ups_54] => Array
        [title] => UPS Worldwide Express Plus
        [carrier] => United Parcel Service
[ups_65] => Array
        [title] => UPS Saver
        [carrier] => United Parcel Service
[ups_01] => Array
        [title] => UPS Next Day Air
        [carrier] => United Parcel Service
[ups_02] => Array
        [title] => UPS Second Day Air
        [carrier] => United Parcel Service
[ups_03] => Array
        [title] => UPS Ground
        [carrier] => United Parcel Service
[ups_07] => Array
        [title] => UPS Worldwide Express
        [carrier] => United Parcel Service
[ups_08] => Array
        [title] => UPS Worldwide Expedited
        [carrier] => United Parcel Service
[customshippingrate_customshippingrate] => Array
        [title] => Custom Shipping Rate
        [carrier] => Custom Shipping Rate
*/
4
votes

I've created a function for this out of the answers already provided. This creates an option group of all the shipping methods:

function getShippingMethods($_methods, $fieldId, $fieldName, $fieldClass){
    $_shippingHtml = '<select name="' . $fieldName . '" id="' . $fieldId . '" class="' . $fieldClass . '">';
    foreach($_methods as $_carrierCode => $_carrier){
        if($_method = $_carrier->getAllowedMethods())  {
            if(!$_title = Mage::getStoreConfig('carriers/' . $_carrierCode . ' /title')) {
                $_title = $_carrierCode;
            }
            $_shippingHtml .= '<optgroup label="' . $_title . '">';
            foreach($_method as $_mcode => $_m){
                $_code = $_carrierCode . '_' . $_mcode;
                $_shippingHtml .= '<option value="' . $_code . '">' . $_m . '</option>';
            }
            $_shippingHtml .= '</optgroup>';
        }
    }
    $_shippingHtml .= '</select>';
    return $_shippingHtml;
}

The $_methods argument is an object from Magento:

$_methods = Mage::getSingleton('shipping/config')->getActiveCarriers();

So, we can call the function and pass the $_methods object to it as follows:

<?php echo getShippingMethods($_methods, 'shipping_method', 'shipping_method', 'shipping'); ?>

Hope that helps someone else.