The recursive BOGO rule will enable customers to get more value for their money by receiving an additional product at a discounted price. The code is designed to implement a “Buy N Get N/2” discount logic for the automatically added product according to the following criteria:
Buy 2 Parent Product and get 1 Free Product at a discount.
Buy 4 Parent Product and get 2 Free Product at a discount.
Buy 6 Parent Product and get 3 Free Product Price at a discount and so on.
add_action('woocommerce_cart_calculate_fees', 'ts_discount_and_free_product_based_on_quantity', 10, 1); add_action('woocommerce_before_calculate_totals', 'ts_set_free_product_price_to_zero'); function ts_discount_and_free_product_based_on_quantity($cart) { if (is_admin() && !defined('DOING_AJAX')) return; $parent_product_id = 54; $free_product_id = 917; // Get the price of the specified products $parent_product_price = wc_get_product($parent_product_id)->get_price(); $free_product_price = wc_get_product($free_product_id)->get_price(); // Initialize the discount amount based on the quantity of the parent product $parent_quantity = 0; // Check if the parent product is in the cart foreach ($cart->get_cart() as $cart_item) { if ($cart_item['product_id'] == $parent_product_id) { $parent_quantity = $cart_item['quantity']; // Check if the parent quantity is an even number (2, 4, 6, 8, ...) if ($parent_quantity % 2 == 0) { // Calculate the number of times the discount should be applied based on the parent product quantity $discount_applications = $parent_quantity / 2; // Calculate the total discounted price $discounted_price = $discount_applications * $free_product_price; // If the discount is applied, display a custom notice if ($discounted_price > 0) { wc_clear_notices(); wc_add_notice(sprintf( __("Congratulations! Buy %d, get %d free product(s).", 'your-text-domain'), $parent_quantity, $discount_applications ), 'success'); // Add a custom fee for the discounted amount $cart->add_fee(__("Discount for Free Product"), -$discounted_price, true); // Check if the free product is not already in the cart $free_product_cart_id = WC()->cart->generate_cart_id($free_product_id); $free_product_in_cart = WC()->cart->find_product_in_cart($free_product_cart_id); // If the free product is not in the cart, add it if (!$free_product_in_cart) { WC()->cart->add_to_cart($free_product_id); } } } // Adjust the price of the parent product in the cart item $cart_item['data']->set_price($parent_product_price); break; // Exit the loop after finding the parent product } } // Check if the free product is in the cart $free_product_in_cart = WC()->cart->find_product_in_cart($free_product_id); // Loop through cart items foreach ($cart->get_cart() as $cart_item) { // Check if the current item is the parent product if ($cart_item['product_id'] == $parent_product_id) { // Adjust the price of the parent product in the cart item $cart_item['data']->set_price($parent_product_price); break; // Exit the loop after finding the parent product } } // Adjust the price of the free product after subtotal calculation if ($free_product_in_cart) { foreach ($cart->get_cart() as $cart_item_key => $cart_item) { if ($cart_item['product_id'] == $free_product_id) { // Modify the item price to include the original price with strikethrough $original_price = wc_get_product($free_product_id)->get_regular_price(); $cart_item['data']->set_price($original_price); break; } } } } function ts_set_free_product_price_to_zero($cart) { if (is_admin() && !defined('DOING_AJAX')) return; $free_product_id = 917; // Loop through cart items foreach ($cart->get_cart() as $cart_item_key => $cart_item) { if ($cart_item['product_id'] == $free_product_id) { // Set the price of the free product to 0 $cart_item['data']->set_price(0); break; // Exit the loop after finding the free product } } } // Function to modify cart item price to include original price with strikethrough function ts_modify_cart_item_price($price, $cart_item, $cart_item_key) { $free_product_id = 917; // Product ID of the free product $original_price = wc_get_product($free_product_id)->get_regular_price(); if ($cart_item['product_id'] == $free_product_id) { // Modify the item price to include the original price with strikethrough $price = sprintf( '<del>%s</del> %s', wc_price($original_price), // Format the original price $price // Keep the current price ); } return $price; } add_filter('woocommerce_cart_item_price', 'ts_modify_cart_item_price', 10, 3);
Output
When the specified parent product A is added to the cart, and based on the quantity of the parent product the code provides a discount on the free product B. When there are 2 units of the parent product in the cart, the free product is automatically added to the cart with a discount equivalent to 1 unit of the free product.
Also, the user gets a notice about the discount, and if the above-mentioned conditions are met, the free product is added to the cart with the calculated discount.
Similarly, you can also implement BOGO bulk discount tiers that will tie the discounts to a quantity range. Check out here on how to add dynamic bulk WooCommerce discount tiers based on quantity.