Well, I think somewhere in-between Brad's answer and this is the solution...
I too have a mix of tangible and tangible products on my site. In the CP I have checked the "Free Shipping" checkbox for all non-tangible products when I create them.
Because I eventually will have products that require shipping, I didn't want to completely do away with the shipping screen. Here is what I came up with.
EDIT/UPDATE
After working through this more, I wanted to provide more insight for others who might come across this thread. As always if there is room for improvement, please let me know so it can be updated.
/shop/checkout/addresses/
{% set freeShipping = false %}
{% for item in cart.lineItems %}
{% set variant = item.purchasable %}
{% set product = variant.product %}
{% if product.freeShipping %}
{% set freeShipping = true %}
{% else %}
{% set freeShipping = false %}
{% endif %}
{% endfor %}
...
<form method="post" accept-charset="utf-8">
<input type="hidden" name="action" value="commerce/cart/updateCart">
{% if freeShipping %}
<input type="hidden" name="redirect" value="shop/checkout/payment"/>
{% else %}
<input type="hidden" name="redirect" value="shop/checkout/shipping"/>
{% endif %}
...
{% if freeShipping %}
<input type="hidden" name="sameAddress" value="1">
{% else %}
<input type="hidden" name="sameAddress" value="0">
<input type="checkbox" name="sameAddress" id="sameAddress"
checked="checked">Use same address for shipping
{% endif %}
...
{% if freeShipping %}
<button type="submit" class="btn btn-primary">Continue To Payment</button>
{% else %}
<button type="submit" class="btn btn-primary">Continue To Shipping</button>
{% endif %}
<span>or <a href="{{ url('/shop/cart') }}">Return to cart</a></span>
What I'm doing here is looping through my cart to see if freeShipping
has been selected for every product (see above). Later I check the same var and handle the form redirect appropriately. If all products in my cart are set to freeShipping
I don't really want to make the user have to enter a shipping address. So I will set the sameAddress
for them. This way we still have a shipping address should we need it in the future. Then at the end changing the next button accordingly as well.
/shop/checkout/payment
{% set freeShipping = false %}
{% for item in cart.lineItems %}
{% set variant = item.purchasable %}
{% set product = variant.product %}
{% if product.freeShipping %}
{% set freeShipping = true %}
{% else %}
{% set freeShipping = false %}
{% endif %}
{% endfor %}
...
{% for adjustment in cart.adjustments %}
<div class="adjustment">
{% if adjustment.name == "Free Shipping" %}
{% if not freeShipping %}
<h4>{{ adjustment.name }}</h4>
<p>{{ adjustment.amount|commerceCurrency(cart.currency) }}
({{ adjustment.description }})</p>
{% endif %}
{% else %}
<h4>{{ adjustment.name }}</h4>
<p>{{ adjustment.amount|commerceCurrency(cart.currency) }}
({{ adjustment.description }})</p>
{% endif %}
</div>
{% endfor %}
...
{% if not cart.shippingMethod %}
{#
If the order requires a shipping method be selected, you could redirect back to the shipping page until one is applied to the order.
{% redirect "shop/checkout/shipping" %}
You might also want to add a php plugin hook to require
#}
{% if freeShipping %}
{# Shipping not applicable. #}
{% else %}
<p><strong>Shipping</strong> None selected. <a href="{{ url('shop/checkout/shipping') }}">
Choose a shipping method.</a>
</p>
{% endif %}
{% endif %}
Same thing here, checking for freeShipping
on all items. The biggest change here is (purely cosmetic) I didn't want to show "Free Shipping" since we aren't shipping anything. The last part is just updating existing shipping logic to accommodate the free shipping.
/shop/checkout/shipping
{% set freeShipping = false %}
{% for item in cart.lineItems %}
{% set variant = item.purchasable %}
{% set product = variant.product %}
{% if product.freeShipping %}
{% set freeShipping = true %}
{% else %}
{% set freeShipping = false %}
{% endif %}
{% endfor %}
...
{% if freeShipping %}
<p>None of the items in your cart require shipping.</p>
<form method="post" accept-charset="utf-8">
<input type="hidden" name="action" value="commerce/cart/updateCart">
<input type="hidden" name="redirect" value="shop/checkout/payment">
<input type="hidden" name="shippingMethod" value="freeShipping">
{{ getCsrfInput() }}
<button type="submit" class="btn btn-primary">Continue to payment</button>
</form>
{% else %}
<h3>Shipping Method</h3>
<p>Select a shipping method below.</p>
...
{% endif %}
All we are doing here is checking (again) for freeShipping
. If everything qualifies, I only show a button that tells the customer they don't have anything to ship and I send them to the /payment
screen. I suppose you could just set a {% redirect %}
as well.