I trying to pass a variable in woocommerce_cart_calculate_fees hook, but this code doesn't work. When I try to pass static value within a variable it works.

Here is my code:

add_action('woocommerce_cart_calculate_fees' , 'add_custom_fees', 20, 1);function add_custom_fees( WC_Cart $cart){$final_discount; // storing ajax value$static_value=5; // static valueif ($final_discount) {/*** custom discount for the cart in woocommerce*/// Hook before calculate feesadd_action('woocommerce_cart_calculate_fees', 'add_custom_fees');/*** Add custom fee if more than three article* @param WC_Cart $cart*/function add_custom_fees(WC_Cart $cart) {// Calculate the amount to reduceglobal $final_discount;$discount=$cart->subtotal * $final_discount / 100;$cart->add_fee('10% discount has been added.', -$discount);}}}


Now I am to pass a WC_Session value in woocommerce_cart_calculate_fees hook, the code works but session variable does not update before page refreshing.

The session variable is storing from onchange ajax value of billing_postcode field of woocommerce checkout page.

My jQuery code (Ajax):

jQuery(document).ready(function () {jQuery('#billing_postcode').on('change', function (event) {//alert( this.value );event.preventDefault();var billing_postcode=jQuery('#billing_postcode').val();console.log(billing_postcode);var data={action: 'woocommerce_apply_state',security: wc_checkout_params.apply_state_nonce,billing_postcode: billing_postcode};jQuery.ajax({type: "POST",data: data,url: wc_checkout_params.ajax_url,success: function (code) {console.log(code);if (code==='0') {jQuery('body').trigger('update_checkout');}},dataType: 'html'});});});

My PHP code in functions.php file of my theme:

wp_enqueue_script('zip_code', get_template_directory_uri() . '/assets/js/zipcode.js', array('jquery'));wp_localize_script('zip_code', 'wc_checkout_params', array('ajaxurl'=> admin_url(http://stackoverflow.com/'admin-ajax.php')));add_action('wp_ajax_woocommerce_apply_state', 'discount', 10);add_action('wp_ajax_nopriv_woocommerce_apply_state', 'discount', 10);function discount() {if(isset($_POST['billing_postcode'])){$billing_postcode=isset($_POST['billing_postcode'])?$_POST['billing_postcode']:'not yet';global $wpdb;$zipcodes=$wpdb->get_results( $wpdb->prepare( "SELECT * FROM wp_zip_codes_value WHERE zip_code_value=%d", $billing_postcode) );$zip_for_discount=array();foreach ( $zipcodes as $zipcode ){$zip_for_discount=$zipcode->zip_code_id;}$find_discount=$wpdb->get_results( $wpdb->prepare( "SELECT * FROM wp_zip_codes WHERE zip_code=%d", $zip_for_discount) );$final_discount=array();if($find_discount){foreach ( $find_discount as $discount ){$final_discount[]=$discount->discount;}}$final_discount[0];WC()->session->set( 'final_discount', $final_discount[0] );}}add_action('woocommerce_cart_calculate_fees' , 'add_custom_fees', 20, 1);function add_custom_fees( WC_Cart $cart){if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;$percent=WC()->session->get( 'final_discount' );if( $percent > 0 ){$discount=$cart->subtotal * $percent / 100;$cart->add_fee( __('Zip Code Discount', 'woocommerce' ) . " ($percent%)", -$discount);}}

    The best way to get that working is to set your $final_discount variable using WC_Sessions in another function before, this way:

    WC()->session->set( 'final_discount', $final_discount );

    Now you can get this value anywhere on front end hooks or code using:

    $final_discount=WC()->session->get( 'final_discount' );

    So your final discount (negative fee) code will be something like:

    add_action('woocommerce_cart_calculate_fees', 'add_custom_fee', 20, 1 );function add_custom_fee( $cart ){if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;// Get the data from WC_Sessions$percent=WC()->session->get( 'final_discount' );if( $percent > 0 ){$discount=$cart->subtotal * $percent / 100;$cart->add_fee( __('Discount', 'woocommerce' ) . " ($percent%)" . $percent, -$discount);}}

    Code goes in function.php file of your active child theme (active theme).

    Tested and works.

    Update regarding your updated question:

    Here is a working Ajax example code similar to yours but simplified (as I don't have similar database custom tables to get the percentage for the discount).

    The variable discount percentage is based on the imputed zip-code value…

    The PHP code:

    add_action( 'wp_enqueue_scripts', 'wc_zipcode_enqueue_scripts' );function wc_zipcode_enqueue_scripts() {// Only on front-end and checkout pageif( is_admin() || ! is_checkout() ) return;// (For child themes use get_stylesheet_directory_uri() instead)wp_enqueue_script('zip_code', get_template_directory_uri() . '/assets/js/zipcode.js', array('jquery'));wp_localize_script('zip_code', 'wc_checkout_params', array('ajaxurl'=> admin_url(http://stackoverflow.com/'admin-ajax.php')));}add_action('wp_ajax_woocommerce_apply_state', 'woocommerce_apply_state', 10 );add_action('wp_ajax_nopriv_woocommerce_apply_state', 'woocommerce_apply_state', 10 );function woocommerce_apply_state() {global $wpdb;if( isset($_POST['billing_postcode']) ){$billing_postcode=$_POST['billing_postcode'];if( empty($billing_postcode) || $billing_postcode==0 ) die();if( $billing_postcode < 30000 )$final_discount=10;elseif( $billing_postcode >=30000 && $billing_postcode < 60000 )$final_discount=15;else$final_discount=20;WC()->session->set( 'final_discount', $final_discount );echo json_encode( WC()->session->get('final_discount' ) );}die(); // Alway at the end (to avoid server error 500)}add_action('woocommerce_cart_calculate_fees' , 'add_custom_discount', 20, 1);function add_custom_discount( WC_Cart $cart){if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;// Get the data from WC_Sessions$percent=WC()->session->get( 'final_discount' );// If the billing postcode is not set we exit$billing_postcode=WC()->session->get('customer')['postcode'];if( empty($billing_postcode) ) return;if( $percent > 0 ){$discount=$cart->subtotal * $percent / 100;$cart->add_fee( __('Zip Code Discount', 'woocommerce' ) . " ($percent%)", -$discount);}}

    Code goes in function.php file of your active child theme (active theme).

    The javascript code:

    jQuery(document).ready(function($) {function postcodeAjax(){$.ajax({type: 'POST',dataType: 'json'data: {action: 'woocommerce_apply_state',billing_postcode: $('#billing_postcode').val(),security: wc_checkout_params.apply_state_nonce},url: wc_checkout_params.ajax_url,success: function (response) {$('body').trigger('update_checkout');console.log('response');}});}if( $('#billing_postcode').val() > 0 )postcodeAjax();$('#billing_postcode').on('change blur', function(e){e.preventDefault();postcodeAjax();$('body').trigger('update_checkout');});});

    To be saved in a file named zipcode.js located in your theme folder /assets/js/zipcode.js

    Tested and perfectly works

    • thanks. :) your code is working fine, but a little bit problem. Discounted value does not update before page refreshing, show discounted value after page refreshing. Will be session unset? How and where?– rafiq islamFeb 14 at 16:59
    • OK thanks. Now i edited my question with details code. Would you please check?– rafiq islamFeb 20 at 16:09
    • @rafiqislam Update after my original answer…– LoicTheAztecFeb 21 at 9:32

    Your Answer


    By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

    Not the answer you're looking for? Browse other questions tagged or ask your own question.