🎟️ Gift Coupon active_time and expires_time

TLDR
gift coupons do not have active_time or expires_time dates passed into them, despite their fields being included in their database record and they are being checked for when a coupon is being validated. Is this just an omission or by design?

Longer
within the valid_coupon function in s2member-pro/src/includes/classes/coupons.inc.php it checks:

$_coupon[‘active_time’]
then $_coupon[‘expires_time’]

before checking
$_coupon[‘singulars’]
then $_coupon[‘users’]
then $_coupon[‘max_uses’]

See lines 534 onwards for this. active_time and expires_time are being checked for on lines 536 & 537

492                 public function valid_coupon($coupon_code, $attr)
493                 {
494                         global $wpdb; // Global DB reference.
495                         /** @var $wpdb \wpdb Reference for IDEs. */
496
497                         global $current_user; // Global user reference.
498                         /** @var $current_user \WP_User for IDEs. */
499
500                         $current_time = time(); // UTC timestamp.
501
502                         if(!($coupon_code = trim((string)$coupon_code)))
503                                 return array(); // Not possible.
504
505                         if(strlen($_affiliate_suffix_chars = $GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_affiliate_coupon_code_suffix_chars']))
506                                 if(preg_match('/^(.+?)'.preg_quote($_affiliate_suffix_chars, '/').'([0-9]+)$/i', $coupon_code, $_m))
507                                         $coupon_code = $_m[1]; // Validate the underlying coupon code only.
508                         unset($_affiliate_suffix_chars, $_m); // Housekeeping.
509
510                         if(!($coupon_code = $this->n_code($coupon_code)))
511                                 return array(); // Not valid at all :-)
512
513                         $attr = (array)$attr; // Force array value.
514
515                         foreach($this->coupons as $_coupon) // Iterate coupons.
516                         {
517                                 if($coupon_code !== $_coupon['code'])
518                                         continue; // Not a match here.
519
520                                 if(!$_coupon['active_time'] || $current_time >= $_coupon['active_time'])
521                                         if(!$_coupon['expires_time'] || $current_time <= $_coupon['expires_time'])
522                                                 if(!$_coupon['singulars'] || (!empty($attr['singular']) && in_array((integer)$attr['singular'], $_coupon['singulars'], TRUE)))
523                                                         if(!$_coupon['users'] || ($current_user->ID && in_array((integer)$current_user->ID, $_coupon['users'], TRUE)))
524                                                                 if(!$_coupon['max_uses'] || $this->get_uses($_coupon['code']) < $_coupon['max_uses'])
525                                                                         //240829 Specific pro-forms
526                                                                         if (!$_coupon['pforms'] || (!empty($attr['pform']) && in_array($attr['pform'], $_coupon['pforms'], TRUE)))
527                                                                                 //250418 Max uses per user.
528                                                                                 if (!$_coupon['user_max_uses'] || (empty($user_coupon_uses = get_user_option('s2member_coupon_uses', $current_user->ID))) || (!isset($user_coupon_uses[strtolower($_coupon['code'])])) || (count($user_coupon_uses[strtolower($_coupon['code'])]) < $_coupon['user_max_uses']))
529                                                                                         return $_coupon; // It's discount time! :-)
530                                 return array(); // Not valid at this time.
531                         }
532                         unset($_coupon); // Housekeeping.
533
534                         if(($_coupon = $this->get_gift($coupon_code))) // It's a gift code?
535                         {
536                                 if(!$_coupon['active_time'] || $current_time >= $_coupon['active_time'])
537                                         if(!$_coupon['expires_time'] || $current_time <= $_coupon['expires_time'])
538                                                 if(!$_coupon['singulars'] || (!empty($attr['singular']) && in_array((integer)$attr['singular'], $_coupon['singulars'], TRUE)))
539                                                         if(!$_coupon['users'] || ($current_user->ID && in_array((integer)$current_user->ID, $_coupon['users'], TRUE)))
540                                                                 if(!$_coupon['max_uses'] || $this->get_uses($_coupon['code']) < $_coupon['max_uses'])
541                                                                         return $_coupon; // It's discount time! :-)
542                                 return array(); // Not valid at this time.
543                         }
544                         unset($_coupon); // Housekeeping.
545
546                         return array(); // Not valid at this time.
547                 }
548

but in the generate_gifts function neither active_time or expires_time are included in $_gift_list on line 582, which is what is being saved on line 591

559                 public function generate_gifts($args)
560                 {
561                         $default_args = array(
562                                 'quantity'  => 0,
563                                 'discount'  => '',
564                                 'directive' => '',
565                                 'singulars' => '',
566                         );
567                         $args         = array_merge($default_args, $args);
568                         $args         = array_intersect_key($args, $default_args);
569
570                         $quantity  = (integer)$args['quantity'];
571                         $discount  = str_replace('|', '', trim((string)$args['discount']));
572                         $directive = str_replace('|', '', trim((string)$args['directive']));
573                         $singulars = str_replace('|', '', trim((string)$args['singulars']));
574
575                         if(!($quantity = (integer)$quantity) || $quantity < 1)
576                                 return array(); // Not possible.
577
578                         for($_i = 0, $gifts = array(); $_i < $quantity; $_i++)
579                         {
580                                 $_gift_code = c_ws_plugin__s2member_utils_encryption::uunnci_key_20_max();
581                                 $_gift_code = $this->n_code('GC'.str_pad($_gift_code, 20, '0', STR_PAD_LEFT));
582                                 $_gift_list = $_gift_code.'|'.$discount.'||'.$directive.'|'.$singulars.'||1';
583                                 // `code|discount|dates|directive|singulars|users|max uses`.
584
585                                 $_gift              = $this->list_to_coupons($_gift_list, FALSE);
586                                 $_gift              = array_merge(array_pop($_gift), array('is_gift' => TRUE));
587                                 $gifts[$_gift_code] = $_gift; // A coupon code that's a gift.
588
589                                 add_option($this->gift_option_key($_gift_code), $gifts[$_gift_code], '', 'no');
590                         }
591                         unset($_i, $_gift_code, $_gift_list, $_gift); // Housekeeping.
592
593                         return $gifts;
594                 }

It’s pretty simple to include the extra lines to include them… So would there be an issue doing so?

gift coupons do not have active_time or expires_time dates passed into them, despite their fields being included in their database record and they are being checked for when a coupon is being validated. Is this just an omission or by design?

Interesting question.

I studied the code, and it seems to be intentional. The validation for git codes is the same used for ooupon codes, and because coupons could have date, the validator checks that.

It seems like gift codes were not meant to have an expiration, and that’s why no time is saved for them. It doesn’t seem to be an oversight, but on purpose. Look at this line:

				$_gift_list = $_gift_code.'|'.$discount.'||'.$directive.'|'.$singulars.'||1';

It clearly skips that field on purpose: '||'

And date is not a shortcode attribute either. WP Admin > s2Member Pro > Pro Coupon Codes > Pro-Form Gift/Redemption Codes > Shortcode Attributes

It’s pretty simple to include the extra lines to include them… So would there be an issue doing so?

I don’t think there’d be an issue.

The gifts shortcode needs to be updated too, if you want to be able to specify the dates.

s2member-pro/src/includes/classes/coupons.inc.php
s2member-pro/src/includes/classes/sc-gift-codes-in.inc.php

:slight_smile:

1 Like