<p>Ok, so shipping is not a necessity for a Commerce site (e.g. think about  e.g. digital downloads - shipping is not relevant here) - so Commerce does not force you to set a shipping method on an order.  </p>

<p>It's up to you to work out how and where you need to do this, if you do.</p>

<p>A lot (most,even) of it is often best tackled at the front end via your flow and some JS and/or general form validation stuff - you don't allow the user to proceed/submit if they have not chosen a method when you need them to.  We actually do it all, pretty much, in this end of things.</p>

<p>In addition, you CAN use any Commerce event you choose:
<a href="https://craftcommerce.com/docs/events-reference" rel="nofollow noreferrer">https://craftcommerce.com/docs/events-reference</a></p>

<p>...to add some extra validation (as you have with the address fields).  But it really depends on your precise checkout flow as to how you'd implement this.</p>

<p>For example, if your shipping page is POSTing to the Commerce controller <code>updateCart</code> when it submits, you could perhaps listen to:
<a href="https://craftcommerce.com/docs/events-reference#commerce_orders.onsaveorder" rel="nofollow noreferrer">https://craftcommerce.com/docs/events-reference#commerce_orders.onsaveorder</a></p>

<p>...and in that validate a shipping method is set (of course your order is saved many times during a commerce process so you should e.g. POST some other variable to check in there if you should actually trigger this validation).</p>

<p><code>&lt;input type="hidden" name="validateShipping" value="true"&gt;</code></p>

<p>And then in your event handler</p>

<p><code>if(craft()-&gt;request-&gt;getPost('validateShipping')){ ... validation here }</code></p>

<p>If there is an error, then to add the error you'd add it to the model you retrieved as an event parameter:</p>

<p><code>$order-&gt;addError('shippingMethod','No shipping method supplied!');</code></p>

<p>..and to set a flash message</p>

<p><code>craft()-&gt;userSession-&gt;setFlash('error', 'No shipping selected');</code></p>

<p>....but there are MANY possible ways you can implement this (e.g. no server side validation at all, if you can handle it all at the front end) -> the key thing is to really understand your checkout flow (and all the many ways users can travel through it) - quite thoroughly BEFORE you start implement the actual validation you need.</p>

CC BY-SA 3.0
2017-03-25T01:11:22.067Z
Wow, thanks for typing this up. Front end validation is on the UI/UX side, and I don't consider it at all a true security/QA feature. I already thought of running a hidden input or snooping the POST in some way; seeing your answer tells me to go with that PLUS a full check suite on payment process probably. I'm very new to Craft and usually don't do ECommerce sites, so I'm all security-worried. I'll give you the answer if no else chimes in by tomorrow with a better answer for my needs. I'm sure I'm overthinking/worrying. Thanks!
jrothafer
CC BY-SA 3.0
2017-03-25T01:14:36.740Z
I guess I'm not really seeing how this in particular is a security/QA feature as such but I guess there's never any real harm in more validation (unless it needlessly annoys customers).  

Payment is of course an entirely different kettle of fish and you need to consider things like PCI, and comes down very much to the client & gateway needs there.
Jeremy Daalder
CC BY-SA 3.0
2017-03-25T01:18:59.270Z
It may not be so much a security/QA thing, but catching a form submit issue and returning to the form with an appropriate error is important. There is also a custom payment processor integration with Craft Commerce for this client which I'm not familiar with, and the processor does require PCI compliancy and use an scanning audit tool. So, yeah, paranoia to provide security on all forms. Thanks again!
jrothafer
CC BY-SA 3.0
2017-03-26T01:20:49.223Z
So setting `addError` to my `onSaveOrder` (also tried `onBeforeSaveOrder`) event and setting `$event->performAction = false;` doesn't work at all. It moves along to the payment page. If I set a flash message, I can retrieve it on the payment page though. Any ideas? I'm going to edit my question and add my event code.
jrothafer
CC BY-SA 3.0
2017-03-26T23:15:47.977Z
Might need to take this to Slack for more.  But yeah, updateCart will always redirect if there's no errors in the update (see Commerce_CartController.php).  Easy to do/handle via ajax, but harder otherwise...
Jeremy Daalder
CC BY-SA 3.0
2017-04-02T03:47:23.490Z
Thanks for the follow-ups; I'll definitely do front-end validation for the shipping options, and figure out how to bounce on the back-end some other way. I don't like that I can't hook it the way I want (what seems intuitive to me), but oh well.
jrothafer
CC BY-SA 3.0
2017-03-25T01:00:23.927Z
2017-03-25T01:00:23.927Z
Jeremy Daalder
<p>I have a page, almost exactly the default Commerce <code>shipping.html</code> template and flow. With just the default shipping method (Free), the user can simply click through without being required to select a shipping method. I've found how to use a Business Logic plugin to address required fields for the address/billing section, but there doesn't seem to be an <code>event</code> I can hook to so I can yell and provide a flash error message if the user clicks "Select Shipping Method" without actually selecting one.</p>

<p>I know I can redirect back to the shipping method page on the payment page by checking the cart (ex: <code>{% if not cart.shippingMethod %}...</code>) but this doesn't provide a flash error unless I use some hacky method like a GET string error message.</p>

<p>Is there an event I can hook to I'm not finding in the docs that will let me force the choice of a shipping method? Or a setting in the plugin I'm missing?</p>

<p><strong>Edit</strong> </p>

<p>So I'm close, here's my event code that isn't working as I expect it to (did I tell you I'm new to Craft yet?):</p>

<pre><code>    craft()-&gt;on( 'commerce_orders.onSaveOrder', function ( Event $event ) {

        $order = $event-&gt;params['order'];

        if(craft()-&gt;request-&gt;getPost('validateShipping')){

            // add error to shippingMethod and see if we can get it
            $order-&gt;addError('shippingMethod',Craft::t('Please select a shipping option.'));
            $event-&gt;performAction = false;

            // pass a flash for testing 
            craft()-&gt;userSession-&gt;setFlash('error', 'No shipping elected');
        }
    });
</code></pre>

<p>So this moves on to the payment page and doesn't return to the shipping page with the added error. However, I am able to retrieve the set flash message on the payment page but <code>{{ dump(cart.getErrors()) }}</code> results in an empty array, so either the error is not attached to the cart properly in my event, or it is lost for some reason.</p>

<p><strong>Edit</strong> </p>

<p>I see I'm getting some up views; If anyone can still help I'd appreciate it. I have yet to get this working as per the only answer, and would love to know what I'm doing wrong in my Craft Commerce event.</p>

CC BY-SA 3.0
2017-03-24T22:46:22.510Z
To clarify - do you mean you have only one shipping method, Free Shipping, and therefore don't need any user selection of shipping at all right?  If so in any `updateCart` you can simply POST the shipping method to automatically set the shipping method and simply remove shipping from your flow altogether.  Or do you in fact have multiple shipping methods - it's not so clear above...
Jeremy Daalder
CC BY-SA 3.0
2017-03-24T23:01:39.970Z
Sorry, there will be multiple shipping methods in production, right now there is only one (the free one), but the user should **not** be able to move to the payment page if they don't select a shipping method (in this example, I can just not select the radio input for the free shipping method, and move to the payment page). So the `shippingMethod` radio array should be required and validated in the back end that some radio input has been selected.
jrothafer
CC BY-SA 3.0
2017-03-24T23:04:34.807Z
For example, I followed this post: http://craftcms.stackexchange.com/questions/15897/craft-commerce-validation-on-address-fields to validate fields on my address page. Now I'm on the shipping option page, and want to similarly vet the shipping methods selection POST (make sure they submitted a choice of shipping method), if not, return to the page with a flash error (`Please select a shipping method, etc...`).
jrothafer
CC BY-SA 3.0
2017-03-30T05:21:35.480Z
As per my comment below, `updateCart` will always re-direct on success if there are no errors...you can't currently stop that.  And setting the `performAction` to false will stop it saving the order.  (and therefore I guess the error).  You're going to have to re-think how you do this and again, front end stuff is the way to go here most likely.
Jeremy Daalder
<plugin-craftcommerce><shipping>
Require shipping method in Commerce order flow
# Require shipping method in Commerce order flow

(Asked by: username_0 on 2017-03-24)

I have a page, almost exactly the default Commerce shipping.html template and flow. With just the default shipping method (Free), the user can simply click through without being required to select a shipping method. I've found how to use a Business Logic plugin to address required fields for the address/billing section, but there doesn't seem to be an event I can hook to so I can yell and provide a flash error message if the user clicks "Select Shipping Method" without actually selecting one.
I know I can redirect back to the shipping method page on the payment page by checking the cart (ex: {% if not cart.shippingMethod %}...) but this doesn't provide a flash error unless I use some hacky method like a GET string error message.
Is there an event I can hook to I'm not finding in the docs that will let me force the choice of a shipping method? Or a setting in the plugin I'm missing?
Edit 
So I'm close, here's my event code that isn't working as I expect it to (did I tell you I'm new to Craft yet?):
    craft()->on( 'commerce_orders.onSaveOrder', function ( Event $event ) {

        $order = $event->params['order'];

        if(craft()->request->getPost('validateShipping')){

            // add error to shippingMethod and see if we can get it
            $order->addError('shippingMethod',Craft::t('Please select a shipping option.'));
            $event->performAction = false;

            // pass a flash for testing 
            craft()->userSession->setFlash('error', 'No shipping elected');
        }
    });

So this moves on to the payment page and doesn't return to the shipping page with the added error. However, I am able to retrieve the set flash message on the payment page but {{ dump(cart.getErrors()) }} results in an empty array, so either the error is not attached to the cart properly in my event, or it is lost for some reason.
Edit 
I see I'm getting some up views; If anyone can still help I'd appreciate it. I have yet to get this working as per the only answer, and would love to know what I'm doing wrong in my Craft Commerce event.

**Tags:** plugin-craftcommerce, shipping

> **Comments:**
> **username_1**: To clarify - do you mean you have only one shipping method, Free Shipping, and therefore don't need any user selection of shipping at all right?  If so in any `updateCart` you can simply POST the shipping method to automatically set the shipping method and simply remove shipping from your flow altogether.  Or do you in fact have multiple shipping methods - it's not so clear above...  
> **username_0**: Sorry, there will be multiple shipping methods in production, right now there is only one (the free one), but the user should **not** be able to move to the payment page if they don't select a shipping method (in this example, I can just not select the radio input for the free shipping method, and move to the payment page). So the `shippingMethod` radio array should be required and validated in the back end that some radio input has been selected.  
> **username_0**: For example, I followed this post: http://craftcms.stackexchange.com/questions/15897/craft-commerce-validation-on-address-fields to validate fields on my address page. Now I'm on the shipping option page, and want to similarly vet the shipping methods selection POST (make sure they submitted a choice of shipping method), if not, return to the page with a flash error (`Please select a shipping method, etc...`).  
> **username_1**: As per my comment below, `updateCart` will always re-direct on success if there are no errors...you can't currently stop that.  And setting the `performAction` to false will stop it saving the order.  (and therefore I guess the error).  You're going to have to re-think how you do this and again, front end stuff is the way to go here most likely.  

---

## 1 answers

### Answer by username_1 on 2017-03-25. Score: 3 | Accepted answer

Ok, so shipping is not a necessity for a Commerce site (e.g. think about e.g. digital downloads - shipping is not relevant here) - so Commerce does not force you to set a shipping method on an order.

It's up to you to work out how and where you need to do this, if you do.

A lot (most,even) of it is often best tackled at the front end via your flow and some JS and/or general form validation stuff - you don't allow the user to proceed/submit if they have not chosen a method when you need them to. We actually do it all, pretty much, in this end of things.

In addition, you CAN use any Commerce event you choose:
<https://craftcommerce.com/docs/events-reference>

...to add some extra validation (as you have with the address fields). But it really depends on your precise checkout flow as to how you'd implement this.

For example, if your shipping page is POSTing to the Commerce controller `updateCart` when it submits, you could perhaps listen to:
<https://craftcommerce.com/docs/events-reference#commerce_orders.onsaveorder>

...and in that validate a shipping method is set (of course your order is saved many times during a commerce process so you should e.g. POST some other variable to check in there if you should actually trigger this validation).

And then in your event handler

`if(craft()->request->getPost('validateShipping')){ ... validation here }`

If there is an error, then to add the error you'd add it to the model you retrieved as an event parameter:

`$order->addError('shippingMethod','No shipping method supplied!');`

..and to set a flash message

`craft()->userSession->setFlash('error', 'No shipping selected');`

....but there are MANY possible ways you can implement this (e.g. no server side validation at all, if you can handle it all at the front end) -> the key thing is to really understand your checkout flow (and all the many ways users can travel through it) - quite thoroughly BEFORE you start implement the actual validation you need.

> **Comments:**
> **username_0**: Wow, thanks for typing this up. Front end validation is on the UI/UX side, and I don't consider it at all a true security/QA feature. I already thought of running a hidden input or snooping the POST in some way; seeing your answer tells me to go with that PLUS a full check suite on payment process probably. I'm very new to Craft and usually don't do ECommerce sites, so I'm all security-worried. I'll give you the answer if no else chimes in by tomorrow with a better answer for my needs. I'm sure I'm overthinking/worrying. Thanks!  
> **username_1**: I guess I'm not really seeing how this in particular is a security/QA feature as such but I guess there's never any real harm in more validation (unless it needlessly annoys customers).    Payment is of course an entirely different kettle of fish and you need to consider things like PCI, and comes down very much to the client & gateway needs there.  
> **username_0**: It may not be so much a security/QA thing, but catching a form submit issue and returning to the form with an appropriate error is important. There is also a custom payment processor integration with Craft Commerce for this client which I'm not familiar with, and the processor does require PCI compliancy and use an scanning audit tool. So, yeah, paranoia to provide security on all forms. Thanks again!  
> **username_0**: So setting `addError` to my `onSaveOrder` (also tried `onBeforeSaveOrder`) event and setting `$event->performAction = false;` doesn't work at all. It moves along to the payment page. If I set a flash message, I can retrieve it on the payment page though. Any ideas? I'm going to edit my question and add my event code.  
> **username_1**: Might need to take this to Slack for more.  But yeah, updateCart will always redirect if there's no errors in the update (see Commerce_CartController.php).  Easy to do/handle via ajax, but harder otherwise...  
> **username_0**: Thanks for the follow-ups; I'll definitely do front-end validation for the shipping options, and figure out how to bounce on the back-end some other way. I don't like that I can't hook it the way I want (what seems intuitive to me), but oh well.  

---

