sRos
sRos

Reputation: 1

update woocommerce cart after changing shipping method

I am currently working on an online shop with WooCommerce. I faced the problem that I want to grant a discount to customers who chose a specific shipping method. The discount is 0.50 for every single product. I basically solved this problem with the following code in my "functions.php":

add_action('woocommerce_before_calculate_totals', 'woo_add_cart_fee');

function woo_add_cart_fee() {

    global $woocommerce;
    $cart = $woocommerce->cart->get_cart();
    //Calculating Quantity
    foreach ($cart as $cart_val => $cid) {
        $qty += $cid['quantity'];
    }

    if ($woocommerce->cart->shipping_label == "specific shipping method") {
        $woo_fee = $qty * (-0.5);
        $woo_name = "discount for specific shipping method";
    }

    $woocommerce->cart->add_fee(__($woo_name, 'woocommerce'), $woo_fee, true);
}

The code technically works, the only problem I have now is that if a customer changes the shipping method i.e. from the "specific shipping method" to a "normal one" (without any discount) or the other way round, it always displays and calculates the discount value from the previously chosen shipping method. In other words it is always one step back and therefore displays the customer the wrong total amount.

Does anyone has an idea to solve this problem?

Upvotes: 0

Views: 13177

Answers (3)

mathee
mathee

Reputation: 163

Mark's answer worked for me, however I had to delete all transient values prior to running the code. Otherwise, it would simply restore the saved values.

public function clear_shipping_transients() {
  global $wpdb;

  $wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_cp_quote_%') OR `option_name` LIKE ('_transient_timeout_cp_quote_%') OR `option_name` LIKE ('_transient_wc_ship_%')" );
}

Upvotes: 0

Mark
Mark

Reputation: 229

This is very old, but I ran into this issue myself and had to work out the solution.

Woocommerce stores pre-calculated cart totals in the database, rather than calculating them on the fly. But the shipping method choice is stored as a session variable. So shipping changes are not reflected immediately at checkout without a visit or refresh of a cart page.

With the original posted code, the shipping changes were not reflected because they aren't recalculated and stored. To do this, the function needs to be tricked into thinking it's a cart page first, and then recalculating the totals to be stored.

GLOBAL $woocommerce;
if ( ! defined('WOOCOMMERCE_CART') ) {
  define( 'WOOCOMMERCE_CART', true );
}

And then at the end of the function, after all the desired changes have been made refresh and store.

WC()->cart->calculate_totals();

See also CODEX for WC_AJAX::update_shipping_method()

http://docs.woothemes.com/wc-apidocs/source-class-WC_AJAX.html#148-174

Upvotes: 0

Richard R
Richard R

Reputation: 967

This solutions is for Woocommerce 2.1.X!

I am not sure if this might help. I was facing a similar problem, where I needed to retrieve the chosen shipping method. In the file \wp-content\plugins\woocommerce\includes\wc-cart-functions.php I found a method called wc_cart_totals_shipping_html().

Within this method there is a check of the current selected shipping method that contains the following code:

$packages = WC()->shipping->get_packages();
foreach ( $packages as $i => $package ) {
    $chosen_method = isset( WC()->session->chosen_shipping_methods[ $i ] ) ? WC()->session->chosen_shipping_methods[ $i ] : '';
}

I used this code in my own functions.php to check for the currently selected shipping method and it works. Example:

add_filter( 'woocommerce_billing_fields', 'wc_change_required_fields');

function wc_change_required_fields($address_fields) {
    $packages = WC()->shipping->get_packages();
    foreach ( $packages as $i => $package ) {
        $chosen_method = isset( WC()->session->chosen_shipping_methods[ $i ] ) ? WC()->session->chosen_shipping_methods[ $i ] : '';
    }
    if ($chosen_method == 'local_delivery') {
        $address_fields['billing_address_1']['required'] = true;
        // place your changes that depend on the shipping method here...
    }
}

Hope that helps!

Upvotes: 3

Related Questions