MAD MAD - 25 days ago 8
PHP Question

Calculate distance via Google API and show it to Woocommerce cart

So, I have written a piece of code after getting some help from SO and internet. I want to add a fees to the cart by calculating the distance between the vendor's location (

billing_city
) and customer's area via
Google Maps API Distance-Matrix
. Here, I use a dropdown after billing form to get the area of customer.

I am having problem of getting the value from cookies and pass the variable to next function. FYKI, I have inserted this code into my child theme functions.

add_action( 'wp_footer', 'calculate_distance_between_two_locations' );
function calculate_distance_between_two_locations($dist) {

// I am getting first item of the cart
foreach( WC()->cart->get_cart() as $cart_item ){
$product_id = $cart_item['product_id'];
break;
}

//Now I am fetching vendor's id and location of the item
$vendor_id = get_post_field( 'post_author', $product_id );
$vendor_location = get_user_meta($vendor_id, 'billing_city', true);

//Here I'm fetching the value from customer location
//I am using a dropdown/select named billing_myfield5
if (is_checkout()) {?>
<script type="text/javascript">
jQuery( document ).ready(function( $ ) {
$('#billing_myfield5').change(function(){
jQuery('body').trigger('update_checkout');
var location = $('#billing_myfield5 option:selected').text();
document.cookie="cusarea="+location;
});
});
</script>
<?php
}

//Encoding the customer's location for Google API
//and putting it into a variable
$customer_area = rawurlencode($_COOKIE ['cusarea']);

//I am setting Google API
$shippingurl = "https://maps.googleapis.com/maps/api/distancematrix/json?origins=".$vendor_location."&destinations=".$customer_area."&key=MY_API_KEY";

//Now fetching json response from googleapis.com:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $shippingurl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = json_decode(curl_exec($ch), true);
//If google responds with a status of OK
//Extract the distance text:
if($response['status'] == "OK"){
$dist = $response['rows'][0]['elements'][0]['distance']['text'];
}

//Getting the integers from the string
$dist_ance = preg_replace("/[^0-9\.]/", '', $dist);

//Finally putting the value in session
session_start();
$_SESSION['dist'] = $dist_ance;
}


So, now I should have a value in
$_SESSION['dist']
and I should be able to pass it to another function in same page. Here's the code I am using to calculate the cart fees.

add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
function woo_add_cart_fee( $cart ){

if ( ! $_POST || ( is_admin() && ! is_ajax() ) ) {
return;
}

if($_SESSION['dist']){
$customshipcost = $dist_ance;
if ( is_admin() && ! defined ( 'DOING_AJAX' ))
WC()->cart->add_fee('Distance Delivery Charge', $customshipcost , true);
}
}


Well, I am having two problems actually. Any help would be really appreciated.


  • Sometimes I get the value from cookie, sometimes I don't. I use echo
    to check whether it's giving me the value or not.

  • The session is not responding. I get a '0' as fees in my cart.



FYKI, I am just trying to show only numerical distance as fees in cart right now.

Answer Source

Here is the correct way to get the selected location value in the woocommerce_cart_calculate_fees action hook. I have moved all php code in this hooked function.

In a custom function hooked in woocommerce_after_checkout_form action hook, I have added your revised jQuery code.

I have test everything (but not the google API part and the distance calculation fee) and it works live: Each time a value is selected, it is updated in the fee function.

Here is the code:

add_action( 'woocommerce_after_checkout_form', 'custom_checkout_jquery_script', 10 );
function custom_checkout_jquery_script() {
    // Setting the country in customer data and session
    $country_code = 'BD'; // For Bangladesh
    WC()->session->set( 'country', $country_code );
    WC()->session->set( 'billing_country', $country_code );
    WC()->session->set( 'shipping_country', $country_code );
    WC()->customer->set_billing_country( $country_code );
    WC()->customer->set_shipping_country( $country_code );

    // The jQuery code
    ?>
    <script type="text/javascript">
        (function($){
            // Initializing (get the default value)
            var location = $('#billing_myfield5 option:selected').html();
            document.cookie="cusarea="+location;
            // To test the default location output in browser console dev tools
            console.log('Selected Area: '+location);

            // Get the live value when selected
            $( 'form.checkout' ).on( 'change', '#billing_myfield5', function(){
                location = $('#billing_myfield5 option:selected').html();
                document.cookie="cusarea="+location;
                $('body').trigger('update_checkout');
                // To test the selected location output in browser console dev tools
                console.log('Selected Area: '+location);
            });
        })(jQuery);
    </script>
    <?php
}

add_action( 'woocommerce_cart_calculate_fees', 'distance_shipping_fee', 10, 1 );
function distance_shipping_fee( $wc_cart ){

    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;

    if( empty($_COOKIE ['cusarea']) ) return; // Waiting for the selected area (cookie)
    else $cookie = $_COOKIE ['cusarea'];

    // Encoding the customer's location for Google API
    $customer_area = rawurlencode( $cookie );

    // I am getting first item of the cart
    foreach( $wc_cart->get_cart() as $cart_item ){
        $product_id = $cart_item['product_id'];
        break;
    }

    // Get the vendor's id and location
    $vendor_id = get_post_field( 'post_author', $product_id );
    $vendor_location = get_user_meta($vendor_id, 'billing_city', true);

    // Setting Google API URL ##
    $gapi_key = "MY_API_KEY"; // Set HERE your google api key
    $shippingurl = "https://maps.googleapis.com/maps/api/distancematrix/json?origins=$vendor_location";
    $shippingurl .= "&destinations=$customer_area&key=$gapi_key";

    // Now fetching json response from googleapis:
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $shippingurl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $response = json_decode(curl_exec($ch), true);

    // If google responds with a status of OK: Extract the distance text:
    if($response['status'] == "OK")
        $dist = $response['rows'][0]['elements'][0]['distance']['text'];

    // Getting the integers from the string
    $distance = preg_replace("/[^0-9\.]/", '', $dist);

    if( $distance > 0 ){
        $customshipcost = $distance;
        // Displaying the selected location in the fee label
        $wc_cart->add_fee( "Distance Delivery fee ($cookie)", $customshipcost , true);
    }
}

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

All code is tested on Woocommerce 3+ and works.

This will solve your coockie and session problem