Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WooCommerce validate coupon by expiry date and time

I am using woocommerce and I wanna validate a coupon not only by the default built-in expiry date checking, but also expiry time as well.

I have added a custom field to coupons, that allows to set an expiry time.

I wrote the following code snippet in order to override the default method validate_coupon_expiry_date in class WC_Discounts:

  class WC_My_plugin_Discounts extends WC_Discounts
  {
    // override validate_coupon_expiry_date to include expiry time:
    protected function validate_coupon_expiry_date($coupon)
    {
      $expiry_date = date('Y-m-d', $coupon->get_date_expires()->getTimestamp());
      // I add a custom field `expiry_time` in postmeta table:
      $expiry_time = $coupon->get_meta('expiry_time');

      $dateTime = new DateTime($expiry_date . $expiry_time);

      if ($coupon->get_date_expires() && apply_filters('woocommerce_coupon_validate_expiry_date', time() > $dateTime, $coupon, $this)) {
        throw new Exception(__('This coupon has expired.', 'woocommerce'), 107);
      }

      return true;
    }
   }

Then, I try to validate coupons with the following snippet:

add_filter('woocommerce_coupon_is_valid', array($this, 'validate_coupon'), 15, 2);
function validate_coupon($valid, $coupon)
{
   $cart = WC()->cart;
   $discounts = new WC_My_plugin_Discounts($cart);

   // is_coupon_valid is a public method in class WC_Discounts; and this method will run the protected 
   // method validate_coupon_expiry_date:
   $valid = $discounts->is_coupon_valid($coupon);
   
   return $valid;
}

The problem:

While I tested my codes by applying a coupon in the front end cart page, and tried to examine my above codes using debugger, I noticed that callback validate_coupon actually did not run; is it that I am using the wrong filter hook such that no event is triggered? Have I written the codes wrongly? Could anyone kindly share any idea on this? Thx a lot.

like image 559
Hugo1280 Avatar asked Mar 15 '21 08:03

Hugo1280


1 Answers

This can be made in a more simple and effective way. You can use the following instead:

add_filter( 'woocommerce_coupon_validate_expiry_date', 'filter_coupon_validate_expiry_date', 10, 3 );
function validate_coupon( $valid, $coupon, $discount ) {
    $expiry_date     = $coupon->get_date_expires();
    $expiry_time     = $coupon->get_meta('expiry_time'); // Coupon custom field 

    if ( $expiry_date && ! empty($expiry_time) ) {
        $timezone        = $coupon->get_date_expires()->getTimezone(); // get timezone
        $expiry_datetime = new WC_DateTime( $expiry_date->date('Y-m-d') . ' ' . $expiry_time );
        $now_datetime    = new WC_DateTime();
    
        $expiry_datetime->setTimezone( $timezone ); // set time zone
        $now_datetime->setTimezone( $timezone ); // set time zone 
        
        $valid = $now_datetime->getTimestamp() > $expiry_datetime->getTimestamp();
    }
    return $valid;   
}

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

For plugins that uses a Class with methods and functions, you will replace:

add_filter( 'woocommerce_coupon_validate_expiry_date', 'filter_coupon_validate_expiry_date', 10, 3 );

with:

add_filter( 'woocommerce_coupon_validate_expiry_date', array($this, 'filter_coupon_validate_expiry_date'), 10, 3 );
like image 60
LoicTheAztec Avatar answered Oct 25 '22 21:10

LoicTheAztec