12

I am trying to check if a coupon is still valid (hasn't reached its usage limit) and display content under this condition.

The reason for this is that I want to be able to hand out a coupon code to particular visitors, but obviously don't want to hand out a coupon that has already reached it's usage limit.

I am trying to achieve this with PHP and imagine the code to be something like this:

<?php if (coupon('mycouponcode') isvalid) {
  echo "Coupon Valid"
} else {
  echo "Coupon Usage Limit Reached"
} ?>

Any help here would be great :)

Raunak Gupta
  • 10,412
  • 3
  • 58
  • 97
NuclearApe
  • 573
  • 2
  • 6
  • 16

3 Answers3

18

I believe the recommended way encouraged by WooCommerce is to use the \WC_Discounts Class. Here is an example:

function is_coupon_valid( $coupon_code ) {
    $coupon = new \WC_Coupon( $coupon_code );   
    $discounts = new \WC_Discounts( WC()->cart );
    $response = $discounts->is_coupon_valid( $coupon );
    return is_wp_error( $response ) ? false : true;     
}

Note: It's also possible to initialize the WC_Discounts class with a WC_Order object as well.

It's important to remember doing that inside the wp_loaded hook at least, like this:

add_action( 'wp_loaded', function(){
   is_coupon_valid('my-coupon-code');
});

There is an apparent simpler method is_valid() from the WC_Coupon class but it was deprecated in favor of WC_Discounts->is_coupon_valid()

$coupon = new WC_Coupon( 'my-coupon-code' );
$coupon->is_valid();
Pablo S G Pacheco
  • 2,550
  • 28
  • 28
7
$code = 'test123';

$coupon = new WC_Coupon($code);
$coupon_post = get_post($coupon->id);
$coupon_data = array(
    'id' => $coupon->id,
    'code' => $coupon->code,
    'type' => $coupon->type,
    'created_at' => $coupon_post->post_date_gmt,
    'updated_at' => $coupon_post->post_modified_gmt,
    'amount' => wc_format_decimal($coupon->coupon_amount, 2),
    'individual_use' => ( 'yes' === $coupon->individual_use ),
    'product_ids' => array_map('absint', (array) $coupon->product_ids),
    'exclude_product_ids' => array_map('absint', (array) $coupon->exclude_product_ids),
    'usage_limit' => (!empty($coupon->usage_limit) ) ? $coupon->usage_limit : null,
    'usage_count' => (int) $coupon->usage_count,
    'expiry_date' => (!empty($coupon->expiry_date) ) ? date('Y-m-d', $coupon->expiry_date) : null,
    'enable_free_shipping' => $coupon->enable_free_shipping(),
    'product_category_ids' => array_map('absint', (array) $coupon->product_categories),
    'exclude_product_category_ids' => array_map('absint', (array) $coupon->exclude_product_categories),
    'exclude_sale_items' => $coupon->exclude_sale_items(),
    'minimum_amount' => wc_format_decimal($coupon->minimum_amount, 2),
    'maximum_amount' => wc_format_decimal($coupon->maximum_amount, 2),
    'customer_emails' => $coupon->customer_email,
    'description' => $coupon_post->post_excerpt,
);

$usage_left = $coupon_data['usage_limit'] - $coupon_data['usage_count'];

if ($usage_left > 0) {
    echo 'Coupon Valid';
} 
else {
    echo 'Coupon Usage Limit Reached';
}

The code is tested and fully functional.

Reference

NuclearApe
  • 573
  • 2
  • 6
  • 16
Raunak Gupta
  • 10,412
  • 3
  • 58
  • 97
  • This is always returning "Coupon Usage Limit Reached". I have replaced test123 with numerous coupons (valid, expired, used up, uses left etc.) but no joy :( – NuclearApe Sep 28 '16 at 12:41
  • @NuclearApe: with any valid coupon print `$coupon_data['usage_limit']`, `$coupon_data['usage_count']` and `$coupon_data['expiry_date']` and see what they are returning. – Raunak Gupta Sep 28 '16 at 12:52
  • Just for info: There is 2 related methods for WC_Coupon class ( `is_valid()` and `is_valid_for_cart()` ). **But unfortunately they doesn't work...** There is a **bug** as they **always return false**. So I have posted a thread in WordPress > Woocommerce support threads: https://wordpress.org/support/topic/wc_coupon-is_valid-method-always-return-false/ – LoicTheAztec Sep 28 '16 at 13:08
  • @LoicTheAztec: Yes I have seen those two method but i guess `is_valid_for_cart()` is for current cart item. but my above custom code is working perfectly, as coupon is stored in `wp_posts` table and all the meta in `wp_postmeta` so I did some random test with few coupon and for this question only this to meta_key are needed `usage_count` and `expiry_date`. – Raunak Gupta Sep 28 '16 at 13:24
  • I have test before something similar to you. But I have tried to use this 2 methods, and I have search a lot. Everything related to this methods report a bug as they always return false. Normally this methods will be very useful in this case, making a very simple and compact code. But nothing is perfect :) – LoicTheAztec Sep 28 '16 at 13:29
  • @RaunakGupta I've printed the above and I get "1" for usage limit, "0" for usage count and "2017-01-13" for the expiry date. It is managing to get the data correctly from the coupon so not sure why your code isn't working... – NuclearApe Sep 28 '16 at 13:57
  • @RaunakGupta I figured out the problem. **If there has been no expiry date set then it always returns false. regardless of whether there are uses left. If there is an expiry date set then it works fine :)** Most of the coupons we use don't have an expiry date set, only a usage limit. I have modified your code above so that it doesn't check against the expiry date and now everything is working fine. – NuclearApe Sep 28 '16 at 14:05
  • @RaunakGupta I have also modified your code to remove unnecessary lines and keep it clean :) Thank you – NuclearApe Sep 28 '16 at 14:20
  • @NuclearApe: as you have said you don't have date in coupons, so just replace with if conditions with this `(($usage_left > 0) && ($coupon_data['expiry_date'] > date('Y-m-d')) || is_null($coupon_data['expiry_date'])) ` i hope this will work. – Raunak Gupta Sep 28 '16 at 14:28
  • Thanks for sharing your answer with us.. :) – Rana Ghosh Nov 08 '16 at 06:40
  • @RaunakGupta `if($coupon_data['expiry_date'] > date('Y-m-d'))` : this thing will show to this coupon haven't expired ? – huykon225 Mar 11 '17 at 16:20
  • @huykon225: sorry I didn't able to get you. – Raunak Gupta Mar 13 '17 at 06:41
  • @RaunakGupta you have a bug in your code as I see. You have passed the date as second parameter here: date('Y-m-d', $coupon->expiry_date) But date function needs to receive UNIX timestamp instead as a second parameter. So date function is not needed here, just write: 'expiry_date' => (!empty($coupon->expiry_date) ) ? $coupon->expiry_date : null, – Blackster Apr 09 '21 at 09:20
1
add_action( 'rest_api_init', 'coupon' );

function coupon($request) {
  register_rest_route('custom-plugin', '/coupon_code/',
    array(
      'methods'  => 'POST',
      'callback' => 'coupon_code',
    )
  );
}

function coupon_code($request)
{
$code = $request->get_param('coupon');
$applied_coupon = $request->get_param('applied_coupon');
$cart_amount = $request->get_param('cart_amount');
$user_id = $request->get_param('user_id');
// $code = 'test123';



$coupon = new WC_Coupon($code);
$coupon_post = get_post($coupon->id);

$coupon_data = array(
    'id' => $coupon->id,
    'code' => esc_attr($coupon_post->post_title),
    'type' => $coupon->type,
    'created_at' => $coupon_post->post_date_gmt,
    'updated_at' => $coupon_post->post_modified_gmt,
    'amount' => wc_format_decimal($coupon->coupon_amount, 2),
    'individual_use' => ( 'yes' === $coupon->individual_use ),
    'product_ids' => array_map('absint', (array) $coupon->product_ids),
    'exclude_product_ids' => array_map('absint', (array) $coupon->exclude_product_ids),
    'usage_limit' => (!empty($coupon->usage_limit) ) ? $coupon->usage_limit : null,
    'usage_count' => (int) $coupon->usage_count,
    'expiry_date' => (!empty($coupon->expiry_date) ) ? date('Y-m-d', $coupon->expiry_date) : null,
    'enable_free_shipping' => $coupon->enable_free_shipping(),
    'product_category_ids' => array_map('absint', (array) $coupon->product_categories),
    'exclude_product_category_ids' => array_map('absint', (array) $coupon->exclude_product_categories),
    'exclude_sale_items' => $coupon->exclude_sale_items(),
    'minimum_amount' => wc_format_decimal($coupon->minimum_amount, 2),
    'maximum_amount' => wc_format_decimal($coupon->maximum_amount, 2),
    'customer_emails' => $coupon->customer_email,
    'description' => $coupon_post->post_excerpt,
);

if ($coupon_data['code'] != $code) {
    $response['status'] = "failed";
    $response['message'] = "COUPON ".$code." DOES NOT EXIST!";
    return new WP_REST_Response($response);
}
$Acoupon = new WC_Coupon($applied_coupon);
 // print_r($Acoupon);exit();
    if($Acoupon->individual_use == 'yes'){
    $response['status'] = "failed";
    $response['message'] = "SORRY, COUPON ".$applied_coupon." HAS ALREADY BEEN APPLIED AND CANNOT BE USED IN CONJUNCTION WITH OTHER COUPONS.";
    $response['result'] = $Acoupon->individual_use;
    return new WP_REST_Response($response); 
    }

 if ($coupon_data['minimum_amount'] > $cart_amount) {

  $response['status'] = "failed";  
  $response['message'] = "THE MINIMUM SPEND FOR THIS COUPON IS $".$coupon_data['minimum_amount'].".";
  return  new WP_REST_Response($response);
}

if ($coupon_data['maximum_amount'] < $cart_amount) {

  $response['status'] = "failed";  
  $response['message'] = "THE MAXIMUM SPEND FOR THIS COUPON IS $".$coupon_data['maximum_amount'].".";
  return  new WP_REST_Response($response);
}

if ($coupon_data['exclude_sale_items'] == true) {
 $response['status'] = "failed";  
  $response['message'] = "SORRY, THIS COUPON IS NOT VALID FOR SALE ITEMS.";
  return  new WP_REST_Response($response); 
}

$usage_left = $coupon_data['usage_limit'] - $coupon_data['usage_count'];

if ($usage_left == 0) {
    $response['status'] = "failed";  
    $response['message'] = "SORRY, COUPON USAGE LIMIT HAS BEEN REACHED.";
    return  new WP_REST_Response($response);
} 
 $current_time = date('Y-m-d');
 $coupon_Expiry_date = $coupon->expiry_date;
if ($coupon_Expiry_date < $current_time) {
    $response['status'] = "failed";  
    $response['message'] = "THIS COUPON HAS EXPIRED.";
    return  new WP_REST_Response($response);
}

$user_limite = get_post_meta($coupon_data['id'], 'usage_limit_per_user', true);
 $p_id = $coupon_data['id'];
 global $wpdb;
$count_of_per_user = $wpdb->get_results("SELECT * FROM wp_postmeta where post_id = $p_id  and meta_key = '_used_by' and meta_value = $user_id");
$count = count($count_of_per_user);
if ( $count >= $user_limite) {
  $response['status'] = "failed"`enter code here`;  
  $response['message'] = "COUPON USAGE LIMIT HAS BEEN REACHED.";
  return  new WP_REST_Response($response);
}enter code here

else{
  $response['status'] = "Success";  
  $response['message'] = "COUPON APPLIED.";
  return  new WP_REST_Response($response); 
}

}
use this function