I agree with the basic underlying premise that showing full cost - i.e. with shipping - is essential on the cart index page for a modern checkout. Customers loathe what they see as a hidden surprise if they hit shipping costs later in the process and your completion rate plummets in my experience.
Luke's answer is right about the root cause of the issue - Commerce currently requires a customer with a valid 'address' before you can set shipping on the cart, and a 'valid address' is (out of the box) at least a firstName
and a lastName
. You can definitely throw a countryId in a hidden field as a default, but only in addition to setting the address details.
This has become without doubt my least favourite thing about Commerce as it currently stands, and I have spent WAY more time on solving this problem than anything else in Commerce. To be fair I really should have discussed this a lot more with Luke (Holder, not Pearce above!) - as I really think this needs to be solved (by Commerce) sooner rather than later for a sophisticated checkout flow to be achievable without too much hassle. But at a certain point I was too far along to contemplate going back to scratch with it (as I will have to once a proper fix comes I guess!). So I've hacked away at it and have it all working pretty well.
So what ARE your options (I've tried all three, and none of them are great):
From easiest to hardest:
Create a fake 'address' for your customer (I used Mr. Shipping Quote for this) - i.e. set firstName Shipping, lastName Quote, and have a select for your countries I guess -> so that you can then use standard methods to set shipping on the cart, and then on your shipping page basically update this with the actual details when you get them
(as per Luke above) - Write an adjuster to add this shipping until such a point as you do get an address, then once you do make the adjuster adjsut to $0...as you'll then have shipping set on the cart appropriately 'for real'
(And this is what we do on imagescience.com.au for a variety of reasons) - write a shipping plugin of your own and ALSO give this an option of being called by controller separate to all the regular shipping stuff in Commerce- so that you can then do a bit of fancy JS on the front end to add the result of the controller to the cart totals on your cart page. That is, fake it totally until late in your checkout when you really do have an address.
Of these, I think option 1 is about as far as you want to hack in most situations. Depending on your checkout flow, and how fancy you want to get with address handling/customer address libraries, this can potentially be a relatively simple fix for the issue. It works for basic scenarios, you basically just need, on your address input form, to test for the Shipping Quote values for those fields and if those are set, display blank fields for user input.
Option 2 was where I started and could also work, but it gets fairly fiddly fast and it seems a shame to just abandon all of Commerce's shipping stuff - seemed more future proof to not do it this way, to me. But in retrospect I'm not sure about that, this may have proved easier than option 3 in the end...
Option 3 is actually diabolical to get right. But, it can solve pretty much all the problems. However, there are MANY complications with it because if you allow a flow back and forth between your cart/shipping/payment pages, there are a bunch of scenarios that arise to do with the possibility that the cart MAY or MAY NOT not have shipping on it, and/or DOES/DOES NOT have coupons, discounts applied - to make it work consistently you have to do stuff like manually summing the lineItem totals etc. It works, but it's a right mess if you want a really flexible checkout flow - and it's a lot more complicated than it initially looks. Add to that address handling such as deleting addresses, adding new ones for billing/shipping etc along the way, and you'll end up writing well more JS than you like (well, I have). Whilst I have it working, I honestly can't recommend it as an approach.
In retrospect, I wish I had persisted with option 1 as an approach for longer, although it soon gets complicated by the same issues as option 3 really, if you allow back and forth flow between your cart pages (and how can you not?).
(Oh, and shipping currently doesn't deal with tax, which further complicated getting your totals/tax right with these approaches)
To really solve this area I'd love to see:
- (The biggie!) Set shipping on the cart without requiring irrelevant
data at that point like names - shipping should only need what it
actually needs for each shipping option (including custom plugins).
- Some basic address controllers - that are separate from the cart - add/remove (and addresses should be elements with fields etc!)
- Tax support with shipping
I wish I could give you a 'this is how you do it' answer but it's really pretty complicated and far from ideal at this point. If you CAN live without shipping being shown in the cart (and just use e.g. a chart as Luke suggests) - your life will be vastly simpler, that's for sure!