-2

Thanks to @Bhautik for helping to correct some functions to auto-generate WooCommerce coupons when applied with a URL. Post is here - How to auto generate a coupon in WooCommerce and apply it to the cart?

I'm now trying to add a free product to this same function. I've kinda got it working but with errors. If anyone could chip in with some advice or help would be greatly appreciated. Please see screenshots below. Thanks in advance.

https://i.stack.imgur.com/Muwdn.gif

https://i.stack.imgur.com/3F9GW.gif

https://i.stack.imgur.com/m9mXF.gif

Here's my code so far.

function coupon_exists( $coupon_code ) {
    global $wpdb;
    $sql = $wpdb->prepare( "SELECT post_name FROM $wpdb->posts WHERE post_type = 'shop_coupon' AND post_name = '%s'", $coupon_code );
    $coupon_codes = $wpdb->get_results($sql);

    if ( count( $coupon_codes ) > 0 ) {
        return true;
    } else {
        return false;
    }
}
// Generate coupon
function generate_coupon($coupon_generated) {
    
    // Set some coupon data by default
    $date_expires     = date('Y-m-d H:i:s', strtotime('+24 hours'));
    $discount_type    = 'percent';
    $coupon_amount    = '100';

    $coupon = new WC_Coupon();
    $coupon->set_code($coupon_generated);
    $coupon->set_discount_type($discount_type);
    $coupon->set_amount($coupon_amount);
    $coupon->set_date_expires($date_expires);
    $coupon->set_individual_use(true);
    $coupon->set_product_ids (array(74)); 
    $coupon->set_usage_limit(1);    
    $coupon->set_limit_usage_to_x_items(1);
    $coupon->set_usage_limit_per_user(1);
    $coupon->set_exclude_sale_items(true);
    $coupon->set_minimum_amount('100');
    $coupon->set_maximum_amount('150');

    $coupon->save();

    return $coupon_generated;
}

// Add coupon and product to cart
function generate_coupon_add_product_to_cart ( $cart ) {
    
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;
    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;
    
    $coupon_code = ( isset( $_GET['coupon-code'] ) && $_GET['coupon-code'] != '' ) ? $_GET['coupon-code'] : '' ;

    if( $coupon_code == '' ){
        return;
    }

    $applied_coupons = $cart->get_applied_coupons();

    if( empty( $applied_coupons ) || ! in_array( $coupon_code, $applied_coupons ) ){
        if ( !coupon_exists( $coupon_code ) ) {
            generate_coupon( $coupon_code );
        } 
    } 
    
    // I'm having trouble with the code below this point
    $free_product_id  = 74;
    $free_product_in_cart = false;
    
    foreach( $cart->get_cart() as $cart_item_key => $cart_item ) {
        $cart_count = $cart->get_cart_contents_count();
        $free_product = $cart_item['data'];
     if ( $free_product->get_id() == $free_product_id ) {
        $free_product_key = $cart_item_key; 
        $regular_price = $cart_item['data']->get_regular_price();
        $cart_item['data']->set_price(0);

        $free_product_in_cart = true;  
      } 
    }

    if ( !in_array($coupon_code, $applied_coupons) && !$free_product_in_cart ){
        $cart->add_to_cart( $free_product_id, 1 );
        $cart->add_discount( $coupon_code );
        wc_add_notice( sprintf(__('<strong>FREE</strong> product valued at %s has been added to your cart.', 'woocommerce'),'<strong>' . get_woocommerce_currency_symbol() . $regular_price . '</strong>'), 'notice');
    }
    // Removing coupon
    elseif( !in_array($coupon_code, $applied_coupons) && $free_product_in_cart ){
        $cart->remove_coupon( $coupon_code );
        wc_add_notice( __("Coupon removed"), 'notice' );
    }
    // Removing free product if it is the only one left in cart
    elseif ( $free_product_in_cart && $cart_count <= 1 ){
        $cart->remove_cart_item( $free_product_key );
        wc_add_notice( __("Product removed"), 'notice' );
    }
}
add_action('woocommerce_before_calculate_totals', 'generate_coupon_add_product_to_cart');```
Stoto
  • 41
  • 1
  • 8

1 Answers1

0

I have got this working now but only by adding the product via the URL, I couldn't get it working correctly by adding the product with PHP. So now both the product and coupon are added with this method.

www.mytheme.com/cart/?add-to-cart=74&coupon-code=mycoupon

After checking this answer, I have created a new user session but have not unset it as the price was not displaying correctly when going to the checkout page.

GET a coupon code via URL and apply it in WooCommerce Checkout page

I have added the coupon with the ‘woocommerce_before_cart_table’ hook and have used the ‘woocommerce_before_calculate_totals’ hook for the price display and banner.

The code now generates a new coupon in WooCommerce with a 24hr expiry based on the URL input, adds a free product to the cart, and sets the price displayed as ‘FREE’. The mini cart is not reflecting the free product price but will do so if the mini cart is edited. From what I could gather this seems to have been a bug for quite a while.

I’m not very familiar with PHP so if anyone has any suggestions to improve this, feel free to chip in. Thanks

    // Check if coupon exists
function coupon_exists( $coupon_code ) {
    global $wpdb;

    $sql = $wpdb->prepare( "SELECT post_name FROM $wpdb->posts WHERE post_type = 'shop_coupon' AND post_name = '%s'", $coupon_code );

    $coupon_codes = $wpdb->get_results($sql);

    if ( count( $coupon_codes ) > 0 ) {
        return true;
    } else {
        return false;
    }
}
// Generate coupon
function generate_coupon($coupon_generated) {
    
    // Set some coupon data by default
    $date_expires     = date('Y-m-d H:i:s', strtotime('+24 hours'));
    $discount_type    = 'percent'; // 'store_credit' doesn't exist
    $coupon_amount    = '100';

    $coupon = new WC_Coupon();
    $coupon->set_code($coupon_generated);
    $coupon->set_discount_type($discount_type);
    $coupon->set_amount($coupon_amount);
    $coupon->set_date_expires($date_expires);
    $coupon->set_individual_use(true);
    $coupon->set_product_ids (array(74)); 
    $coupon->set_usage_limit(1);    
    $coupon->set_limit_usage_to_x_items(1);
    $coupon->set_usage_limit_per_user(1);
    $coupon->set_exclude_sale_items(true);
    $coupon->set_minimum_amount('100');
    //$coupon->set_maximum_amount('150');

    $coupon->save();

    return $coupon_generated;
}

// Generate coupon and set session
function ts_get_custom_coupon_code_to_session() {
    if( isset( $_GET[ 'coupon-code' ] ) ) {
        // Ensure that customer session is started
        if( !WC()->session->has_session() )
            WC()->session->set_customer_session_cookie(true);
        
    $coupon_code = ( isset( $_GET['coupon-code'] ) && $_GET['coupon-code'] != '' ) ? $_GET['coupon-code'] : '' ;
    
    if( $coupon_code == '' ){
        return;
    }
    if( empty( $applied_coupons ) || ! in_array( $coupon_code, $applied_coupons ) ){
        if ( !coupon_exists( $coupon_code ) ) {
            generate_coupon( $coupon_code );
        } 
    }   
        // Check and register coupon code in a custom session variable
        $coupon_code = WC()->session->get( 'coupon-code' );
        if( empty( $coupon_code ) && isset( $_GET[ 'coupon-code' ] ) ) {
            $coupon_code = esc_attr( $_GET[ 'coupon-code' ] );
            WC()->session->set( 'coupon-code', $coupon_code ); // Set the coupon code in session
        }
    }
}
add_action( 'init', 'ts_get_custom_coupon_code_to_session' );

// Apply the coupon to the cart
function ts_apply_discount_to_cart() {
    // Set coupon code
    $coupon_code      = WC()->session->get( 'coupon-code' );
    $applied_coupons  = WC()->session->get('applied_coupons');

    $free_product_id  = 74;
    $minimum_amount   = 100;
    
    foreach( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
        $cart_subtotal += $cart_item['line_total'] + $cart_item['line_tax'];
        $free_product = $cart_item['data']->get_id();
    } 
    
    if ( ! empty( $coupon_code ) && ! WC()->cart->has_discount($coupon_code) && $free_product == $free_product_id && $cart_subtotal >= $minimum_amount){
        WC()->cart->apply_coupon( $coupon_code ); // apply the coupon discount
        //WC()->session->__unset( 'coupon-code' ); // remove coupon code from session - have disabled this as it caused the price of the free prouct to display as full on the ckecout page
    }
}
add_action( 'woocommerce_before_cart_table', 'ts_apply_discount_to_cart', 10, 0 );


// Change cart items prices (and order items prices)
function set_free_prod_cart_item_prices ( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;
    
    $coupon_code      = WC()->session->get( 'coupon-code' );
    $applied_coupons  = WC()->session->get('applied_coupons');
    
    $free_product_id  = 74;
    $minimum_amount   = 100;
    
    foreach( $cart->get_cart() as $cart_item_key => $cart_item ) {      
        $free_product = $cart_item['data']->get_id();
        $regular_price = $cart_item['data']->get_regular_price();
        $prod_name = $cart_item ['data']->post->post_title;
        $cart_subtotal += $cart_item['line_total'] + $cart_item['line_tax'];
     if ( $applied_coupons = $coupon_code && $free_product == $free_product_id && $cart_item['quantity'] == 1 && $cart_subtotal >= $minimum_amount ) {
        $cart_item['data']->set_price(0); // Set free product price to zero
      }
    elseif ( $free_product == $free_product_id && $cart_item['quantity'] > 2 || !$cart->has_discount()) {
        $cart_item['data']->get_regular_price();
        } 
    }
    if ($applied_coupons = $coupon_code && $free_product == $free_product_id && is_cart() && $cart_subtotal >= $minimum_amount ) {
        wc_add_notice( sprintf(__('<strong>FREE</strong> %s valued at %s has been added to your cart.', 'woocommerce'), $prod_name,'<strong>' . get_woocommerce_currency_symbol() . $regular_price . '</strong>'), 'notice');
    }
}
add_action('woocommerce_before_calculate_totals', 'set_free_prod_cart_item_prices', 100, 1 );

// Change price display from $0.00 to FREE
function filter_cart_item_price( $price, $cart_item, $cart_item_key ) {
    $free_product_id  = 74;
    
    if ( $cart_item[ 'data' ]->price == 0 && $cart_item['data']->get_id() == $free_product_id ) {
        $price = __( 'FREE', 'textdomain' );
    }
    return $price;
}
add_filter( 'woocommerce_cart_item_price', 'filter_cart_item_price', 10, 3 );

// Prevent page refresh for adding item to cart using add-to-cart url
function resolve_dupes_add_to_cart_redirect($url = false) {
  if(!empty($url)) { 
  return $url; 
  }
  return get_home_url() .add_query_arg(array(), remove_query_arg('add-to-cart'));
}
add_action('woocommerce_add_to_cart_redirect', 'resolve_dupes_add_to_cart_redirect');

// Remonve redirect to cart banner on cart and checkout pages
function misha_remove_add_to_cart_message( $message ){
    if( is_cart() || is_checkout() ) {
    return '';
        }
}
add_filter( 'wc_add_to_cart_message_html', 'misha_remove_add_to_cart_message' );
Stoto
  • 41
  • 1
  • 8