How to restrict Shipping Method options based on a product attribute?
Solution Logic
I set up a solution that iterates through each item in a customer's cart, check's each item's height attribute, then if any item is over a given length, it raises the flag(s) for whatever shipping method can't ship something that length, and hides the shipping method(s) from the customer's view.
I configured this solution to work for USPS (max length 12", limited by the largest box our store offers), UPS (max length 108" per UPS Ground website), and FedEx (max length 165" per FedEx website).
To reiterate, if any one item is over the maximum length, then that shipping method is disabled for the entire cart. I injected this logic check into the "View Cart" and "Onepage Checkout" pages to hide any unavailable shipping methods dynamically.
Files changed
/app/design/frontend/base/default/template/checkout/onepage/shipping_method/available.phtml
/app/design/frontend/rwd/default/template/checkout/cart/shipping.phtml
PHP added
Both Files
<?php
$cart = Mage::getModel('checkout/cart')->getQuote();
$uspsAllowed = true; // USPS allowed by default (unless height attrib greater than 12)
$fedexAllowed = true; // FedEx allowed by default (unless height attrib greater than 108)
$upsAllowed = true; // UPS allowed by default (unless height attrib greater than 165)
foreach ($cart->getAllItems() as $item) {
$storeId = 1; // Mbs Standoffs store code
$attributeId = 'height';// Height attribute code
$qty += $item->getQty();// Keep track of total item quantity in cart
$productId = $item->getProduct()->getId();
$productLength = Mage::getResourceModel('catalog/product')->getAttributeRawValue($productId, $attributeId, $storeId);
if($productLength > 165) {
$uspsAllowed = false;
$fedexAllowed = false;
$upsAllowed = false;
} elseif($productLength > 108) {
$uspsAllowed = false;
$upsAllowed = false;
} elseif($productLength > 12) { $uspsAllowed = false; }
} ?>
Shipping.phtml
<?php if($this->escapeHtml($this->getCarrierName($code)) == 'United States Postal Service' && $uspsAllowed == false) { ?>
<li>This shipping method is currently unavailable. If you would like to ship using this shipping method, please contact us.</li>
<?php } elseif($this->escapeHtml($this->getCarrierName($code)) == 'United Parcel Service' && $upsAllowed == false) { ?>
<li>One or more of the items in your cart will need to be shipped through UPS Freight. If you would like to ship using this shipping method, please contact us.</li>
<?php } elseif($this->escapeHtml($this->getCarrierName($code)) == 'Federal Express' && $fedexAllowed == false) { ?>
<li>One or more of the items in your cart will need to be shipped through FedEx Freight. If you would like to ship using this shipping method, please contact us.</li>
<?php } else { ?>
<?php foreach ($_rates as $_rate): ?>
<li<?php if ($_rate->getErrorMessage()) echo ' class="error-msg"';?>>
<?php if ($_rate->getErrorMessage()): ?>
<?php echo $this->escapeHtml($_rate->getErrorMessage()) ?>
<?php else: ?>
<input name="estimate_method" type="radio" value="<?php echo $this->escapeHtml($_rate->getCode()) ?>" id="s_method_<?php echo $_rate->getCode() ?>"<?php if($_rate->getCode()===$this->getAddressShippingMethod()) echo ' checked="checked"' ?> class="radio" />
<label for="s_method_<?php echo $_rate->getCode() ?>"><?php echo $this->escapeHtml($_rate->getMethodTitle()) ?>
<?php $_excl = $this->getShippingPrice($_rate->getPrice(), $this->helper('tax')->displayShippingPriceIncludingTax()); ?>
-
<?php $_incl = $this->getShippingPrice($_rate->getPrice(), true); ?>
<?php echo $_excl; ?>
<?php if ($this->helper('tax')->displayShippingBothPrices() && $_incl != $_excl): ?>
(<?php echo $this->__('Incl. Tax'); ?> <?php echo $_incl; ?>)
<?php endif; ?>
</label>
<?php endif ?>
</li>
<?php endforeach; ?>
<?php } ?>
Available.phtml
<?php if($this->escapeHtml($this->getCarrierName($code)) == 'USPS' && $uspsAllowed == false) { ?>
<li>This shipping method is currently unavailable. If you would like to ship using this shipping method, please contact us.</li>
<?php } elseif($this->escapeHtml($this->getCarrierName($code)) == 'UPS' && $upsAllowed == false) { ?>
<li>One or more of the items in your cart will need to be shipped through UPS Freight. If you would like to ship using this shipping method, please contact us.</li>
<?php } elseif($this->escapeHtml($this->getCarrierName($code)) == 'FedEx' && $fedexAllowed == false) { ?>
<li>One or more of the items in your cart will need to be shipped through FedEx Freight. If you would like to ship using this shipping method, please contact us.</li>
<?php } else { ?>
<?php $_sole = $_sole && count($_rates) == 1; foreach ($_rates as $_rate): ?>
<?php if ($this->escapeHtml($_rate->getMethodTitle()) == 'Priority Mail 1-Day Small Flat Rate Box' || $this->escapeHtml($_rate->getMethodTitle()) == 'Priority Mail 2-Day Small Flat Rate Box' || $this->escapeHtml($_rate->getMethodTitle()) == 'Priority Mail 3-Day Small Flat Rate Box') {
// Do nothing. Small Flat Rate not offered on frontend.
} elseif (($this->escapeHtml($_rate->getMethodTitle()) == 'Priority Mail 1-Day Medium Flat Rate Box' || $this->escapeHtml($_rate->getMethodTitle()) == 'Priority Mail 2-Day Medium Flat Rate Box' || $this->escapeHtml($_rate->getMethodTitle()) == 'Priority Mail 3-Day Medium Flat Rate Box') && $qty >= 50) {
// Do nothing. Medium Flat Rate not offered on frontend if customer is shipping more than 50 items.
} elseif (($this->escapeHtml($_rate->getMethodTitle()) == 'Priority Mail 1-Day Large Flat Rate Box' || $this->escapeHtml($_rate->getMethodTitle()) == 'Priority Mail 2-Day Large Flat Rate Box' || $this->escapeHtml($_rate->getMethodTitle()) == 'Priority Mail 3-Day Large Flat Rate Box') && $qty >= 100) {
// Do nothing. Large Flat Rate not offered on frontend if customer is shipping more than 100 items. ?>
<li>This shipping method is currently unavailable. If you would like to ship using this shipping method, please contact us.</li>
<?php } else { ?>
// Normal code section
<?php } ?>