phpwordpresswoocommercecheckoutshipping-method

Prevent access to checkout without shipping method in WooCommerce


I am trying to remove the proceed to checkout button and restrict access to the checkout page until a customer fills out the 'Calculate shipping' option on the basket page.

I created a local shipping method that's restricted to multiple post/zipcodes. I then went and added this to my functions.php file.

function disable_checkout_button_no_shipping() {
  $package_counts = array();

  // get shipping packages and their rate counts
  $packages = WC()->shipping->get_packages();
  foreach( $packages as $key => $pkg )
      $package_counts[ $key ] = count( $pkg[ 'rates' ] );

  // remove button if any packages are missing shipping options
  if( in_array( 0, $package_counts ) )
      remove_action( 'woocommerce_proceed_to_checkout', 'woocommerce_button_proceed_to_checkout', 20 );
}
add_action( 'woocommerce_proceed_to_checkout', 'disable_checkout_button_no_shipping', 1 );

However when I test the site in different browsers and in incognito modes the 'Proceed to checkout' button is there.

If I click on the 'Calculate shipping' link and not fill out the form but update it the button disappears. I basically want the button to appear when a customer fills out the 'Calculate shipping' form on the cart page (and have one of the postcodes in my shipping method) before being able to proceed to the checkout page.


Solution

  • You should better try with the "Chosen shipping method" from WooCommerce session like:

    function disable_checkout_button_no_shipping() {
    
        $chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
    
        // remove button if there is no chosen shipping method
        if( empty( $chosen_shipping_methods ) ) {
            remove_action( 'woocommerce_proceed_to_checkout', 'woocommerce_button_proceed_to_checkout', 20 );
        }
    }
    add_action( 'woocommerce_proceed_to_checkout', 'disable_checkout_button_no_shipping', 1 );
    

    Or in a different way using woocommerce_check_cart_items action hook:

    add_action( 'woocommerce_check_cart_items', 'required_chosen_shipping_methods' );
    function required_chosen_shipping_methods() {
        $chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
    
        if( is_array( $chosen_shipping_methods ) && count( $chosen_shipping_methods ) > 0 ) {
            // Display an error message
            wc_add_notice( __("A shipping method is required in order to proceed to checkout."), 'error' );
        }
    }
    

    It should better work.