1

I am trying to add an input field which allows the customer (guest) to enter their postcode on the product page before 'add to cart' which then sets/prepopulates the postcode in the basket & checkout without them having to enter their details or login/create an account.

I've seen some resources saying the shipping calculator on the basket page is complicated to prepopulate, but I'm unfamiliar with how the shipping calculator works. Is this true?

Based on Add a product note field in single product pages in Woocommerce answer code, I have successfully managed to achieve passing the postcode from the product page to the checkout page using the following code which allows a guest to add their postcode to the product page, and the checkout correctly shows the guest postcode with the shipping rates correctly showing:

// Add a custom product note after add to cart button in single product pages
add_action('woocommerce_after_add_to_cart_button', 'custom_field_delivery_postcode', 10 );
function custom_field_delivery_postcode() {

    woocommerce_form_field('postcode_note', array(
        'type' => 'text',
        'class' => array( 'my-field-class form-row-wide') ,
        'label' => __('Postcode') ,
        'placeholder' => __('Enter your service postcode...') ,
        'required' => true,
    ) , '');
}

// Add customer note to cart item data
add_filter( 'woocommerce_add_cart_item_data', 'add_delivery_postcode_to_cart_item_data', 20, 2 );
function add_delivery_postcode_to_cart_item_data( $cart_item_data, $product_id ){
    if( isset($_POST['postcode_note']) && ! empty($_POST['postcode_note']) ){
        $postcode_note = sanitize_textarea_field( $_POST['postcode_note'] );
        $cart_item_data['postcode_note'] = $postcode_note;
    }
    return $cart_item_data;
}

// If user not logged in, set the guest postcode, otherwise whow saved customer postcode
add_action('woocommerce_after_checkout_form','sab_guest_checkout_postcode');
function sab_guest_checkout_postcode(){

$isLoggedIn = is_user_logged_in();
if(false == $isLoggedIn){
?>
    <script type="text/javascript">
        jQuery(function($){
            $('#billing_postcode').val('<?php
                foreach( WC()->cart->get_cart() as $cart_item ){
                if( isset($cart_item['postcode_note']) )
                echo $cart_item['postcode_note'];
                } ?>'); //enter postcode here
        });
    </script>
<?php 
} 
}

While this works for the checkout page, does anyone have any knowledge of how to implement this with the cart/basket shipping calculator?

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
DSmit
  • 105
  • 13
  • Can the customer add more products to the cart with different postcodes? – Vincenzo Di Gaetano Feb 28 '21 at 10:44
  • Sorry @LoicTheAztec you're right, I should have included that. Updated. – DSmit Mar 01 '21 at 08:47
  • @VincenzoDiGaetano No, the delivery postcode will remain the same. The customer is only able to checkout one product at a time. Thank you. – DSmit Mar 01 '21 at 08:48
  • Just an observation at this point... Now that I have the code working with the checkout page, I have noticed if I go to the checkout page and back to the cart/basket, the shipping calculator has updated to show the guest postcode. – DSmit Mar 01 '21 at 11:40

1 Answers1

1

You don't need any Javascript code and neither to set that "delivery postcode" as custom cart item data. Simply use the following simplified code replacement, that will allow guests to set their "delivery postcode" from product page:

The code

// Add a custom product note after add to cart button in single product pages
add_action('woocommerce_after_add_to_cart_button', 'add_delivery_postcode_field', 10 );
function add_delivery_postcode_field() {
    if( is_user_logged_in() ) return; // Exit

    $postcode = WC()->customer->get_shipping_postcode();
    $postcode = empty($postcode) ? WC()->customer->get_billing_postcode() : $postcode;

    if ( empty($postcode) ) {
        echo '<div class="postcode-field" style="margin-top:12px;">';

        woocommerce_form_field('delivery_postcode', array(
            'type' => 'text',
            'class' => array( 'my-field-class form-row-wide') ,
            'label' => __('Postcode') ,
            'placeholder' => __('Enter your delivery postcode...') ,
            'required' => true,
        ) , '');

        echo '</div>';
    }
}

// Set submitted postcode
add_action( 'init', 'set_delivery_postcode' );
function set_delivery_postcode() {
    if( isset($_POST['delivery_postcode']) && ! empty($_POST['delivery_postcode']) ) {
        WC()->customer->set_billing_postcode( sanitize_text_field( $_POST['delivery_postcode'] ) );
        WC()->customer->set_shipping_postcode( sanitize_text_field( $_POST['delivery_postcode'] ) );
    }
}

Code goes in functions.php file of the active child theme (or active theme). Tested and works.

Note: This "delivery postcode" field is only displayed to guests. Once the "delivery postcode" has ben submitted once, the field is not displayed anymore.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Thank you, this is a much cleaner method. However there's a slight issue... I could not get this to work at first as I had 'Redirect to the basket page after successful addition' switched ON in WooCommerce. If I turn this option OFF, the code works perfectly. Can you confirm the same issue? This might be why I've been having difficulty from the start. Is there a way for this to work regardless of this option being on or off? I will have a play around with the code later today to see what I can find out. Thanks. – DSmit Mar 02 '21 at 09:56
  • 1
    Thanks. Yes, I tried this earlier this morning and found it works regardless of the redirect option. 'Init' is definitely the right way to go to avoid any issues. Thanks again for your input & support. – DSmit Mar 02 '21 at 12:05