Coupon discount on product regular price (not sale price)
Asked Answered
F

2

5

In WooCommerce, I have products with a regular price of X and a sales price of Y. I would like to add a coupon with a code for a $45.00 discount to be taken from the regular price X.

I would like the coupon to disregard the sale price so I get X-$45 NOT Y-$45. But when the coupon is not applied price Y is used.

I found the following which works for percentage discounts, but I can't seem to make it work for a fixed product discount price.

add_filter('woocommerce_coupon_get_discount_amount', 'woocommerce_coupon_get_discount_amount', 10, 5 );
function woocommerce_coupon_get_discount_amount( $discount, $discounting_amount, $cart_item, $single, $coupon ) {
    if ($coupon->type == 'percent_product' || $coupon->type == 'percent') {
        global $woocommerce;
        $cart_total = 0;

        foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $cart_item ) {

         $variable_product1= new WC_Product_Variation( $cart_item["variation_id"] );

         $cart_total += $variable_product1 ->regular_price * $cart_item['quantity'];
        } 
        $discount = round( ( $cart_total / 100 ) * $coupon->amount, $woocommerce->cart->dp );
        return $discount;
    }
    return $discount;
}
Furmenty answered 12/4, 2017 at 18:20 Comment(2)
I think that code is the same of: gist.github.com/frozonfreak/1458e5a43a87812ebeab I'm reading that it has the problem of deducting the discount to the already discounted price :/Baran
The above code just returns the discount off regular price but it doesn't subtract the discount amount from regular price at checkout. So you end up giving more discount than you want.Oby
R
8

This seems to check for a coupon and then change the cart price to regular price rather than discounted price (obtained from woocommerce dynamic pricing in this application) prior to applying the coupon. placed in functions.php

add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 10, 1);
function add_custom_price( $cart_object) {

    global $woocommerce;

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

    $coupon = False;

    if ($coupons = WC()->cart->get_applied_coupons()  == False ) 
      $coupon = False;
    else {
        foreach ( WC()->cart->get_applied_coupons() as $code ) {
          $coupons1 = new WC_Coupon( $code );
          if ($coupons1->type == 'percent_product' || $coupons1->type == 'percent')
            $coupon = True;
        }
    }

    if ($coupon == True)
        foreach ( $cart_object->get_cart() as $cart_item ) 
        {
            $price = $cart_item['data']->regular_price;
            $cart_item['data']->set_price( $price );
        }
}
Residence answered 20/3, 2018 at 13:34 Comment(0)
G
2

Here's a more complete answer based on JSE's which checks if each product qualifies before reverting the price to the non-sale one. So if the coupon is restricted to particular products or cats, or is excluded from any, it will act accordingly. For coupons with no restrictions, it'll just go through the entire cart, as expected.

function regular_price_for_coupon_items($cart_object){
    if (!function_exists('WC') || !isset(WC()->cart)){
        return;
    }

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

    // Check if cart has coupon.
    if (!WC()->cart->has_discount()){
        return;
    }

    // Get coupons.
    $coupons = WC()->cart->get_applied_coupons();

    // Loop through coupons.
    foreach ($coupons as $coupon){
        // Create coupon object.
        $coupon = new WC_Coupon($coupon);

        foreach ($cart_object->get_cart() as $cart_item){
            // Check if products are not resticted from this coupon
            $included_products = true;
            $included_cats = true;

            if (count($product_ids = $coupon->get_product_ids()) > 0){
                if (!in_array($cart_item['product_id'], $product_ids, false)){
                    $included_products = false;
                }
            }
            if (count($exluded_product_ids = $coupon->get_excluded_product_ids()) > 0){
                if (in_array($cart_item['product_id'], $exluded_product_ids, false)){
                    $included_products = false;
                }
            }

            if (count($product_cats = $coupon->get_product_categories()) > 0){
                if (!has_term($product_cats, 'product_cat', $cart_item['product_id'])){
                    $included_cats = false;
                }
            }
            if (count($excluded_product_cats = $coupon->get_excluded_product_categories()) > 0){
                if (has_term($excluded_product_cats, 'product_cat', $cart_item['product_id'])){
                    $included_cats = false;
                }
            }

            if ($included_products && $included_cats){
                $price = $cart_item['data']->get_regular_price();
                $cart_item['data']->set_price($price);
            }
        }
    }
}
add_action('woocommerce_before_calculate_totals', 'regular_price_for_coupon_items', PHP_INT_MAX, 1);

If you wish to exclude a particular type of coupon, you can use $coupon->get_discount_type() in an if statement in the coupon foreach loop, right after the coupon object is instantiated, and "continue" to iterate to the next if it's not the type of coupon you wish to act on.

WooCommerce should cover the basis that this function does not. Such as having it set to a Fixed Cart Discount where there is at least one item that doesn't qualify among other scenarios based on each coupon's restrictions. If I've missed anything, please let me know!

Glisson answered 12/10, 2022 at 15:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.