phpwordpresswoocommerceproductdiscount

Discount product price, auto add free product for specific user role in WooCommerce


I have a WordPress site where I have a "Premium" user role. I want all users with this role to get a 10% discount on Wall pictures and free candles. I want the discounted price to be displayed in both the shop page, and cart/checkout.

I am far from an expert in PHP, but here is my attempt.
My code does not seem to work properly. For example, the free products are not added to the cart.

Is there anyone who can help me resolve this?

Thank you so much for your help :)

function apply_discounts_based_on_user_role_and_product_type( $cart ) {
    if ( is_user_logged_in() ) {
        $user_roles = wp_get_current_user()->roles;

        foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
            if ( $cart_item['data']->get_name() === 'Wall Picture' ) {
                if ( in_array( 'premium', $user_roles ) ) {
                    $discount = $cart_item['data']->get_price() * 0.1;
                    $cart->add_fee( 'Premium Discount', -$discount, true );
                }
            } elseif ( $cart_item['data']->get_name() === 'Candle' ) {
                if ( in_array( 'premium', $user_roles ) ) {
                    $cart->remove_cart_item( $cart_item_key );
                }
            }
        }
    }
}
add_action( 'woocommerce_cart_calculate_fees', 'apply_discounts_based_on_user_role_and_product_type' );

function update_product_price_based_on_user_role( $price, $product ) {
    if ( is_user_logged_in() ) {
        $user_roles = wp_get_current_user()->roles;

        if ( $product->get_name() === 'Wall Picture' ) {
            if ( in_array( 'premium', $user_roles ) ) {
                $discounted_price = $product->get_price() * 0.9;
                return wc_price( $discounted_price );
            }
        } elseif ( $product->get_name() === 'Candle' ) {
            if ( in_array( 'premium', $user_roles ) ) {
                return __('Free', 'text-domain');
            }
        }
    }

    return $price;
}
add_filter( 'woocommerce_get_price_html', 'update_product_price_based_on_user_role', 10, 2 );

Solution

  • Note that all Fees are only displayed in cart and checkout pages, but it's not possible technically to display them in the products (shop, product archives, single products or mini-cart).

    So it's better to change the product price in cart (to discount the price) and to display it as discounted everywhere else (shop, single product, cart, mini cart and checkout). For the free product that is auto added, we display "Free" and set the price to zero.

    In the first function, you need to define the product to be discounted and the free product by their IDs (but not by their names).

    The code:

    // HERE set the related product IDs (settings)
    function discounted_products_settings() {
        return array(
            'free_product_id'     => 26, // HERE set the free product ID
            'targeted_product_id' => 18, // HERE set the targeted product ID to discount
        );
    }
    
    // Display discounted product price in shop and single product.
    add_filter( 'woocommerce_get_price_html', 'user_role_product_price_html', 20, 2 );
    function user_role_product_price_html( $price_html, $product ) {
        global $current_user;
    
        // Targeting user role
        if ( ! in_array( 'administrator', $current_user->roles ) ) return $price_html;
        //if ( ! in_array( 'premium', $current_user->roles ) ) return $price_html;
    
        extract(discounted_products_settings()); // Load the product IDs (settings)
    
        if( $product->get_id() == $targeted_product_id ) {
            $regular_price    = wc_get_price_to_display( $product, array('price' => $product->get_regular_price()) );
            $discounted_price = wc_get_price_to_display( $product, array('price' => $product->get_regular_price() * 0.9) );
    
            return wc_format_sale_price( $regular_price, $discounted_price ) . $product->get_price_suffix();
        }
        return $price_html;
    }
    
    // Cart and mini cart displayed price html
    add_filter( 'woocommerce_cart_item_price', 'display_cart_item_price_html', 20, 2 );
    function display_cart_item_price_html( $price_html, $cart_item ) {
        global $current_user;
    
        // Targeting user role
        if ( ! in_array( 'administrator', $current_user->roles ) ) return $price_html;
        //if ( ! in_array( 'premium', $current_user->roles ) ) return $price_html;
    
        extract(discounted_products_settings()); // Load the product IDs (settings)
    
        $product = wc_get_product($cart_item['product_id']); // Get the product Object from the ID
    
        if( $targeted_product_id == $cart_item['product_id'] ) {
            $args  = array( 'price' => $product->get_regular_price() ); 
            $args2 = array( 'price' => $product->get_regular_price() * 0.9 ); // Set discounted price calculation
    
            if ( WC()->cart->display_prices_including_tax() ) {
                $regular_price    = wc_get_price_including_tax( $product, $args );
                $discounted_price = wc_get_price_including_tax( $product, $args2 );
            } else {
                $regular_price    = wc_get_price_excluding_tax( $product, $args );
                $discounted_price = wc_get_price_excluding_tax( $product, $args2 );
            }
            return wc_format_sale_price( $regular_price, $discounted_price );
        }
        elseif ( $free_product_id == $cart_item['product_id'] ) {
            return esc_html__('Free', 'text-domain');
        }
        return $price_html;
    }
    
    // Cart and Checkout displayed product subtotal html
    add_filter( 'woocommerce_cart_item_subtotal', 'display_cart_item_subtotal_html', 10, 2 ); 
    function display_cart_item_subtotal_html( $item_subtotal_html, $cart_item ) { 
        global $current_user;
    
        // Targeting user role
        if ( ! in_array( 'administrator', $current_user->roles ) ) return $price_html;
        //if ( ! in_array( 'premium', $current_user->roles ) ) return $price_html;
    
        extract(discounted_products_settings()); // Load the product IDs (settings)
    
        if( $targeted_product_id == $cart_item['product_id'] ) {
            $product = wc_get_product($cart_item['product_id']); // Get the product Object from the ID
            $args    = array( 'price' => $product->get_regular_price() );
    
            if ( WC()->cart->display_prices_including_tax() ) {
                $regular_price       = wc_get_price_including_tax( $product, $args );
                $regular_subtotal    = $regular_price * $cart_item['quantity'];
                $discounted_subtotal = $cart_item['line_subtotal'] * $cart_item['line_subtotal_tax'];
            } else {
                $regular_price       = wc_get_price_excluding_tax( $product, $args );
                $regular_subtotal    = $regular_price * $cart_item['quantity'];
                $discounted_subtotal = $cart_item['line_subtotal'];
            }
            return wc_format_sale_price( $regular_subtotal, $discounted_subtotal );
        }
        return $item_subtotal_html;
    }
    
    // Set cart item prices, and auto add the free product
    add_action( 'woocommerce_before_calculate_totals', 'user_role_add_free_product' );
    function user_role_add_free_product( $cart ) {
        if ( is_admin() && ! defined( 'DOING_AJAX' ) )
            return;
    
        global $current_user;
    
        // Targeting user role
        if ( ! in_array( 'administrator', $current_user->roles ) ) return;
        //if ( ! in_array( 'premium', $current_user->roles ) ) return;
            
        extract(discounted_products_settings()); // Load the product IDs (settings)
    
        $discount_enabled = $free_product_key = false; // Initializing variables
        
        foreach ( $cart->get_cart() as $item_key => $item ) {
            $product = wc_get_product($item['product_id']); // Get the product Object from the ID
    
            if ( $targeted_product_id == $item['product_id'] ) {
                $price = $product->get_regular_price() * 0.9; // calculate the price
                $item['data']->set_price($price); // Set the discounted price
                $discount_enabled = true;
            } 
            elseif ( $item['product_id'] == $free_product_id ) {
                $item['data']->set_price(0); // Set the price to zero
                // Adjust free product quantity if needed
                if ( $item['quantity'] > 1 ) {
                    $cart->set_quantity( $item_key, 1 ); 
                }
                $free_product_key = $item_key;
            }
        }
    
        if ( $discount_enabled && ! $free_product_key ) {
            // add free product when discounted product is in cart
            $cart->add_to_cart( $free_product_id, 1 ); 
        }
        elseif ( ! $discount_enabled && $free_product_key ) {
            // remove free product when discounted product is not anymore in cart
            $cart->remove_cart_item( $free_product_key ); 
        }
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). Tested and works.