Ask your WordPress questions! Pay money and get answers fast! (more info)

WooCommerce - Apply Coupon To Empty Cart

  • SOLVED

Hello

Together with a coder I'm creating a simple plugin that lets me add a coupon to any URL on my site like this mystore.com/product/?coupon=code50

Problem we have is that it's not possible to add the coupon if the cart is empty (in a fresh session).

However we have noticed that it works if you do like this:
1. Add any product to cart
2. Remove the product to cart, emptying the cart
3. Use the URL ?coupon=code50
4. Add a product to cart

(notice here that the coupon is added when the cart is empty)

So, essentially it seems like you somehow need to "open" / "activate" the cart for the coupon application to work.

One way that could possibly work is to make the plugin add a "fake" product to cart, activate the coupon and then remove the "fake" product.

That's certainly not the prettiest solution since then every site that uses this would need to create fake products with certain ID numbers etc.

Do you have any ideas for a 100% proof solution for this?


I set up a fresh woocommerce install for testing, you can try here:

http://testing.maybeauty.uk/?coupon=test50 = test50 is a test coupon
http://testing.maybeauty.uk/?product=test-buy = Test product you can add to cart

Answers (4)

2015-02-05

Kyle answers:

You may just need to set the initial cart session, try adding this to your code before your coupon codes:


if (class_exists('WC_Cart')) {
WC_Cart::set_session();
}


Kyle comments:

Also try:

if (class_exists('WC_Cart')) {
WC_Cart::maybe_set_cart_cookies();
}

2015-02-05

Reigel Gallarde answers:

you can add a filter to make the coupon always valid...

add_filter('woocommerce_coupon_is_valid','coupon_always_valid',10,1);
function coupon_always_valid($valid){
$valid = true;
// you can make conditional statement here too...
return $valid ;
}


Reigel Gallarde comments:

I forgot to mention that above function will work depending on how you put your coupon.
If you are using add_discount() then that should do the trick...

if you try to look at the source code WC_Cart class, you'll find this here...

[[LINK href="https://github.com/woothemes/woocommerce/blob/master/includes/class-wc-cart.php#L1645"]]https://github.com/woothemes/woocommerce/blob/master/includes/class-wc-cart.php#L1645[[/LINK]]

it will check if the coupon can be used with cart. And will return false if the cart is empty...

as what you can see here... in [[LINK href="https://github.com/woothemes/woocommerce/blob/7b9c226cc98ef97924cbbf2bceb5d087f8a9e704/includes/class-wc-coupon.php#L283"]]WC_Coupon[[/LINK]], you will find that function is_valid() will check if the cart is empty... sizeof( WC()->cart->get_cart() ) > 0

also, if you're going to use my above function, you will have to add other validation... just not the ones that are checking if cart is empty...

so, your code will now look something like this.. (latest woocommerce... or manipulate this if needed)

add_filter('woocommerce_coupon_is_valid','coupon_always_valid',99,2);
function coupon_always_valid($valid, $coupon){

// Usage Limit
if ( $coupon->usage_limit > 0 ) {
if ($coupon->usage_count >= $coupon->usage_limit ) {
$valid = false;
$error_code = WC_Coupon::E_WC_COUPON_USAGE_LIMIT_REACHED;
}
}

// Per user usage limit - check here if user is logged in (against user IDs)
// Checked again for emails later on in WC_Cart::check_customer_coupons()
if ( $coupon->usage_limit_per_user > 0 && is_user_logged_in() ) {
$used_by = (array) get_post_meta( $coupon->id, '_used_by' );
$usage_count = sizeof( array_keys( $used_by, get_current_user_id() ) );

if ( $usage_count >= $coupon->usage_limit_per_user ) {
$valid = false;
$error_code = WC_Coupon::E_WC_COUPON_USAGE_LIMIT_REACHED;
}
}

// Expired
if ( $coupon->expiry_date ) {
if ( current_time( 'timestamp' ) > $coupon->expiry_date ) {
$valid = false;
$error_code = WC_Coupon::E_WC_COUPON_EXPIRED;
}
}

// Minimum spend
if ( $coupon->minimum_amount > 0 ) {
if ( $coupon->minimum_amount > WC()->cart->subtotal ) {
$valid = false;
$error_code = WC_Coupon::E_WC_COUPON_MIN_SPEND_LIMIT_NOT_MET;
}
}

// Maximum spend
if ( $coupon->maximum_amount > 0 ) {
if ( $coupon->maximum_amount < WC()->cart->subtotal ) {
$valid = false;
$error_code = WC_Coupon::E_WC_COUPON_MAX_SPEND_LIMIT_MET;
}
}

// give error message...
if ( $error_code )
$coupon->error_message = $coupon->get_coupon_error( $error_code );

return $valid ;

}


Reigel Gallarde comments:

Update... I have a suggestion on how you should do the whole thing of adding coupon code via link...

forget my last suggestion cause as I think of it more, there are silent problems you might encounter... silent cause it's just there waiting for it's time to come up.

I have a better solution on how to do this....
here's the code... I put some comments for explanation...

// let's use action template_redirect cause it's the best time to capture form inputs...
add_action('template_redirect','add_coupon_code',90);
function add_coupon_code(){
// if coupon request found: (example visiting a link that has coupon param - http://testing.maybeauty.uk/?coupon=test50)
if ( ! empty( $_REQUEST['coupon'] ) ) {
// let's save this to the database for future use... you can also use session if you want...
update_option('_wc_future_coupon',sanitize_text_field( $_REQUEST['coupon'] ));
}
// now, if cart is not empty, and we have a coupon waiting on the database, apply it... otherwise, do nothing....
if ((sizeof( WC()->cart->get_cart() ) > 0) && !empty(get_option('_wc_future_coupon'))) {
// let's add the coupon to the cart
WC()->cart->add_discount( sanitize_text_field(get_option('_wc_future_coupon')));
// then let's remove the option in the database...
delete_option( '_wc_future_coupon' );
}
}

// add notices to non woocommerce pages...
add_action('loop_start','add_wc_print_notices');
function add_wc_print_notices( $query) {
if ( $query->is_main_query() ){
echo '<div class="woocommerce-page">';
wc_print_notices();
echo '</div>';
}
}

2015-02-05

Romel Apuya answers:

try making a hook to before cart..
smething like

add_action('woocommerce_before_cart','add_coupon_to_empty_cart');
function add_coupon_to_empty_cart(){
global $woocommerce;
if(isset($_GET['coupon'])){
$coupon_code = $_GET['coupon'];
}
if ( $woocommerce->cart->has_discount( $coupon_code ) ) return; //check if coupon already applied
$woocommerce->cart->add_discount( $coupon_code ); //apply coupon
$woocommerce->show_messages();
}


Romel Apuya comments:

or to the init
change

add_action('woocommerce_before_cart','add_coupon_to_empty_cart');

to

add_action( 'init', 'add_coupon_to_empty_cart' );

2015-02-05

Arnav Joy answers:

not sure this will work or not but please try this

<?php

add_action('woocommerce_before_cart_table', 'aj_apply_coupon');
function aj_apply_coupon {
global $woocommerce;


$coupon_code = $_GET['coupon'];
if (!$woocommerce->cart->add_discount( sanitize_text_field( $coupon_code ))) {
$woocommerce->show_messages();
}

}