1
votes

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?

1
Can the customer add more products to the cart with different postcodes?Vincenzo Di Gaetano
Sorry @LoicTheAztec you're right, I should have included that. Updated.David Smith
@VincenzoDiGaetano No, the delivery postcode will remain the same. The customer is only able to checkout one product at a time. Thank you.David Smith
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.David Smith

1 Answers

1
votes

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.