I'm managing a store set up with simple, downloadable and virtual products. We have a cart price rule that offers free shipping on orders over £50 being shipped within the UK, which works exactly as it should when there are only simple products in the cart. If, however, the customer then adds a downloadable or virtual product, of any price, the free shipping rule no longer applies. The shipping itself is handled by MatrixRates, but I don't believe this should interact with the free shipping rule. [EDIT: The same issue occurs with both flat rate and vanilla table rates.]

Here are the conditions and action settings for the cart price rule. enter image description here

Some examples:

  1. Customer adds two basic £20 items, giving a subtotal of £40 and the standard delivery shipping option.
  2. Customer adds a third basic £20 item, giving a subtotal of £60 and the free shipping option is applied.
  3. Customer then adds a downloadable product costing £5, giving a subtotal of £65, however the shipping reverts back to standard delivery only.
  4. Customer removes the downloadable product and the free shipping is reapplied.

  1. Customer adds basic products totalling over £50, free shipping is applied
  2. Customer adds a free virtual or downloadable product to the cart, shipping only allows standard delivery.
  3. Customer removes the downloadable product and the free shipping is reapplied.

I've been playing with this for a while, but haven't found any solutions. I found this Stack Overflow post from earlier this month identifying the same problem, but with no solution. Does anyone have any ideas?

3 Answers 3


There is the same bug on Magento 1.6. This fix is working and I hope to work on Magento 1.7 too.

Open app/code/core/Mage/SalesRule/Model/Validator.php and add below this:

protected $_baseRoundingDeltas = array();

this code:

protected $_address = null;

also in protected function _getAddress below this:

if ($item instanceof Mage_Sales_Model_Quote_Address_Item) {
    $address = $item->getAddress();

add this:

} elseif ($this->_address) {
    $address = $this->_address;

and finally in public function reset above this:

return $this;

add this:

$this->_address = $address;

The For shipment with matching items option works by setting a free_shipping flag on the address. When it comes time to determine the available shipping methods and their prices, each method is responsible for checking that flag and providing a free shipping option (if the method is configured to do so).

It sounds like MatrixRates may be causing this issue. You can test this theory by disabling the MatrixRates shipping method and enabling a built-in method instead - if the rule starts working, then MatrixRates is the culprit.

A couple reasons why MatrixRates might be behaving this way:

  • The module isn't checking the free_shipping flag
  • It's not properly configured to allow free shipping
  • Hi Colin, thanks for the response. Unfortunately the same issue occurs with both flat rate shipping and the vanilla table rates. In case it wasn't clear, the free shipping works fine with MatrixRates (and the other shipping methods) unless there is a downloadable or virtual product in the cart, at which point it no longer applies. Commented Jul 9, 2014 at 14:04
  • Ah okay. Can you try changing the Free Shipping cart rule to For matching items only? Commented Jul 9, 2014 at 14:06
  • Yes, I tried that originally and it works in exactly the same way - fine with simple products, doesn't apply if there are any virtual/downloadable products. Commented Jul 9, 2014 at 14:08
  • Perhaps it's the Shipping Country condition not playing nicely with your virtual products? Unfortunately I'm not really sure how you'd work around that. Commented Jul 9, 2014 at 14:21
  • Thanks for continuing to provide suggestions, I just tried the rule without the country restriction, but no luck, exactly the same problem. Commented Jul 9, 2014 at 14:29

So the problem with this is the code in the class Mage_SalesRule_Model_Validator

protected function _getAddress(Mage_Sales_Model_Quote_Item_Abstract $item)
    if ($item instanceof Mage_Sales_Model_Quote_Address_Item) {
        $address = $item->getAddress();
    } elseif ($item->getQuote()->getItemVirtualQty() > 0) {
        $address = $item->getQuote()->getBillingAddress();
    } else {
        $address = $item->getQuote()->getShippingAddress();
    return $address;

It decides which address to check depending on the item. If there is a downloadable item in the cart, it will take the billing address. However, when a downloadable item is present together with a simple item, Magento will assign all the money values to the shipping address.

Thus, your rule will fail, because the subtotal is 0 at the billing address, but the downloadable item wants to check the billing address.

I think this is a bug in Magento and this method should be changed to reflect this issue.

An easy fix for this would be to rewrite the method to:

    protected function _getAddress(Mage_Sales_Model_Quote_Item_Abstract $item)
        $quote = $item->getQuote();
        if ($quote->isVirtual()) {
            return $quote->getBillingAddress();
        } else {
            return $quote->getShippingAddress();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.