<p><a href="https://craftcommerce.com/docs/order-model" rel="nofollow noreferrer">Commerce_OrderModel</a> has a <a href="https://craftcommerce.com/docs/order-model#getshippingmethod" rel="nofollow noreferrer"><code>getShippingMethod()</code></a> that will return a <code>Commerce_ShippingMethodModel</code> class of the current shipping method, or null if nothing has been set.</p>

<p>If you've already got the order in the template is should be as simple as:</p>

<pre><code>{% if order.getShippingMethod() %}
    Shipping.
{% else %}
    No shipping.
{% endif %}
</code></pre>

CC BY-SA 3.0
2017-04-09T19:29:46.423Z
As a follow up question, Is there a way to check for this similar thing at the cart level? For example, I have not checked out yet, but all products in my cart have `freeShipping` selected. At this point, I don't know if my whole order qualifies for free shipping so I am checking each line item. Is `cart.totalShippingCost` accurate at this point in the checkout process?
Damon
CC BY-SA 3.0
2017-04-09T23:22:50.633Z
A cart is just an [OrderModel](https://craftcommerce.com/docs/order-model#overview) with its `isCompleted` property set to `false`.
Brad Bell
CC BY-SA 3.0
2017-04-06T16:56:00.843Z
2017-04-06T16:56:00.843Z
Brad Bell
<p>Well, I think somewhere in-between Brad's answer and this is the solution...</p>

<p>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.</p>

<p>Because I eventually <em>will</em> have products that require shipping, I didn't want to completely do away with the shipping screen. Here is what I came up with.</p>

<p><strong>EDIT/UPDATE</strong></p>

<p>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.</p>

<p><strong>/shop/checkout/addresses/</strong></p>

<pre><code>{% 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 %}

...

&lt;form method="post" accept-charset="utf-8"&gt;
&lt;input type="hidden" name="action" value="commerce/cart/updateCart"&gt;

{% if freeShipping %}
    &lt;input type="hidden" name="redirect" value="shop/checkout/payment"/&gt;
{% else %}
    &lt;input type="hidden" name="redirect" value="shop/checkout/shipping"/&gt;
{% endif %}


...

{% if freeShipping %}
    &lt;input type="hidden" name="sameAddress" value="1"&gt;
{% else %}
    &lt;input type="hidden" name="sameAddress" value="0"&gt;
    &lt;input type="checkbox" name="sameAddress" id="sameAddress"
                                               checked="checked"&gt;Use same address for shipping
{% endif %}


...

{% if freeShipping %}
    &lt;button type="submit" class="btn btn-primary"&gt;Continue To Payment&lt;/button&gt;
{% else %}
    &lt;button type="submit" class="btn btn-primary"&gt;Continue To Shipping&lt;/button&gt;
{% endif %}

&lt;span&gt;or &lt;a href="{{ url('/shop/cart') }}"&gt;Return to cart&lt;/a&gt;&lt;/span&gt;
</code></pre>

<p>What I'm doing here is looping through my cart to see if <code>freeShipping</code> 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 <code>freeShipping</code> I don't really want to make the user have to enter a shipping address. So I will set the <code>sameAddress</code> 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.</p>

<p><strong>/shop/checkout/payment</strong></p>

<pre><code>{% 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 %}
    &lt;div class="adjustment"&gt;
        {% if adjustment.name == "Free Shipping" %}
            {% if not freeShipping %}
                &lt;h4&gt;{{ adjustment.name }}&lt;/h4&gt;
                &lt;p&gt;{{ adjustment.amount|commerceCurrency(cart.currency) }}
                                    ({{ adjustment.description }})&lt;/p&gt;
            {% endif %}
        {% else %}
            &lt;h4&gt;{{ adjustment.name }}&lt;/h4&gt;
            &lt;p&gt;{{ adjustment.amount|commerceCurrency(cart.currency) }}
            ({{ adjustment.description }})&lt;/p&gt;
        {% endif %}
    &lt;/div&gt;
{% 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 %}
        &lt;p&gt;&lt;strong&gt;Shipping&lt;/strong&gt; None selected. &lt;a href="{{ url('shop/checkout/shipping') }}"&gt;
        Choose a shipping method.&lt;/a&gt;
        &lt;/p&gt;
    {% endif %}
{% endif %}
</code></pre>

<p>Same thing here, checking for <code>freeShipping</code> 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.</p>

<p><strong>/shop/checkout/shipping</strong></p>

<pre><code>{% 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 %}
    &lt;p&gt;None of the items in your cart require shipping.&lt;/p&gt;
    &lt;form method="post" accept-charset="utf-8"&gt;
        &lt;input type="hidden" name="action" value="commerce/cart/updateCart"&gt;
        &lt;input type="hidden" name="redirect" value="shop/checkout/payment"&gt;
        &lt;input type="hidden" name="shippingMethod" value="freeShipping"&gt;
        {{ getCsrfInput() }}

        &lt;button type="submit" class="btn btn-primary"&gt;Continue to payment&lt;/button&gt;         
    &lt;/form&gt;
{% else %}
    &lt;h3&gt;Shipping Method&lt;/h3&gt;
    &lt;p&gt;Select a shipping method below.&lt;/p&gt;

    ...
{% endif %}
</code></pre>

<p>All we are doing here is checking (again) for <code>freeShipping</code>. 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 <code>/payment</code> screen. I suppose you <em>could</em> just set a <code>{% redirect %}</code> as well.</p>

CC BY-SA 3.0
2017-04-10T17:14:27.590Z
Thanks. I may end up doing something like what you've suggested. I'm still getting my head around the way shipping works...Shipping Categories and Methods and Zones, Oh my...
casey
CC BY-SA 3.0
2017-04-10T20:36:28.470Z
What I struggled with was I wanted to check if the cart had anything that qualified for shipping before actually getting to the shipping screen. So I don't think checking `cart.totalShippingCost` would be accurate since I haven't even gotten to that screen yet. Hope this helps, I'd be interested to know what you come up with!
Damon
CC BY-SA 3.0
2017-04-10T02:09:18.210Z
2017-04-14T15:46:20.637Z
2017-04-14T15:46:20.637Z
Damon
<p>We're selling a mix of both tangible and digital products with Commerce.</p>

<p>If an order doesn't require shipping, I'd rather just take them to directly to the final one page checkout/payment form.</p>

<p>Is there a way to determine this natively or do I need to add a "RequireShipping" field and loop through the line items to see if one exists in the user's cart?</p>

<plugin-craftcommerce><shipping>
Is there a way to determine if an order requires shipping?
# Is there a way to determine if an order requires shipping?

(Asked by: username_0 on 2017-04-06)

We're selling a mix of both tangible and digital products with Commerce.

If an order doesn't require shipping, I'd rather just take them to directly to the final one page checkout/payment form.

Is there a way to determine this natively or do I need to add a "RequireShipping" field and loop through the line items to see if one exists in the user's cart?

**Tags:** plugin-craftcommerce, shipping

---

## 2 answers

### Answer by username_1 on 2017-04-06. Score: 1

Commerce_OrderModel has a getShippingMethod() that will return a Commerce_ShippingMethodModel class of the current shipping method, or null if nothing has been set.
If you've already got the order in the template is should be as simple as:
{% if order.getShippingMethod() %}
    Shipping.
{% else %}
    No shipping.
{% endif %}

> **Comments:**
> **username_2**: As a follow up question, Is there a way to check for this similar thing at the cart level? For example, I have not checked out yet, but all products in my cart have `freeShipping` selected. At this point, I don't know if my whole order qualifies for free shipping so I am checking each line item. Is `cart.totalShippingCost` accurate at this point in the checkout process?  
> **username_1**: A cart is just an [OrderModel](https://craftcommerce.com/docs/order-model#overview) with its `isCompleted` property set to `false`.  

---

### Answer by username_2 on 2017-04-10. Score: 1

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 %}

...




{% if freeShipping %}
    
{% else %}
    
{% endif %}


...

{% if freeShipping %}
    
{% else %}
    
    Use same address for shipping
{% endif %}


...

{% if freeShipping %}
    Continue To Payment
{% else %}
    Continue To Shipping
{% endif %}

or Return to cart

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 %}
    
        {% if adjustment.name == "Free Shipping" %}
            {% if not freeShipping %}
                {{ adjustment.name }}
                {{ adjustment.amount|commerceCurrency(cart.currency) }}
                                    ({{ adjustment.description }})
            {% endif %}
        {% else %}
            {{ adjustment.name }}
            {{ adjustment.amount|commerceCurrency(cart.currency) }}
            ({{ adjustment.description }})
        {% endif %}
    
{% 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 %}
        Shipping None selected. 
        Choose a shipping method.
        
    {% 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 %}
    None of the items in your cart require shipping.
    
        
        
        
        {{ getCsrfInput() }}

        Continue to payment         
    
{% else %}
    Shipping Method
    Select a shipping method below.

    ...
{% 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.

> **Comments:**
> **username_0**: Thanks. I may end up doing something like what you've suggested. I'm still getting my head around the way shipping works...Shipping Categories and Methods and Zones, Oh my...  
> **username_2**: What I struggled with was I wanted to check if the cart had anything that qualified for shipping before actually getting to the shipping screen. So I don't think checking `cart.totalShippingCost` would be accurate since I haven't even gotten to that screen yet. Hope this helps, I'd be interested to know what you come up with!  

---

