Limit Woocommerce Shipping Options

A client recently asked me to modify his Woocommerce checkout process so that if the cart contained one particular product then shipping for the entire order would be restricted to a single option, but if that product was not in the cart then every shipping option except for that one would be available.

A Gist for my solution, modifying the Woocommerce template file cart-shipping.php is at GitHub if you want to get right to work, the rest is mostly me patting myself on the back.

Like this, with Product 1 being the flagged item:

Contents
Shipping Methods
Product 1, sku 123
Product 2, sku 456
Product 3, sku 457
… and so on
UPS
Product 2, sku 456
Product 3, sku 457
… and so on
FedEx
DHL
Local Pickup

The folks who developed Woocommerce made it extremely versatile by including lots of filters and action hooks and by providing a standard template-override system so that, if you can’t find a hook that will do what you need you can override the template, and write php functions to do the custom work.

Using the provided hooks has worked out better for me and I started down that path for this project, using the action hook woocommerce_review_order_before_shipping.

That worked fine until I realized that the results of this action are saved in the session, which caused a problem when the tagged product was added to the cart after my modified action was initially triggered because the deleted method no longer existed in the shipping options and the existing shipping options could not be used for this order because it contained the flagged product. It sounds more complicated than it was — the effect was that when the flagged item was added to a cart then there were no available shipping methods. Not good.

The solution was to modify the template rather than the action and so control what shipping methods are rendered on the screen, limiting what the user can choose from, rather than deleting shipping methods from the session.