Get fields from checkout form into calculate_shipping

calculate_shipping() is not always called

First off, you should know that the calculate_shipping() method of your shipping method class will only be called when the shipping rates are calculated for the first time (in the current WooCommerce session), each time after a product is added to the cart, and whenever the shipping address is changed — from the cart or checkout page.

But of course, a plugin or custom code can programmatically call the method (or re-calculate the rates) at any times. However, the default behavior is as follows:

Rates are stored in the session based on the package hash to avoid re-calculation every page load.

And the calculate_shipping() method is executed by the WC_Shipping class through its calculate_shipping_for_package() method. In fact, the above quote was taken from the description of WC_Shipping::calculate_shipping_for_package() which calls WC_Shipping_Method::get_rates_for_package() and eventually the calculate_shipping() method in your own class.

How to get the submitted value of a form field in the checkout form from the calculate_shipping() method

So if you have this in the checkout form:

<input type="text" name="my_field"...>

Then you can get the submitted (POSTed) value using either the $_POST superglobal or the WC_Checkout::get_value() method:

  1. $_POST['my_field']

  2. WC()->checkout->get_value( 'my_field' )

It's as simple as that. :)


To ensure calculate_shipping is called

Run something similar to the following to clear out the session information, which will indicate that calculation still needs to be done. Be aware that if you do this on every page, it will mean that the shipping is constantly being recalculated when it doesn't need to be.

$packages = WC()->cart->get_shipping_packages();
foreach( $packages as $package_key => $package ) {
    $session_key  = 'shipping_for_package_'.$package_key;
    $stored_rates = WC()->session->__unset( $session_key );
}