How to Create a Flexible BOGO (Buy One Get One) Offer in WooCommerce with Code
WooCommerce is powerful, but when it comes to running dynamic promotions like Buy One Get One Free (BOGO), it requires some custom code. In this blog post, you’ll learn how to implement a flexible BOGO deal that gives customers the option to receive a free product — either the same product or a different one — when they purchase a qualifying item.
What We’ll Build
A WooCommerce feature where:
- When a customer adds a qualifying product to their cart,
- They see a prompt to choose a free product (same or from alternatives),
- Once selected, the free product is automatically added to the cart,
- The free product is labeled and excluded from normal pricing logic.
Use Case Example
Buy 1 of Product A (ID: 123
) and get one of the following free:
- Product A (same)
- Product B (ID:
456
) - Product C (ID:
789
)
Step 1: Show Free Product Options Notice
Add the following to your theme’s functions.php
file or a custom plugin.
add_action('woocommerce_before_cart', 'show_bogo_free_choice_notice');
function show_bogo_free_choice_notice() {
$trigger_product_id = 123; // Product that triggers the BOGO
$found = false;
foreach (WC()->cart->get_cart() as $item) {
if ($item['product_id'] == $trigger_product_id && empty($item['bogo_free'])) {
$found = true;
break;
}
}
if ($found && !isset($_GET['bogo-choice'])) {
$free_options = array(
123 => 'Same Product (Free)',
456 => 'Free Mug',
789 => 'Free Tote Bag'
);
$html = '<strong>Select your free product:</strong><br>';
foreach ($free_options as $pid => $label) {
$url = add_query_arg('bogo-choice', $pid);
$html .= "<a href='$url' class='button'>$label</a> ";
}
wc_print_notice($html, 'notice');
}
}
This snippet checks if the trigger product is in the cart and shows buttons to pick a free product.
Step 2: Add the Chosen Free Product to Cart
add_action('woocommerce_before_calculate_totals', 'handle_bogo_add_free_product', 10, 1);
function handle_bogo_add_free_product($cart) {
if (is_admin() && !defined('DOING_AJAX')) return;
$trigger_product_id = 123;
$choice_product_id = isset($_GET['bogo-choice']) ? intval($_GET['bogo-choice']) : 0;
$already_has_free = false;
$has_trigger = false;
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
if (!empty($cart_item['bogo_free'])) {
$already_has_free = true;
}
if ($cart_item['product_id'] == $trigger_product_id && empty($cart_item['bogo_free'])) {
$has_trigger = true;
}
}
$valid_choices = [123, 456, 789];
if ($has_trigger && !$already_has_free && in_array($choice_product_id, $valid_choices)) {
$cart->add_to_cart($choice_product_id, 1, 0, array(), array('bogo_free' => true));
wc_add_notice('Your free product has been added!', 'success');
wp_safe_redirect(wc_get_cart_url());
exit;
}
}
This code ensures that only one free product is added, and only if the trigger product is in the cart.
Step 3: Label the Free Product in Cart
add_filter('woocommerce_get_item_data', 'show_bogo_label', 10, 2);
function show_bogo_label($item_data, $cart_item) {
if (!empty($cart_item['bogo_free'])) {
$item_data[] = array(
'name' => 'Promotion',
'value' => 'Free Product (BOGO Offer)'
);
}
return $item_data;
}
This adds a label to the cart so the customer knows it’s a promotional free item.
Results
- Works with simple products (can be extended to variations).
- Customers can pick from same or alternative free products.
- Easy to maintain and modify.
Bonus Ideas
- Expand to Buy 2 Get 1 Free logic.
- Add an admin interface to define BOGO rules.
- Use a modal or dropdown for choosing free product instead of URL param.
Conclusion
With this custom code, you can run flexible BOGO promotions on your WooCommerce store without installing bloated plugins. It gives you full control over logic, styling, and scalability.
Let me know if you want this turned into a standalone plugin or extended to handle more complex conditions!
Leave a Reply