Search code examples
phpwordpressrandomwoocommercecoupon

Applying conditionally a generated coupon on WooCommerce add to cart


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 );
}

Solution

  • 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+