WooCommerce Extended Coupon Features - Version 2.2.5

Version Description

  • FEATURE: BOGO On all matching products
  • FIX: Changed WooCommerce detection method for better Multi Site support
  • FIX: Free products: Fixed an inconsistency that could cause a loop on removal/adding of free variant products
  • TWEAK: Free products: Hooking before_calculate_totals for most cases but also on woocommerce_applied_coupon, which is required when one coupon is replaced by another
  • INTERNAL: Check if classes already exist before creating them
Download this release

Release Info

Developer josk79
Plugin Icon 128x128 WooCommerce Extended Coupon Features
Version 2.2.5
Comparing to
See all releases

Code changes from version 2.2.4 to 2.2.5

includes/wjecf-autocoupon.php CHANGED
@@ -1,13 +1,17 @@
1
  <?php
2
 
3
- class WC_Jos_AutoCoupon_Controller{
 
 
 
 
 
 
4
 
5
  private $_autocoupon_codes = null;
6
 
7
  private $_user_emails = null;
8
 
9
- private $_check_already_performed = false;
10
-
11
  protected $_executed_coupon_by_url = false;
12
 
13
  public function __construct() {
@@ -23,8 +27,8 @@ class WC_Jos_AutoCoupon_Controller{
23
  add_action( 'admin_init', array( &$this, 'admin_init' ) );
24
 
25
  //Frontend hooks - logic
26
- add_action( 'woocommerce_after_calculate_totals', array( &$this, 'update_matched_autocoupons' ) );
27
- add_action( 'woocommerce_check_cart_items', array( &$this, 'update_matched_autocoupons' ) , 0 ); //Remove coupon before WC does it and shows a message
28
  //Last check for coupons with restricted_emails
29
  add_action( 'woocommerce_checkout_update_order_review', array( $this, 'fetch_billing_email' ), 10 ); // AJAX One page checkout
30
 
@@ -170,18 +174,21 @@ class WC_Jos_AutoCoupon_Controller{
170
  return $originaltext;
171
  }
172
  }
 
 
 
173
 
174
  /**
175
  * Apply matched autocoupons and remove unmatched autocoupons.
176
  * @return void
177
  */
178
  function update_matched_autocoupons() {
179
- if ( $this->_check_already_performed ) {
180
- //$this->log ( 'check already performed' );
181
  return;
182
  }
183
- $this->_check_already_performed = true;
184
 
 
185
  $calc_needed = $this->remove_unmatched_autocoupons();
186
  foreach ( $this->get_all_auto_coupons() as $coupon_code ) {
187
  if ( ! WC()->cart->has_discount( $coupon_code ) ) {
@@ -445,7 +452,6 @@ class WC_Jos_AutoCoupon_Controller{
445
 
446
  //FOR DEBUGGING ONLY
447
  private function log ( $string ) {
448
- error_log($string);
449
- // file_put_contents ( "/lamp/www/logfile.log", date("Y-m-d | h:i:sa") . " " . current_filter() . ": " . $string . "\n" , FILE_APPEND );
450
  }
451
  }
1
  <?php
2
 
3
+ defined('ABSPATH') or die();
4
+
5
+ if ( class_exists('WC_Jos_AutoCoupon_Controller') ) {
6
+ return;
7
+ }
8
+
9
+ class WC_Jos_AutoCoupon_Controller {
10
 
11
  private $_autocoupon_codes = null;
12
 
13
  private $_user_emails = null;
14
 
 
 
15
  protected $_executed_coupon_by_url = false;
16
 
17
  public function __construct() {
27
  add_action( 'admin_init', array( &$this, 'admin_init' ) );
28
 
29
  //Frontend hooks - logic
30
+ add_action( 'woocommerce_after_calculate_totals', array( &$this, 'update_matched_autocoupons' ) );
31
+ add_action( 'woocommerce_check_cart_items', array( &$this, 'update_matched_autocoupons' ) , 0 ); //Remove coupon before WC does it and shows a message
32
  //Last check for coupons with restricted_emails
33
  add_action( 'woocommerce_checkout_update_order_review', array( $this, 'fetch_billing_email' ), 10 ); // AJAX One page checkout
34
 
174
  return $originaltext;
175
  }
176
  }
177
+
178
+ //Infinite loop protection
179
+ private $_update_matched_autocoupons_count = 0;
180
 
181
  /**
182
  * Apply matched autocoupons and remove unmatched autocoupons.
183
  * @return void
184
  */
185
  function update_matched_autocoupons() {
186
+ if ( $this->_update_matched_autocoupons_count++ > 20 ) {
187
+ $this->log ( 'update_matched_autocoupons counter reached limit 20' );
188
  return;
189
  }
 
190
 
191
+ //$this->log ( 'update_matched_autocoupons' );
192
  $calc_needed = $this->remove_unmatched_autocoupons();
193
  foreach ( $this->get_all_auto_coupons() as $coupon_code ) {
194
  if ( ! WC()->cart->has_discount( $coupon_code ) ) {
452
 
453
  //FOR DEBUGGING ONLY
454
  private function log ( $string ) {
455
+ error_log( date("Y-m-d | h:i:sa") . ": " . get_class( $this ) . ": " . $string );
 
456
  }
457
  }
includes/wjecf-coupon-extensions.php CHANGED
@@ -1,11 +1,28 @@
1
  <?php
2
 
3
-
4
  defined('ABSPATH') or die();
5
 
 
 
 
 
6
  class WC_Jos_Extended_Coupon_Features_Controller {
7
  private $options = false;
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  public function __construct() {
11
  add_action('init', array( &$this, 'controller_init' ));
@@ -34,33 +51,44 @@ class WC_Jos_Extended_Coupon_Features_Controller {
34
  }
35
  }
36
 
37
- private $wc_version = null;
38
  /**
39
  * Check whether WooCommerce version is greater or equal than $req_version
40
  * @param string @req_version The version to compare to
41
  * @return bool true if WooCommerce is at least the given version
42
  */
43
- public function check_woocommerce_version( $req_version ) {
44
- if ($this->wc_version === null) {
 
 
 
 
 
 
 
 
 
45
  // If get_plugins() isn't available, require it
46
- if ( ! function_exists( 'get_plugins' ) )
47
  require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
 
48
 
49
- // Create the plugins folder and file variables
50
  $plugin_folder = get_plugins( '/woocommerce' );
51
  $plugin_file = 'woocommerce.php';
52
 
53
  // If the plugin version number is set, return it
54
  if ( isset( $plugin_folder[$plugin_file]['Version'] ) ) {
55
- $this->wc_version = $plugin_folder[$plugin_file]['Version'];
 
 
56
  }
57
- }
58
- if ($this->wc_version === false) {
59
- return false;
60
- }
61
 
62
- return version_compare( $this->wc_version, $req_version, '>=' );
63
- }
 
 
 
 
64
 
65
  //Upgrade options on version change
66
  public function auto_upgrade_options() {
@@ -663,7 +691,7 @@ class WC_Jos_Extended_Coupon_Features_Controller {
663
 
664
  //Test if coupon is valid for the product
665
  // (this function is used to count the quantity of matching products)
666
- private function coupon_is_valid_for_product( $coupon, $product, $values = array() ) {
667
  //Ugly hack: $coupon->is_valid_for_product only works for these types
668
  $original_discount_type = $coupon->discount_type;
669
  if ( ! $this->coupon_is_type( $coupon, array( 'fixed_product', 'percent_product' ) ) ) {
@@ -677,14 +705,28 @@ class WC_Jos_Extended_Coupon_Features_Controller {
677
 
678
 
679
 
680
- //
 
 
 
 
 
 
 
 
 
 
 
 
 
 
681
 
682
  /**
683
  * Get a WC_Coupon object
684
  * @param WC_Coupon|string $coupon The coupon code or a WC_Coupon object
685
  * @return WC_Coupon The coupon object
686
  */
687
- private function get_coupon( $coupon ) {
688
  if ( ! ( $coupon instanceof WC_Coupon ) ) {
689
  $coupon = new WC_Coupon( $coupon );
690
  }
1
  <?php
2
 
 
3
  defined('ABSPATH') or die();
4
 
5
+ if ( class_exists('WC_Jos_Extended_Coupon_Features_Controller') ) {
6
+ return;
7
+ }
8
+
9
  class WC_Jos_Extended_Coupon_Features_Controller {
10
  private $options = false;
11
 
12
+ /**
13
+ * Singleton Instance
14
+ *
15
+ * @static
16
+ * @return Singleton Instance
17
+ */
18
+ public static function instance() {
19
+ if ( is_null( self::$_instance ) ) {
20
+ self::$_instance = new self();
21
+ }
22
+ return self::$_instance;
23
+ }
24
+ protected static $_instance = null;
25
+
26
 
27
  public function __construct() {
28
  add_action('init', array( &$this, 'controller_init' ));
51
  }
52
  }
53
 
 
54
  /**
55
  * Check whether WooCommerce version is greater or equal than $req_version
56
  * @param string @req_version The version to compare to
57
  * @return bool true if WooCommerce is at least the given version
58
  */
59
+ public static function check_woocommerce_version( $req_version ) {
60
+ return version_compare( self::get_woocommerce_version(), $req_version, '>=' );
61
+ }
62
+
63
+ private static $wc_version = null;
64
+ /**
65
+ * Get the WooCommerce version number
66
+ * @return string|bool WC Version number or false if WC not detected
67
+ */
68
+ public static function get_woocommerce_version() {
69
+ if (self::$wc_version === null) {
70
  // If get_plugins() isn't available, require it
71
+ if ( ! function_exists( 'get_plugins' ) ) {
72
  require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
73
+ }
74
 
75
+ // Create the plugins folder and file variables
76
  $plugin_folder = get_plugins( '/woocommerce' );
77
  $plugin_file = 'woocommerce.php';
78
 
79
  // If the plugin version number is set, return it
80
  if ( isset( $plugin_folder[$plugin_file]['Version'] ) ) {
81
+ self::$wc_version = $plugin_folder[$plugin_file]['Version'];
82
+ } else {
83
+ self::$wc_version = false; // Not found
84
  }
 
 
 
 
85
 
86
+ //echo "<pre>";var_dump( get_site_option( 'active_sitewide_plugins' ) );die();
87
+ //echo "<pre>";var_dump( get_plugins() );die();
88
+ //die(self::$wc_version);
89
+ }
90
+ return self::$wc_version;
91
+ }
92
 
93
  //Upgrade options on version change
94
  public function auto_upgrade_options() {
691
 
692
  //Test if coupon is valid for the product
693
  // (this function is used to count the quantity of matching products)
694
+ public function coupon_is_valid_for_product( $coupon, $product, $values = array() ) {
695
  //Ugly hack: $coupon->is_valid_for_product only works for these types
696
  $original_discount_type = $coupon->discount_type;
697
  if ( ! $this->coupon_is_type( $coupon, array( 'fixed_product', 'percent_product' ) ) ) {
705
 
706
 
707
 
708
+ // =====================
709
+
710
+ /**
711
+ * Retrieve the id of the product or the variation id if it's a variant.
712
+ * @Returns int|bool The variation or product id. False if not a valid product
713
+ */
714
+ public function get_product_or_variation_id( $product ) {
715
+ if ( is_a( $product, 'WC_Product_Variation' ) ) {
716
+ return $product->variation_id;
717
+ } elseif ( is_a( $product, 'WC_Product' ) ) {
718
+ return $product->id;
719
+ } else {
720
+ return false;
721
+ }
722
+ }
723
 
724
  /**
725
  * Get a WC_Coupon object
726
  * @param WC_Coupon|string $coupon The coupon code or a WC_Coupon object
727
  * @return WC_Coupon The coupon object
728
  */
729
+ public function get_coupon( $coupon ) {
730
  if ( ! ( $coupon instanceof WC_Coupon ) ) {
731
  $coupon = new WC_Coupon( $coupon );
732
  }
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=5T9XQ
4
  Tags: woocommerce, coupons, discount
5
  Requires at least: 4.0.0
6
  Tested up to: 4.3.1
7
- Stable tag: 2.2.4
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -100,6 +100,13 @@ Sure! [This](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=5T9XQ
100
  4. Additionals restrictions based on shipping or payment method or the customer
101
 
102
  == Changelog ==
 
 
 
 
 
 
 
103
  = 2.2.4 =
104
  * FEATURE: Online documentation added
105
  * FEATURE: Use AND-operator for the selected categories (default is OR)
4
  Tags: woocommerce, coupons, discount
5
  Requires at least: 4.0.0
6
  Tested up to: 4.3.1
7
+ Stable tag: 2.2.5
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
100
  4. Additionals restrictions based on shipping or payment method or the customer
101
 
102
  == Changelog ==
103
+ = 2.2.5 =
104
+ * FEATURE: BOGO On all matching products
105
+ * FIX: Changed WooCommerce detection method for better Multi Site support
106
+ * FIX: Free products: Fixed an inconsistency that could cause a loop on removal/adding of free variant products
107
+ * TWEAK: Free products: Hooking before_calculate_totals for most cases but also on woocommerce_applied_coupon, which is required when one coupon is replaced by another
108
+ * INTERNAL: Check if classes already exist before creating them
109
+
110
  = 2.2.4 =
111
  * FEATURE: Online documentation added
112
  * FEATURE: Use AND-operator for the selected categories (default is OR)
woocommerce-jos-autocoupon.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: WooCommerce Extended Coupon Features
4
  * Plugin URI: http://www.soft79.nl
5
  * Description: Additional functionality for WooCommerce Coupons: Apply certain coupons automatically, allow applying coupons via an url, etc...
6
- * Version: 2.2.4
7
  * Author: Jos Koenis
8
  * License: GPL2
9
  */
@@ -19,18 +19,31 @@ require_once( 'includes/wjecf-coupon-extensions.php' );
19
  @include_once( 'includes/wjecf-pro-free-products.php' );
20
 
21
  /**
22
- * Create the plugin if WooCommerce is active
23
  **/
24
- if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
25
-
 
 
 
 
 
26
  if ( ! function_exists( 'wjecf_load_plugin_textdomain' ) ) {
 
 
 
 
 
 
 
27
  function wjecf_load_plugin_textdomain() {
28
  load_plugin_textdomain('woocommerce-jos-autocoupon', false, basename(dirname(__FILE__)) . '/languages/' );
29
  }
30
  add_action('plugins_loaded', 'wjecf_load_plugin_textdomain');
31
- $wjecf_extended_coupon_features = new WC_Jos_Extended_Coupon_Features_Controller();
 
32
  $wjecf_autocoupon = new WC_Jos_AutoCoupon_Controller();
33
- if ( $wjecf_extended_coupon_features->is_pro() ) {
34
  if ( class_exists( 'WC_Jos_Pro_Controller' ) ) {
35
  $wjecf_pro = new WC_Jos_Pro_Controller();
36
  }
@@ -40,7 +53,6 @@ if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', g
40
  }
41
  }
42
 
43
-
44
  }
45
 
46
  /**
3
  * Plugin Name: WooCommerce Extended Coupon Features
4
  * Plugin URI: http://www.soft79.nl
5
  * Description: Additional functionality for WooCommerce Coupons: Apply certain coupons automatically, allow applying coupons via an url, etc...
6
+ * Version: 2.2.5
7
  * Author: Jos Koenis
8
  * License: GPL2
9
  */
19
  @include_once( 'includes/wjecf-pro-free-products.php' );
20
 
21
  /**
22
+ * Initiate the plugin if WooCommerce is active
23
  **/
24
+ if ( WC_Jos_Extended_Coupon_Features_Controller::get_woocommerce_version() == false ) {
25
+ add_action( 'admin_notices', 'wjecf_admin_notice' );
26
+ function wjecf_admin_notice() {
27
+ $msg = __( 'WooCommerce Extended Coupon Features is disabled because WooCommerce could not be detected.', 'soft79-wc-pricing-rules' );
28
+ echo '<div class="error"><p>' . $msg . '</p></div>';
29
+ }
30
+ } else {
31
  if ( ! function_exists( 'wjecf_load_plugin_textdomain' ) ) {
32
+ /**
33
+ * Get the instance if the WC_Jos_Extended_Coupon_Features_Controller
34
+ */
35
+ function WJECF() {
36
+ return WC_Jos_Extended_Coupon_Features_Controller::instance();
37
+ }
38
+
39
  function wjecf_load_plugin_textdomain() {
40
  load_plugin_textdomain('woocommerce-jos-autocoupon', false, basename(dirname(__FILE__)) . '/languages/' );
41
  }
42
  add_action('plugins_loaded', 'wjecf_load_plugin_textdomain');
43
+
44
+ $wjecf_extended_coupon_features = WJECF();
45
  $wjecf_autocoupon = new WC_Jos_AutoCoupon_Controller();
46
+ if ( WJECF()->is_pro() ) {
47
  if ( class_exists( 'WC_Jos_Pro_Controller' ) ) {
48
  $wjecf_pro = new WC_Jos_Pro_Controller();
49
  }
53
  }
54
  }
55
 
 
56
  }
57
 
58
  /**