3

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.

  • 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 Mar 24 '17 at 22:46
  • 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 Mar 24 '17 at 23:01
  • For example, I followed this post: craftcms.stackexchange.com/questions/15897/… 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 Mar 24 '17 at 23:04
  • 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 Mar 30 '17 at 5:21
3

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).

<input type="hidden" name="validateShipping" value="true">

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.

  • 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 Mar 25 '17 at 1:11
  • 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 Mar 25 '17 at 1:14
  • 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 Mar 25 '17 at 1:18
  • 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 Mar 26 '17 at 1:20
  • 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 Mar 26 '17 at 23:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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