1

I'm currently using Gravity Forms (with referral as lead enabled). I'm using a hook on submit to generate a random coupon based off of a coupon template (in my functions.php). My goal is to then have that coupon automatically applied to their order at the checkout page. I'm successfully able to generate the coupon, but can't quite figure out how to apply it. FYI- I do not use a cart in the user experience, so Product Page > Checkout.

If someone could provide some help, or point me in the right direction, I'd be grateful.

// Generate Random Coupon  
function after_submission () {
$coupon_code = substr( "abcdefghijklmnopqrstuvwxyz123456789", mt_rand(0, 50) , 1) .substr( md5( time() ), 1); // Code
$coupon_code = substr( $coupon_code, 0,10); // create 10 letters coupon
$amount = '0'; // Amount
$discount_type = 'free_shipping'; // Type: fixed_cart, percent, fixed_product, percent_product

$coupon = array(
    'post_title' => $coupon_code,
    'post_content' => 'Free Shipping & Handling',
    'post_excerpt' => 'Free Shipping & Handling',
    'post_status' => 'publish',
    'post_author' => 1,
    'post_type'     => 'shop_coupon'
);

$new_coupon_id = wp_insert_post( $coupon );

// Add meta
update_post_meta( $new_coupon_id, 'discount_type', $discount_type );
update_post_meta( $new_coupon_id, 'coupon_amount', $amount );
update_post_meta( $new_coupon_id, 'individual_use', 'yes' );
update_post_meta( $new_coupon_id, 'product_ids', '' );
update_post_meta( $new_coupon_id, 'exclude_product_ids', '' );
update_post_meta( $new_coupon_id, 'usage_limit', '1' );
update_post_meta( $new_coupon_id, 'expiry_date', '' );
update_post_meta( $new_coupon_id, 'apply_before_tax', 'no' );
update_post_meta( $new_coupon_id, 'free_shipping', 'no' );
update_post_meta( $new_coupon_id, 'exclude_sale_items', 'no' );
update_post_meta( $new_coupon_id, 'free_shipping', 'yes' );
update_post_meta( $new_coupon_id, 'product_categories', '' );
update_post_meta( $new_coupon_id, 'exclude_product_categories', '' );
update_post_meta( $new_coupon_id, 'minimum_amount', '' );
update_post_meta( $new_coupon_id, 'customer_email', '' );       

return $coupon_code;

}

// Gravity Forms Referral 
add_action( 'gform_after_submission_9', 'after_submission', 10, 2 );


// Add generated coupon to cart 
add_action( 'woocommerce_add_to_cart', 'apply_matched_coupons' );

function apply_matched_coupons() {
     if ( is_cart() || is_checkout() ) return;
     if ( WC()->cart->has_discount( $coupon_code ) ) return;
     WC()->checkout->add_discount( $coupon_code );
}
LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399

1 Answers1

2

You need to set in a WC session variable the created coupon code. Then you will be able to get it easely.

Since WooCommerce 3, your code is a bit obsolete, with mistakes. Try the following instead:

// Early enable customer WC_Session
add_action( 'init', 'wc_session_enabler' );
function wc_session_enabler() {
    if ( is_user_logged_in() || is_admin() ) 
        return; 
        
    if ( isset(WC()->session) && ! WC()->session->has_session() ) { 
        WC()->session->set_customer_session_cookie( true ); 
    } 
}

// Utility function that generate a non existing coupon code (as each coupon code required to be unique)
function generated_counpon_code() {
    for ( $i = 0; $i < 1; $i++ ) {
        $coupon_code = strtolower( wp_generate_password( 10, false ) );

        // Check that the generated code doesn't exist yet
        if( coupon_exists( $coupon_code ) ) $i--; // continue
        else break; // Stop the loopp
    }
    return $coupon_code;
}

function coupon_exists( $coupon_code ) {
    global $wpdb;
    return $wpdb->get_var( $wpdb->prepare("SELECT COUNT(ID) FROM $wpdb->posts
        WHERE post_type = 'shop_coupon' AND post_name = '%s'", $coupon_code));
}

// Generate coupon and set code in customer WC session variable
function after_submission () {
    // Get a random unique coupon code
    $coupon_code = generated_counpon_code();

    // Get an empty instance of the WC_Coupon Object
    $coupon = new WC_Coupon();

    $coupon->set_code( $coupon_code );
    $coupon->set_status( 'publish' );
    $coupon->set_discount_type( 'fixed_cart' );
    $coupon->set_description( __('Free Shipping & Handling') );
    $coupon->set_amount( 0 );
    $coupon->set_usage_limit( 1 );
    $coupon->set_free_shipping( 1 ); // <== Added back
    $coupon->set_individual_use( 1 );

    // Save coupon (data)
    $coupon->save();

    WC()->session->set( 'unique_coupon', $coupon_code );
}

// Gravity Forms Referral (hook)
add_action( 'gform_after_submission_9', 'after_submission', 10, 2 );


// Add generated coupon to cart
add_action( 'woocommerce_add_to_cart', 'apply_matched_coupons' );
function apply_matched_coupons() {
    if ( is_cart() || is_checkout() ) return;

    // Load coupon code
    $coupon_code = WC()->session->get( 'unique_coupon' );

    if ( $coupon_code && ! WC()->cart->has_discount( $coupon_code ) ) {
        WC()->cart->apply_coupon( $coupon_code ); // Apply coupon code
        WC()->session->__unset( 'unique_coupon' ); // remove session variable 
    }
}

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


Documentation: WC_Coupon Class available setter and getter methods

Related: Create multiple coupons programmatically in WooCommerce 3+

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Confirming it works! Thank you very much. The one thing I noticed is I've lost the "free shipping" - I added update meta per below but didn't seem to work. update_post_meta( $coupon_code, 'free_shipping', 'yes' ); – Matt Melton Aug 04 '20 at 17:29
  • Works perfect. Thank you kind sir! – Matt Melton Aug 04 '20 at 20:22
  • I've discovered the code snippet to 'Early enable customer WC_Session' when enabled, disables the REST API. Any idea why this would happen, and how to fix? – Matt Melton Aug 17 '20 at 23:31
  • @MattMelton No sorry no idea, I don't use so much rest API… You should try to ask on WooCommerce support pages, or open a new thread. – LoicTheAztec Aug 17 '20 at 23:53
  • A little googling found me the answer... I had to change the Early enable customer WC_Session to the following, and now REST works, as does your code: ` // Early enable customer WC_Session add_action( 'init', 'force_non_logged_user_wc_session' ); function force_non_logged_user_wc_session() { if (is_user_logged_in() || is_admin()) return; if (isset(WC()->session)) { if (!WC()->session->has_session()) { WC()->session->set_customer_session_cookie(true); } } } ` (Sorry- new to StackO, having trouble formatting code in the comment) – Matt Melton Aug 19 '20 at 00:48