skip to Main Content

I’ve been trying to update the manual shipping value in the order review table in the checkout page, when user a click a button in the billing details section that I have already created. I used a manual test value in this case. But the order review table isn’t updating that value in the order review table.

Updated
I declared a test value and assigned to the shipping label, and I’ve got that updated value through the Ajax response. But the order review table shipping value is not getting updated. (please see the PHP code)

PHP

<?php
/*
Plugin Name: Change Shipping Value
Description: Customizations for WooCommerce.
Version: 1.0
Author: udd_ish
*/

function enqueue_custom_scripts() {
    // Enqueue the custom JS file
    wp_enqueue_script('jquery');
    wp_enqueue_script('distancecal-scripts', plugin_dir_url(__FILE__) . 'js/distancecal-scripts.js', array('jquery'), '1.0', true);
    wp_localize_script('distancecal-scripts', 'ajax_object', array('ajaxurl' => admin_url('admin-ajax.php')));
}

add_action('wp_enqueue_scripts', 'enqueue_custom_scripts');

// Add a button after the billing form in WooCommerce checkout
add_action('woocommerce_after_checkout_billing_form', 'add_custom_button_after_billing_form');

function add_custom_button_after_billing_form() {
    include_once(plugin_dir_path(__FILE__) . 'distancecal.php'); // Include PHP functions file
    ?>
    <div id="custom-button-wrapper">
        <button type="button" id="custom-button" class="button alt">Calculate Delivery Fee</button>
    </div>
<?php
}


function modify_shipping_cost($shipping_cost) {
    if ( isset($shipping_cost) ){
        WC()->session->set('shipping_cost', $shipping_cost);
        return $shipping_cost;
    }
}


add_filter( 'woocommerce_package_rates', 'shipping_package_rates_filter_callback', 100, 2 );
function shipping_package_rates_filter_callback( $rates, $package ) {
    // The defined rate id
    $shipping_rate_id = 'flat_rate:4'; //Use your own shipping method id

    $tax_rate = 0.1; // 10%

    if( isset(WC()->session->get('shipping_cost') ) ) {
        $shipping_cost = WC()->session->get('shipping_cost' );
        $rates = array( $shipping_rate_id => $rates[ $shipping_rate_id ] );
        // Set rate cost
        $rates[$shipping_rate_id ]->cost = $shipping_cost;
        // Set taxes rate cost (if enabled)
        $taxes = array();
        foreach ($rates[$shipping_rate_id ]->taxes as $key => $tax){
            if( $rates[$shipping_rate_id ]->taxes[$key] > 0 )
                $taxes[$key] = $shipping_cost * $tax_rate;
        }
        $rates[$shipping_rate_id ]->taxes = $taxes;
    } else {
        unset( $rates[ $shipping_rate_id ] );
    }

    return $rates;
}


// AJAX handler for updating checkout
add_action('wp_ajax_update_checkout', 'update_checkout_callback');

function update_checkout_callback() {

    $testvalue = 100;

    // Update the shipping cost with the new test value
    $newvalue = modify_shipping_cost($testvalue);
    
    wp_send_json(array('updated_fee' => $newvalue));
    
    // Make sure to exit after handling the AJAX request
    wp_die();

} ?>

JS

jQuery(document).ready(function($) {
    // Add your custom JavaScript here
    $('#custom-button').on('click', function() {
        var streetAddress = $('#billing_address_1').val();
        $.ajax({
            type: 'POST',
            url: ajax_object.ajaxurl,
            data: {
                action: 'update_checkout',
                street_address: streetAddress
            },
            success: function(response) {
                console.log(response);
                $('body').trigger('update_checkout', { update_shipping_method: true });
                
            },
            error: function(error) {
                // Handle AJAX error if needed
                console.error('AJAX error:', error);
            }
        });
    });
});

2

Answers


  1. I recently created a custom checkout process that had to draw shipping costs from a separate database.

    It uses the existing shipping methods in woocommerce and just adjusted their rates, meaning you don’t have to hide the existing shipping label.

    I have adjusted your code to use the same method I used.

    function modify_shipping_cost($shipping_cost) {
        if ( isset($shipping_cost) ){
            WC()->session->set('shipping_cost', $shipping_cost);
            return $shipping_cost;
        }
    }
    
    add_filter( 'woocommerce_package_rates', 'shipping_package_rates_filter_callback', 100, 2 );
    function shipping_package_rates_filter_callback( $rates, $package ) {
        // The defined rate id
        $shipping_rate_id = 'flat_rate:31'; //Use your own shipping method id
    
        $tax_rate = 0.1; // 10%
    
        if( isset(WC()->session->get('shipping_cost') ) ) {
            $shipping_cost = WC()->session->get('shipping_cost' );
            $rates = array( $shipping_rate_id => $rates[ $shipping_rate_id ] );
            // Set rate cost
            $rates[$shipping_rate_id ]->cost = $shipping_cost;
            // Set taxes rate cost (if enabled)
            $taxes = array();
            foreach ($rates[$shipping_rate_id ]->taxes as $key => $tax){
                if( $rates[$shipping_rate_id ]->taxes[$key] > 0 )
                    $taxes[$key] = $shipping_cost * $tax_rate;
            }
            $rates[$shipping_rate_id ]->taxes = $taxes;
        } else {
            unset( $rates[ $shipping_rate_id ] );
        }
    
        return $rates;
    }
    
    add_action('wp_ajax_update_checkout', 'update_checkout_callback');
    function update_checkout_callback() {
    
        $testvalue = 100;
        
        // Update the shipping cost with the new test value
        $newvalue = modify_shipping_cost($testvalue);
        
        wp_send_json(array('updated_fee' => $newvalue));
    
        // Make sure to exit after handling the AJAX request
        wp_die();
    
    }
    

    Your existing JS code should work fine.

    You can find your shipping method id from 2 methods:

    Method 1
    If your shipping method is a Flat Rate method, you can inspect the ‘Edit’ button and just change the id number in the code to match.
    Get Flat Rate shipping method ID

    Method 2
    At checkout, you can inspect the shipping method and then the value of the element is the full shipping method id, so in this instance you will need to replace ‘flat_rate:31’ with ‘local_pickup:28’
    Get all shipping method ID

    Login or Signup to reply.
  2. There are multiple mistakes and missing things in your codeā€¦

    I have commented/disabled the following code line, as you don’t provide distancecal.php file:

    // include_once(plugin_dir_path(__FILE__) . 'distancecal.php'); // Include PHP functions file
    

    Also, you should not use WooCommerce existing Ajax actions, so I changed your action name from update_checkoutto shipping_cost_update.

    Then there was some missing mandatory hooked functions (see this thread)

    Try the following revised main php code:

    <?php
    /**
     * Plugin Name: Woo Custom Shipping Value (Test)
     * Description: Customizations for WooCommerce.
     * Version: 1.0
     * Author: udd_ish
    **/
    
    defined( 'ABSPATH' ) or exit;
    
    add_action('wp_enqueue_scripts', 'enqueue_custom_scripts');
    function enqueue_custom_scripts() {
        // Enqueue the custom JS file
        wp_enqueue_script('jquery');
        wp_enqueue_script('distancecal-scripts', plugin_dir_url(__FILE__) . 'js/distancecal-scripts.js', array('jquery'), '1.0', true);
        wp_localize_script('distancecal-scripts', 'ajax_object', array('ajaxurl' => admin_url('admin-ajax.php')));
    }
    
    function modify_shipping_cost($shipping_cost) {
        if ( isset($shipping_cost) ){
            WC()->session->set('shipping_cost', $shipping_cost);
        }
        return $shipping_cost;
    }
    
    // Add a button after the billing form in WooCommerce checkout
    add_action('woocommerce_after_checkout_billing_form', 'add_custom_button_after_billing_form');
    function add_custom_button_after_billing_form() {
        // include_once(plugin_dir_path(__FILE__) . 'distancecal.php'); // Include PHP functions file
        ?>
        <div id="custom-button-wrapper">
            <button type="button" id="custom-button" class="button alt"><?php _e('Calculate Delivery Fee'); ?></button>
        </div>
    <?php
    }
    
    add_filter( 'woocommerce_package_rates', 'shipping_package_rates_filter_callback', 100, 2 );
    function shipping_package_rates_filter_callback( $rates, $package ) {
        // HERE define your targeted rate id
        $targeted_rate_id = 'flat_rate:4'; 
        
        if ( ! array_key_exists($targeted_rate_id, $rates) ) 
            return $rates;
    
        $new_cost = WC()->session->get('shipping_cost'); // Get new cost from WC sessions
    
        if ( ! empty($new_cost) ) {
            // (optional) Customize the shipping method label name when the new cost is set
            $rates[$targeted_rate_id]->label = __('New name', 'woocommerce'); // Set the new name
    
            $rate = $rates[$targeted_rate_id];
            $cost = $rate->cost; // Set the initial cost in a variable for taxes calculations
            $rates[$targeted_rate_id]->cost = $new_cost; // Set the new cost
    
            $has_taxes = false; // Initializing
            $taxes     = array(); // Initializing
            foreach ($rate->taxes as $key => $tax_cost){
                if( $tax_cost > 0 ) {
                    $tax_rate    = $tax_cost / $cost; // Get the tax rate conversion
                    $taxes[$key] = $new_cost * $tax_rate; // Set the new tax cost in taxes costs array
                    $has_taxes   = true; // There are taxes (set it to true)
                }
            }
            if( $has_taxes ) {
                $rates[$targeted_rate_id]->taxes = $taxes; // Set taxes costs array
            }
        } else {
            unset($rates[$targeted_rate_id]);
        }
        return $rates;
    }
    
    
    // PHP WP AJAX handler
    add_action('wp_ajax_shipping_cost_update', 'shipping_cost_update_callback');
    add_action('wp_ajax_nopriv_shipping_cost_update', 'shipping_cost_update_callback');
    function shipping_cost_update_callback() {
        $test_value = 100;
    
        wp_send_json( array( 'updated_shipping_cost' => modify_shipping_cost($test_value) ) );
        wp_die(); // Make sure to exit after handling the AJAX request
    }
    

    And for distancecal-scripts.js JavaScript file:

    jQuery( function($) {
        // Add your custom JavaScript here
        $(document.body).on('click', '#custom-button', function() {
            const streetAddress = $('#billing_address_1').val();
    
            if ( $('#billing_address_1').val() !== '' ) {
                $.ajax({
                    type: 'POST',
                    url: ajax_object.ajaxurl,
                    data: {
                        action: 'shipping_cost_update',
                        street_address: streetAddress
                    },
                    success: function(response) {
                        console.log(response);
                        $(document.body).trigger('update_checkout', { update_shipping_method: true });
                        
                    },
                    error: function(error) {
                        // Handle AJAX error if needed
                        console.error('AJAX error:', error);
                    }
                });
            }
        });
    });
    

    PHP: Missing mandatory code (Refresh shipping methods cache):

    // Refresh shipping methods
    add_action('woocommerce_checkout_update_order_review', 'checkout_update_refresh_shipping_methods' );
    function checkout_update_refresh_shipping_methods() {
        if ( WC()->session->__isset('shipping_cost') ) {
            $packages = WC()->cart->get_shipping_packages();
            foreach ($packages as $package_key => $package ) {
                 WC()->session->set( 'shipping_for_package_' . $package_key, false );
            }
        }
    }
    
    // Remove the WC session variable once the order is created
    add_action('woocommerce_checkout_order_created', 'remove_wc_session_shipping_cost_variable', 10, 1);
    function remove_wc_session_shipping_cost_variable( ) {
        if ( WC()->session->__isset('shipping_cost') ) {
            WC()->session->__unset('shipping_cost');
        }
    }
    

    Add the code (both functions) to your main plugin file.

    Optional code: Reset/remove the WC Session variable if customer goes other pages.

    // (optional) Remove the WC Session variable on other pages than checkout
    add_action('template_redirect', 'wc_session_shipping_cost_variable_only_on_checkout', 10, 1);
    function wc_session_shipping_cost_variable_only_on_checkout() {
        if ( ! ( is_checkout() && ! is_wc_endpoint_url() ) ) {
            remove_wc_session_shipping_cost_variable();
    
            $packages = WC()->cart->get_shipping_packages();
            foreach ($packages as $package_key => $package ) {
                 WC()->session->set( 'shipping_for_package_' . $package_key, false );
            }
        }
    }
    

    Add optionally this code functions to your main plugin file.

    Tested and works, Updating the shipping cost.

    Important note: Don’t forget to empty your cart to refresh shipping method caches on first start.


    Related:

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search