Question

In Woocommerce I'm trying to find a way to apply a 10% discount to an entire customer's order if the weight in the cart is over 100 lbs. I'm partway to achieving this. For the next step, I'm looking for a way to programmatically apply a coupon code via action/hook through functions.php.

It appears that I can use the function woocommerce_ajax_apply_coupon to do this ( http://docs.woothemes.com/wc-apidocs/function-woocommerce_ajax_apply_coupon.html ) but I am unsure of how to use it.

So far I've modified cart.php to get the total weight of all the products in the cart, I've created a coupon that applies the discount (if entered manually) and I've added some code to functions.php to check the weight and display a message to the user.

EDIT: Partial code removed, completed code included in the solution below.


Thanks for the guidance Freney. Here's the working end result which successfully applies the discount coupon when the condition is met and also removes it when it's no longer met:

/* Mod: 10% Discount for weight greater than 100 lbs 
Works with code added to child theme: woocommerce/cart/cart.php lines 13 - 14: which gets $total_weight of cart:
        global $total_weight;
        $total_weight = $woocommerce->cart->cart_contents_weight;
*/
add_action('woocommerce_before_cart_table', 'discount_when_weight_greater_than_100');
function discount_when_weight_greater_than_100( ) {
    global $woocommerce;
    global $total_weight;
    if( $total_weight > 100 ) {
        $coupon_code = '999';
        if (!$woocommerce->cart->add_discount( sanitize_text_field( $coupon_code ))) {
            $woocommerce->show_messages();
        }
        echo '<div class="woocommerce_message"><strong>Your order is over 100 lbs so a 10% Discount has been Applied!</strong> Your total order weight is <strong>' . $total_weight . '</strong> lbs.</div>';
    }
}

/* Mod: Remove 10% Discount for weight less than or equal to 100 lbs */
add_action('woocommerce_before_cart_table', 'remove_coupon_if_weight_100_or_less');
function remove_coupon_if_weight_100_or_less( ) {
    global $woocommerce;
    global $total_weight;
    if( $total_weight <= 100 ) {
        $coupon_code = '999';
        $woocommerce->cart->get_applied_coupons();
        if (!$woocommerce->cart->remove_coupons( sanitize_text_field( $coupon_code ))) {
            $woocommerce->show_messages();
        }
        $woocommerce->cart->calculate_totals();
    }
}
Was it helpful?

Solution

First, create a discount coupon (via http://docs.woothemes.com/document/create-a-coupon-programatically/):

$coupon_code = 'UNIQUECODE'; // Code - perhaps generate this from the user ID + the order ID
$amount = '10'; // Amount
$discount_type = 'percent'; // Type: fixed_cart, percent, fixed_product, percent_product

$coupon = array(
    'post_title' => $coupon_code,
    'post_content' => '',
    'post_status' => 'publish',
    'post_author' => 1,
    'post_type'     => 'shop_coupon'
);    

$new_coupon_id = wp_insert_post( $coupon );

// Add meta
update_post_meta( $new_coupon_id, 'discount_type', $discount_type );
update_post_meta( $new_coupon_id, 'coupon_amount', $amount );
update_post_meta( $new_coupon_id, 'individual_use', 'no' );
update_post_meta( $new_coupon_id, 'product_ids', '' );
update_post_meta( $new_coupon_id, 'exclude_product_ids', '' );
update_post_meta( $new_coupon_id, 'usage_limit', '1' );
update_post_meta( $new_coupon_id, 'expiry_date', '' );
update_post_meta( $new_coupon_id, 'apply_before_tax', 'yes' );
update_post_meta( $new_coupon_id, 'free_shipping', 'no' );

Then apply that coupon to your order:

if (!$woocommerce->cart->add_discount( sanitize_text_field( $coupon_code )))
    $woocommerce->show_messages();

That last function returns a BOOL value: TRUE if the discount was successful, FALSE if it fails for any one of a variety of reasons.

OTHER TIPS

I used this solution, but it contains a bug as the OP wrote it. If the user skips previewing the cart and goes straight to the checkout form, it does not apply the coupon. Here was my solution.

// Independence day 2013 coupon auto add
// Add coupon when user views cart before checkout (shipping calculation page).
add_action('woocommerce_before_cart_table', 'add_independence_day_2013_coupon_automatically');

// Add coupon when user views checkout page (would not be added otherwise, unless user views cart first).
add_action('woocommerce_before_checkout_form', 'add_independence_day_2013_coupon_automatically');

// Check if php function exists.  If it doesn't, create it.
if (!function_exists('add_independence_day_2013_coupon_automatically')) {

    function add_independence_day_2013_coupon_automatically() {

        global $woocommerce;
        $coupon_code = 'independencedaysale';
        $bc_coupon_start_date = '2013-06-30 17:00:00';
        $bc_coupon_end_date = '2013-07-08 06:59:59';

        // Only apply coupon between 12:00am on 7/1/2013 and 11:59pm on 7/7/2013 PST.
        if ((time() >= strtotime($bc_coupon_start_date)) &&
            (time() <= strtotime($bc_coupon_end_date))) {

            // If coupon has been already been added remove it.
            if ($woocommerce->cart->has_discount(sanitize_text_field($coupon_code))) {

                if (!$woocommerce->cart->remove_coupons(sanitize_text_field($coupon_code))) {

                    $woocommerce->show_messages();

                }

            }

            // Add coupon
            if (!$woocommerce->cart->add_discount(sanitize_text_field($coupon_code))) {

                $woocommerce->show_messages();

            } else {

                $woocommerce->clear_messages();
                $woocommerce->add_message('Independence day sale coupon (10%) automatically applied');
                $woocommerce->show_messages();

            }

            // Manually recalculate totals.  If you do not do this, a refresh is required before user will see updated totals when discount is removed.
            $woocommerce->cart->calculate_totals();

        } else {

            // Coupon is no longer valid, based on date.  Remove it.
            if ($woocommerce->cart->has_discount(sanitize_text_field($coupon_code))) {

                if ($woocommerce->cart->remove_coupons(sanitize_text_field($coupon_code))) {

                    $woocommerce->show_messages();

                }

                // Manually recalculate totals.  If you do not do this, a refresh is required before user will see updated totals when discount is removed.
                $woocommerce->cart->calculate_totals();

            }

        }

    }

}

2017 / 2019 since Woocommerce 3

The following compact code in one hooked function will add a discount (coupon) based on cart total weight displaying a custom message. If customer changes cart items the code will check cart items removing the discount (coupon) if the cart weight is under the defined weight.

The code:

add_action('woocommerce_before_calculate_totals', 'discount_based_on_weight_threshold');
function discount_based_on_weight_threshold( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;

    // Your settings
    $coupon_code      = 'onweight10'; // Coupon code
    $weight_threshold = 100; // Total weight threshold

    // Initializing variables
    $total_weight     = $cart->get_cart_contents_weight();
    $applied_coupons  = $cart->get_applied_coupons();
    $coupon_code      = sanitize_text_field( $coupon_code );

    // Applying coupon
    if( ! in_array($coupon_code, $applied_coupons) && $total_weight >= $weight_threshold ){
        $cart->add_discount( $coupon_code );
        wc_clear_notices();
        wc_add_notice( sprintf(
            __("Your order is over %s so a %s Discount has been Applied! Your total order weight is %s.", "woocommerce"),
            wc_format_weight( $weight_threshold ), '10%', '<strong>' . wc_format_weight( $total_weight ) . '</strong>'
        ), "notice");
    }
    // Removing coupon
    elseif( in_array($coupon_code, $applied_coupons) && $total_weight < $weight_threshold ){
        $cart->remove_coupon( $coupon_code );
    }
}

Code goes in function.php file of your active child theme (or active theme). Tested and works.

enter image description here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top