Search code examples
phpwordpresswoocommerceproductcart

How do I make two products with different product IDs act as one on WooCommerce cart page (BOGO)


I am running a BOGO on one item. The problem with this is when you increase the quantity of bought item, the given free item quantity doesnt increase with it.

How can we make them act as one like so that both the items have same quantity?

I am trying to make changes to this code so that it does the job.

add_action( 'template_redirect', 'bbloomer_add_gift_if_id_in_cart' );
 
function bbloomer_add_gift_if_id_in_cart() {
 
   if ( is_admin() ) return;
   if ( WC()->cart->is_empty() ) return;
 
   $product_bought_id = 874;
   $product_gifted_id = 870;
 
   // see if product id in cart
   $product_bought_cart_id = WC()->cart->generate_cart_id( $product_bought_id );
   $product_bought_in_cart = WC()->cart->find_product_in_cart( $product_bought_cart_id );
 
   // see if gift id in cart
   $product_gifted_cart_id = WC()->cart->generate_cart_id( $product_gifted_id );
   $product_gifted_in_cart = WC()->cart->find_product_in_cart( $product_gifted_cart_id );
 
   // if not in cart remove gift, else add gift
   if ( ! $product_bought_in_cart ) {
      if ( $product_gifted_in_cart ) WC()->cart->remove_cart_item( $product_gifted_in_cart );
   } else {
      if ( ! $product_gifted_in_cart ) WC()->cart->add_to_cart( $product_gifted_id );
   }
}

Solution

  • The code you are using is will not work if the customer removes the gifted product ID. In this case, the gifted product will be deleted after the page has been reloaded.

    So woocommerce_before_calculate_totals is recommended over template_redirect

    My answer contains:

    • When the purchased product is added with a certain amount, the same amount of gift product is added to cart
    • When the quantity of one product is updated on the shop page, the quantity will change with the other product, this through jQuery
    • Optional 2 extra codes that can be useful throughout the operation of the gift product
    • Comment with explanation added to the code tags

    Than you get:

    function action_woocommerce_before_calculate_totals( $cart ) {  
        if ( is_admin() && ! defined( 'DOING_AJAX' ) )
            return;
    
        if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
            return;
        
        // SETTINGS
        $product_bought_id = 30;
        $product_gifted_id = 815;
        // END SETTINGS
        
        // Flags
        $product_bought_in_cart = false;
        $gifted_key = false;
        
        // Loop trough
        foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
            // Product ID in cart
            $product_id_in_cart = $cart_item['product_id'];
            
            // Check if product bought is in cart
            if ( $product_id_in_cart == $product_bought_id  ) {
                // True
                $product_bought_in_cart = true;
                
                // Product quantity in cart
                $product_bought_in_cart_quantity = $cart_item['quantity'];
            }
            
            // Check if product gifted is in cart
            if ( $product_id_in_cart == $product_gifted_id  ) {
                // Set gifted key (true)
                $gifted_key = $cart_item_key;
            }
        }
    
       // If product bought is false & gifted key is true
       if ( ! $product_bought_in_cart && $gifted_key ) {
           $cart->remove_cart_item( $gifted_key );
        // If product bought in true & gifted key is false
        } elseif ( $product_bought_in_cart && ! $gifted_key ) {
            $cart->add_to_cart( $product_gifted_id, $product_bought_in_cart_quantity );
        // If product bought in true & gifted key is true
        } elseif ( $product_bought_in_cart && $gifted_key ) {
            $cart->set_quantity( $gifted_key, $product_bought_in_cart_quantity );
        }
    }
    add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
    

    jQuery part, ensures that the quantity fields are adjusted simultaneously

    jquery_video

    function action_wp_footer() {
        // SETTINGS
        $product_bought_id = 30;
        $product_gifted_id = 815;
        // END SETTINGS
        
        // See if product id in cart
        $product_bought_cart_id = WC()->cart->generate_cart_id( $product_bought_id );
        $product_bought_in_cart = WC()->cart->find_product_in_cart( $product_bought_cart_id );
    
        // See if gift id in cart
        $product_gifted_cart_id = WC()->cart->generate_cart_id( $product_gifted_id );
        $product_gifted_in_cart = WC()->cart->find_product_in_cart( $product_gifted_cart_id );
        
        // Both true
        if ( $product_bought_in_cart && $product_gifted_in_cart ) {
            ?>
            <script>
                jQuery(function($) {
                    // Selectors
                    var product_bought_in_cart_selector = $( "input[name*='<?php echo $product_bought_in_cart; ?>']" );
                    var product_gifted_in_cart_selector = $( "input[name*='<?php echo $product_gifted_in_cart; ?>']" );
                    
                    // When 1 of the 2 quantity fields are updated, these values ​​change similarly
                    $( product_bought_in_cart_selector ).change(function() {
                        var product_bought_in_cart_selector_quantity = $( this ).val();
                        
                        $( product_gifted_in_cart_selector ).val( product_bought_in_cart_selector_quantity );
                    });
                    
                    $( product_gifted_in_cart_selector ).change(function() {
                        var product_gifted_in_cart_selector_quantity = $( this ).val();
                        
                        $( product_bought_in_cart_selector ).val( product_gifted_in_cart_selector_quantity );
                    });
                });
            </script>
            <?php
        }
    }
    add_action( 'wp_footer', 'action_wp_footer');
    

    Optional 1: A warning that the gift product cannot be purchased separately

    function filter_woocommerce_add_to_cart_validation( $passed, $product_id, $quantity, $variation_id = null, $variations = null ) {
        // SETTINGS
        $product_gifted_id = 815;
    
        // True
        if ( $product_gifted_id == $product_id ) {
            // Add notice    
            wc_add_notice( __( 'This is a gift item and cannot be purchased separately', 'woocommerce' ), 'error' );
    
            // NOT passed
            $passed = false;
        }
    
        return $passed;
    }
    add_filter( 'woocommerce_add_to_cart_validation', 'filter_woocommerce_add_to_cart_validation', 10, 5 );
    

    Optional 2: Ensures that the gift product is not individually removable in the shopping cart

    function filter_woocommerce_cart_item_remove_link( $link, $cart_item_key ) {
        // SETTINGS
        $product_gifted_id = 815;
        
        // Cart id
        $product_cart_id = WC()->cart->generate_cart_id( $product_gifted_id );
    
        // Find product in cart
        $in_cart_key = WC()->cart->find_product_in_cart( $product_cart_id );
        
        // True
        if ( $in_cart_key == $cart_item_key ) {
            $link = '';
        }
    
        return $link;
    }
    add_filter( 'woocommerce_cart_item_remove_link', 'filter_woocommerce_cart_item_remove_link', 10, 2 );
    

    Optional 3: Make sure that the order cannot be fulfilled if the quantity of both products is not equal

    function action_woocommerce_check_cart_items() {
        // SETTINGS
        $product_bought_id = 30;
        $product_gifted_id = 815;
        // END SETTINGS
    
        // Loop though cart items searching for the defined product
        foreach( WC()->cart->get_cart() as $cart_item ) {
            // Product id
            $product_id = $cart_item['product_id'];
    
            if ( $product_bought_id == $product_id ) {
                $product_bought_quantity = $cart_item['quantity'];
                $product_bought_name = $cart_item['data']->get_name();
            }
            
            if ( $product_gifted_id = $product_id ) {
                $product_gifted_quantity = $cart_item['quantity'];
                $product_gifted_name = $cart_item['data']->get_name();
            }
        }
    
        // Isset & NOT equal
        if( isset ( $product_bought_quantity ) && isset ( $product_gifted_quantity ) && $product_bought_quantity != $product_gifted_quantity  ) {
            wc_add_notice( sprintf(
                __( 'The quantity of %s and %s must be equal before you can continue', 'woocommerce' ),
                $product_bought_name,
                $product_gifted_name,
            ), 'error' );
            
            // Removing the proceed button, until the condition is met
            // optional
            remove_action( 'woocommerce_proceed_to_checkout','woocommerce_button_proceed_to_checkout', 20);
        }
    }
    add_action( 'woocommerce_check_cart_items', 'action_woocommerce_check_cart_items', 10, 0 );