WooCommerce Extended Coupon Features - Version 2.5.1

Version Description

  • (PRO) FEATURE: Free product selection using checkboxes / numeric inputs
  • (PRO) FIX: Free product selection fails if coupon code contains a space
  • FIX: Draft settings not being saved
  • FIX: PHP < 5.5 compatibility
  • FIX: Abstract_WJECF_Plugin log function
  • INTERNAL: Functions add_action_once / add_filter_once. To guarantee execution only once.
  • INTERNAL: Updated the API example; also usable from CLI
  • INTERNAL: Created Sanitizer for form data handling
  • INTERNAL: Reorganised coupon meta handling ( Abstract_WJECF_Plugin::admin_coupon_meta_fields )
Download this release

Release Info

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

Code changes from version 2.4.3 to 2.5.1

assets/wjecf.css CHANGED
@@ -1,18 +1,23 @@
1
  /*
2
  WJECF columns system
3
  */
 
4
  ul.wjecf-cols { list-style-type: none;margin:0}
 
5
  ul.wjecf-cols > li { float:left;margin-right:3%;margin-left:0; }
6
- .woocommerce-cart table.cart ul.wjecf-cols > li > img { width:auto; }
7
 
8
- ul.wjecf-cols.cols-2 li { width:48.5%; }
9
- ul.wjecf-cols.cols-3 li { width:31.3%; }
10
- ul.wjecf-cols.cols-4 li { width:22.7%; }
11
- ul.wjecf-cols.cols-5 li { width:17.6%; }
12
- ul.wjecf-cols.cols-6 li { width:14.1%; }
 
 
 
 
 
 
13
 
14
- ul.wjecf-cols.cols-2 li:nth-child(2n+2),
15
- ul.wjecf-cols.cols-3 li:nth-child(3n+3),
16
- ul.wjecf-cols.cols-4 li:nth-child(4n+4),
17
- ul.wjecf-cols.cols-5 li:nth-child(5n+5),
18
- ul.wjecf-cols.cols-6 li:nth-child(6n+6) { margin-right:0!important; }
1
  /*
2
  WJECF columns system
3
  */
4
+
5
  ul.wjecf-cols { list-style-type: none;margin:0}
6
+ ul.wjecf-cols::after { content:'';display:block;clear:both; } /* clearfix */
7
  ul.wjecf-cols > li { float:left;margin-right:3%;margin-left:0; }
 
8
 
9
+ ul.wjecf-cols.cols-2 > li { width:48.5%; }
10
+ ul.wjecf-cols.cols-3 > li { width:31.3%; }
11
+ ul.wjecf-cols.cols-4 > li { width:22.7%; }
12
+ ul.wjecf-cols.cols-5 > li { width:17.6%; }
13
+ ul.wjecf-cols.cols-6 > li { width:14.1%; }
14
+
15
+ ul.wjecf-cols.cols-2 > li:nth-child(2n+2),
16
+ ul.wjecf-cols.cols-3 > li:nth-child(3n+3),
17
+ ul.wjecf-cols.cols-4 > li:nth-child(4n+4),
18
+ ul.wjecf-cols.cols-5 > li:nth-child(5n+5),
19
+ ul.wjecf-cols.cols-6 > li:nth-child(6n+6) { margin-right:0!important; }
20
 
21
+ .wjecf-select-free-products ul.wjecf-cols > li > img { width:auto; }
22
+ .wjecf-select-free-products ul.wjecf-cols > li input[type="number"] { width:100%; }
23
+ .wjecf-select-free-products ul.wjecf-cols > li select { width:100%; }
 
 
includes/{abstract-wjecf-plugin.php → Abstract_WJECF_Plugin.php} RENAMED
@@ -5,8 +5,24 @@ abstract class Abstract_WJECF_Plugin {
5
  //Override these functions in the WJECF plugin
6
 
7
  public function init_hook() {}
 
8
  public function init_admin_hook() {}
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  /**
11
  * Asserts that all dependencies are respected. If not an Exception is thrown. Override this function for extra assertions (e.g. minimum plugin versions)
12
  * @return void
@@ -18,8 +34,8 @@ abstract class Abstract_WJECF_Plugin {
18
  }
19
  }
20
 
21
- if ( ! empty ( $this->plugin_data['required_version_wjecf'] ) ) {
22
- $this->assert_wjecf_version( $this->plugin_data['required_version_wjecf'] );
23
  }
24
  }
25
 
@@ -29,8 +45,8 @@ abstract class Abstract_WJECF_Plugin {
29
  * @return void
30
  */
31
  protected function assert_wjecf_version( $required_version ) {
32
- if ( version_compare( WJECF()->version, $required_version, '<' ) ) {
33
- throw new Exception( sprintf( __( 'WooCommerce Extended Coupon Features version %s is required. You have version %s', 'woocommerce-jos-autocoupon' ), $required_version, WJECF()->version ) );
34
  }
35
  }
36
 
@@ -42,8 +58,13 @@ abstract class Abstract_WJECF_Plugin {
42
  * @param string $message The message to log
43
  *
44
  */
45
- protected function log ( $message ) {
46
- WJECF()->log( $message, 1 );
 
 
 
 
 
47
  }
48
 
49
  private $plugin_data = array();
@@ -97,7 +118,8 @@ abstract class Abstract_WJECF_Plugin {
97
  }
98
 
99
  public function plugin_is_enabled() {
100
- return true;
 
101
  }
102
 
103
  }
5
  //Override these functions in the WJECF plugin
6
 
7
  public function init_hook() {}
8
+
9
  public function init_admin_hook() {}
10
 
11
+ /**
12
+ * Returns an array with the meta_keys for this plugin and the sanitazion to apply.
13
+ * Instead of a sanitazion a callback can be given; which must return the meta value to save to the database
14
+ *
15
+ * e.g. [
16
+ * '_wjecf_some_comma_separated_ints' => 'int,',
17
+ * '_wjecf_some_callback' => [ 'callback' => [ callback ] ],
18
+ * ]
19
+ *
20
+ * @return array The fields for this plugin
21
+ */
22
+ public function admin_coupon_meta_fields( $coupon ) {
23
+ return array();
24
+ }
25
+
26
  /**
27
  * Asserts that all dependencies are respected. If not an Exception is thrown. Override this function for extra assertions (e.g. minimum plugin versions)
28
  * @return void
34
  }
35
  }
36
 
37
+ if ( ! empty ( $this->plugin_data['minimal_wjecf_version'] ) ) {
38
+ $this->assert_wjecf_version( $this->plugin_data['minimal_wjecf_version'] );
39
  }
40
  }
41
 
45
  * @return void
46
  */
47
  protected function assert_wjecf_version( $required_version ) {
48
+ if ( version_compare( WJECF()->plugin_version(), $required_version, '<' ) ) {
49
+ throw new Exception( sprintf( __( 'WooCommerce Extended Coupon Features version %s is required. You have version %s', 'woocommerce-jos-autocoupon' ), $required_version, WJECF()->plugin_version() ) );
50
  }
51
  }
52
 
58
  * @param string $message The message to log
59
  *
60
  */
61
+ protected function log( $level, $message = null ) {
62
+ //Backwards compatibility; $level was introduced in 2.4.4
63
+ if ( is_null( $message ) ) {
64
+ $message = 'level';
65
+ $level = 'debug';
66
+ }
67
+ WJECF()->log( $level, $message, 1 );
68
  }
69
 
70
  private $plugin_data = array();
118
  }
119
 
120
  public function plugin_is_enabled() {
121
+ if ( ! $this->get_plugin_data( 'can_be_disabled' ) ) return true;
122
+ return ! in_array( $this->get_plugin_class_name(), WJECF()->get_option('disabled_plugins') );
123
  }
124
 
125
  }
includes/{wjecf-autocoupon.php → WJECF_AutoCoupon.php} RENAMED
@@ -25,21 +25,22 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
25
 
26
  //Frontend hooks - logic
27
  if ( WJECF_WC()->check_woocommerce_version('2.3.0')) {
28
- add_action( 'woocommerce_after_calculate_totals', array( &$this, 'update_matched_autocoupons' ) );
29
  } else {
30
  //WC Versions prior to 2.3.0 don't have after_calculate_totals hook, this is a fallback
31
- add_action( 'woocommerce_cart_updated', array( &$this, 'update_matched_autocoupons' ) );
32
  }
33
- add_action( 'woocommerce_check_cart_items', array( &$this, 'remove_unmatched_autocoupons' ) , 0, 0 ); //Remove coupon before WC does it and shows a message
 
34
  //Last check for coupons with restricted_emails
35
- add_action( 'woocommerce_checkout_update_order_review', array( &$this, 'fetch_billing_email' ), 10 ); // AJAX One page checkout
36
 
37
  //Frontend hooks - visualisation
38
- add_filter('woocommerce_cart_totals_coupon_label', array( &$this, 'coupon_label' ), 10, 2 );
39
- add_filter('woocommerce_cart_totals_coupon_html', array( &$this, 'coupon_html' ), 10, 2 );
40
 
41
  //Inhibit redirect to cart when apply_coupon supplied
42
- add_filter('option_woocommerce_cart_redirect_after_add', array ( &$this, 'option_woocommerce_cart_redirect_after_add') );
43
 
44
  if ( ! is_ajax() ) {
45
  //Get cart should not be called before the wp_loaded action nor the add_to_cart_action (class-wc-form-handler)
@@ -50,7 +51,6 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
50
  /* ADMIN HOOKS */
51
  public function init_admin_hook() {
52
  add_action( 'wjecf_woocommerce_coupon_options_extended_features', array( $this, 'admin_coupon_options_extended_features' ), 20, 2 );
53
- add_action( 'woocommerce_process_shop_coupon_meta', array( $this, 'process_shop_coupon_meta' ), 10, 2 );
54
 
55
  //Inject columns
56
  if ( WJECF()->is_pro() ) {
@@ -77,7 +77,7 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
77
  * @param WP_Post The coupon post object
78
  */
79
  public function admin_render_shop_coupon_columns( $column, $post ) {
80
- $wrap_coupon = WJECF_Wrap( $post->ID );
81
 
82
  switch ( $column ) {
83
  case '_wjecf_auto_coupon' :
@@ -170,30 +170,33 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
170
 
171
  if (jQuery("#_wjecf_is_auto_coupon").prop('checked')) {
172
  jQuery("._wjecf_show_if_autocoupon").show( animation );
 
173
  } else {
174
  jQuery("._wjecf_show_if_autocoupon").hide( animation );
 
175
  }
176
  }
177
- update_wjecf_apply_silently_field( 0 );
178
-
179
- jQuery("#_wjecf_is_auto_coupon").click( update_wjecf_apply_silently_field );
 
 
180
  </script>
181
  <?php
182
 
183
  }
184
-
185
- public function process_shop_coupon_meta( $post_id, $post ) {
186
- $wrap_coupon = WJECF_Wrap( $post_id );
187
 
188
- $autocoupon = isset( $_POST['_wjecf_is_auto_coupon'] );
189
- $wrap_coupon->set_meta( '_wjecf_is_auto_coupon', $autocoupon ? 'yes' : 'no' );
190
- $wrap_coupon->set_meta( '_wjecf_apply_silently', isset( $_POST['_wjecf_apply_silently'] ) ? 'yes' : 'no' );
 
 
 
191
  if ( WJECF()->is_pro() ) {
192
- $wrap_coupon->set_meta( '_wjecf_coupon_priority', intval( $_POST['_wjecf_coupon_priority'] ) );
193
  }
194
-
195
- $wrap_coupon->save();
196
- }
197
 
198
  /* FRONTEND HOOKS */
199
 
@@ -257,9 +260,8 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
257
  */
258
  function coupon_label( $originaltext, $coupon ) {
259
 
260
- if ( $this->is_auto_coupon($coupon) ) {
261
-
262
- return $this->coupon_excerpt($coupon); //__($this->autocoupons[$coupon->code], 'woocommerce-jos-autocoupon');
263
  } else {
264
  return $originaltext;
265
  }
@@ -310,7 +312,7 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
310
  foreach ( $this->get_all_auto_coupons() as $coupon ) {
311
  $coupon_code = WJECF_Wrap( $coupon )->get_code();
312
  if ( WC()->cart->has_discount( $coupon_code ) && ! in_array( $coupon_code, $valid_coupon_codes ) ) {
313
- $this->log( sprintf( "Removing %s", $coupon_code ) );
314
  WC()->cart->remove_coupon( $coupon_code );
315
  $calc_needed = true;
316
  }
@@ -318,18 +320,14 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
318
  return $calc_needed;
319
  }
320
 
321
- private $update_matched_autocoupons_executed = false;
322
 
323
  /**
324
  * Apply matched autocoupons and remove unmatched autocoupons.
325
  * @return void
326
  */
327
  function update_matched_autocoupons() {
328
- if ( $this->update_matched_autocoupons_executed ) {
329
- return;
330
- }
331
- $this->update_matched_autocoupons_executed = true;
332
- $this->log( "()" );
333
 
334
  //2.3.3 Keep track of queued coupons and apply when they validate
335
  $queuer = WJECF()->get_plugin('WJECF_Pro_Coupon_Queueing');
@@ -346,7 +344,7 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
346
  $valid_coupon_codes[] = WJECF_Wrap( $coupon )->get_code();
347
  }
348
 
349
- $this->log( sprintf( "Auto coupons that should be in cart: %s", implode( ', ', $valid_coupon_codes ) ) );
350
 
351
  $calc_needed = $this->remove_unmatched_autocoupons( $valid_coupon_codes );
352
 
@@ -354,7 +352,7 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
354
  foreach( $valid_coupons as $coupon ) {
355
  $coupon_code = WJECF_Wrap( $coupon )->get_code();
356
  if ( ! WC()->cart->has_discount( $coupon_code ) ) {
357
- $this->log( sprintf( "Applying auto coupon %s", $coupon_code ) );
358
 
359
  $apply_silently = WJECF_Wrap( $coupon )->get_meta( '_wjecf_apply_silently' ) == 'yes';
360
 
@@ -377,7 +375,7 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
377
  }
378
  }
379
 
380
- $this->log( 'Coupons in cart: ' . implode( ', ', WC()->cart->applied_coupons ) . ($calc_needed ? ". RECALC" : "") );
381
 
382
  if ( $calc_needed ) {
383
  WC()->cart->calculate_totals();
@@ -438,7 +436,7 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
438
  global $woocommerce;
439
  foreach ( $woocommerce->cart->get_cart() as $cart_item ) {
440
  if ( $coupon->is_valid_for_cart() || $coupon->is_valid_for_product( $cart_item['data'], $cart_item ) ) {
441
- $has_a_value = true;
442
  break;
443
  }
444
  }
@@ -496,7 +494,7 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
496
  if ( isset( $_POST['billing_email'] ) )
497
  $this->_user_emails[] = $_POST['billing_email'];
498
  }
499
- //$this->log( "User emails: " . implode( ",", $this->_user_emails ) );
500
  return $this->_user_emails;
501
  }
502
 
@@ -511,7 +509,7 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
511
  $append_emails = array( $append_emails );
512
  }
513
  $this->_user_emails = array_unique( array_merge( $this->get_user_emails(), $append_emails ) );
514
- //$this->log('Append emails: ' . implode( ',', $append_emails ) );
515
  }
516
 
517
  public function fetch_billing_email( $post_data ) {
@@ -590,7 +588,7 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
590
  $coupon_codes[] = WJECF_Wrap( $coupon )->get_code();
591
  }
592
 
593
- $this->log( "Autocoupons: " . implode(", ", $coupon_codes ) );
594
  }
595
 
596
  return $this->_autocoupons;
@@ -605,9 +603,9 @@ class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
605
  private function sort_auto_coupons( $coupon_a, $coupon_b ) {
606
  $prio_a = $this->get_coupon_priority( $coupon_a );
607
  $prio_b = $this->get_coupon_priority( $coupon_b );
608
- $this->log("A: $prio_a B: $prio_b ");
609
  if ( $prio_a == $prio_b ) {
610
- return $a->code < $b->code ? -1 : 1; //By title ASC
611
  } else {
612
  return $prio_a > $prio_b ? -1 : 1; //By prio DESC
613
  }
25
 
26
  //Frontend hooks - logic
27
  if ( WJECF_WC()->check_woocommerce_version('2.3.0')) {
28
+ WJECF()->add_action_once( 'woocommerce_after_calculate_totals', array( $this, 'update_matched_autocoupons' ) );
29
  } else {
30
  //WC Versions prior to 2.3.0 don't have after_calculate_totals hook, this is a fallback
31
+ WJECF()->add_action_once( 'woocommerce_cart_updated', array( $this, 'update_matched_autocoupons' ) );
32
  }
33
+
34
+ add_action( 'woocommerce_check_cart_items', array( $this, 'remove_unmatched_autocoupons' ) , 0, 0 ); //Remove coupon before WC does it and shows a message
35
  //Last check for coupons with restricted_emails
36
+ add_action( 'woocommerce_checkout_update_order_review', array( $this, 'fetch_billing_email' ), 10 ); // AJAX One page checkout
37
 
38
  //Frontend hooks - visualisation
39
+ add_filter('woocommerce_cart_totals_coupon_label', array( $this, 'coupon_label' ), 10, 2 );
40
+ add_filter('woocommerce_cart_totals_coupon_html', array( $this, 'coupon_html' ), 10, 2 );
41
 
42
  //Inhibit redirect to cart when apply_coupon supplied
43
+ add_filter('option_woocommerce_cart_redirect_after_add', array ( $this, 'option_woocommerce_cart_redirect_after_add') );
44
 
45
  if ( ! is_ajax() ) {
46
  //Get cart should not be called before the wp_loaded action nor the add_to_cart_action (class-wc-form-handler)
51
  /* ADMIN HOOKS */
52
  public function init_admin_hook() {
53
  add_action( 'wjecf_woocommerce_coupon_options_extended_features', array( $this, 'admin_coupon_options_extended_features' ), 20, 2 );
 
54
 
55
  //Inject columns
56
  if ( WJECF()->is_pro() ) {
77
  * @param WP_Post The coupon post object
78
  */
79
  public function admin_render_shop_coupon_columns( $column, $post ) {
80
+ $wrap_coupon = WJECF_Wrap( intval( $post->ID ) );
81
 
82
  switch ( $column ) {
83
  case '_wjecf_auto_coupon' :
170
 
171
  if (jQuery("#_wjecf_is_auto_coupon").prop('checked')) {
172
  jQuery("._wjecf_show_if_autocoupon").show( animation );
173
+ jQuery("._wjecf_hide_if_autocoupon").hide( animation );
174
  } else {
175
  jQuery("._wjecf_show_if_autocoupon").hide( animation );
176
+ jQuery("._wjecf_hide_if_autocoupon").show( animation );
177
  }
178
  }
179
+
180
+ jQuery( function( $ ) {
181
+ update_wjecf_apply_silently_field( 0 );
182
+ $("#_wjecf_is_auto_coupon").click( update_wjecf_apply_silently_field );
183
+ } );
184
  </script>
185
  <?php
186
 
187
  }
 
 
 
188
 
189
+ public function admin_coupon_meta_fields( $coupon ) {
190
+ $fields = array(
191
+ '_wjecf_is_auto_coupon' => 'yesno',
192
+ '_wjecf_apply_silently' => 'yesno',
193
+ );
194
+
195
  if ( WJECF()->is_pro() ) {
196
+ $fields['_wjecf_coupon_priority'] = 'int';
197
  }
198
+ return $fields;
199
+ }
 
200
 
201
  /* FRONTEND HOOKS */
202
 
260
  */
261
  function coupon_label( $originaltext, $coupon ) {
262
 
263
+ if ( $this->is_auto_coupon($coupon) ) {
264
+ return $this->coupon_excerpt($coupon);
 
265
  } else {
266
  return $originaltext;
267
  }
312
  foreach ( $this->get_all_auto_coupons() as $coupon ) {
313
  $coupon_code = WJECF_Wrap( $coupon )->get_code();
314
  if ( WC()->cart->has_discount( $coupon_code ) && ! in_array( $coupon_code, $valid_coupon_codes ) ) {
315
+ $this->log( 'debug', sprintf( "Removing %s", $coupon_code ) );
316
  WC()->cart->remove_coupon( $coupon_code );
317
  $calc_needed = true;
318
  }
320
  return $calc_needed;
321
  }
322
 
 
323
 
324
  /**
325
  * Apply matched autocoupons and remove unmatched autocoupons.
326
  * @return void
327
  */
328
  function update_matched_autocoupons() {
329
+
330
+ $this->log( 'debug', "()" );
 
 
 
331
 
332
  //2.3.3 Keep track of queued coupons and apply when they validate
333
  $queuer = WJECF()->get_plugin('WJECF_Pro_Coupon_Queueing');
344
  $valid_coupon_codes[] = WJECF_Wrap( $coupon )->get_code();
345
  }
346
 
347
+ $this->log( 'debug', sprintf( "Auto coupons that should be in cart: %s", implode( ', ', $valid_coupon_codes ) ) );
348
 
349
  $calc_needed = $this->remove_unmatched_autocoupons( $valid_coupon_codes );
350
 
352
  foreach( $valid_coupons as $coupon ) {
353
  $coupon_code = WJECF_Wrap( $coupon )->get_code();
354
  if ( ! WC()->cart->has_discount( $coupon_code ) ) {
355
+ $this->log( 'debug', sprintf( "Applying auto coupon %s", $coupon_code ) );
356
 
357
  $apply_silently = WJECF_Wrap( $coupon )->get_meta( '_wjecf_apply_silently' ) == 'yes';
358
 
375
  }
376
  }
377
 
378
+ $this->log( 'debug', 'Coupons in cart: ' . implode( ', ', WC()->cart->applied_coupons ) . ($calc_needed ? ". RECALC" : "") );
379
 
380
  if ( $calc_needed ) {
381
  WC()->cart->calculate_totals();
436
  global $woocommerce;
437
  foreach ( $woocommerce->cart->get_cart() as $cart_item ) {
438
  if ( $coupon->is_valid_for_cart() || $coupon->is_valid_for_product( $cart_item['data'], $cart_item ) ) {
439
+ $has_a_value = WJECF_Wrap( $coupon )->get_amount() > 0;
440
  break;
441
  }
442
  }
494
  if ( isset( $_POST['billing_email'] ) )
495
  $this->_user_emails[] = $_POST['billing_email'];
496
  }
497
+ //$this->log( 'debug', "User emails: " . implode( ",", $this->_user_emails ) );
498
  return $this->_user_emails;
499
  }
500
 
509
  $append_emails = array( $append_emails );
510
  }
511
  $this->_user_emails = array_unique( array_merge( $this->get_user_emails(), $append_emails ) );
512
+ //$this->log( 'debug','Append emails: ' . implode( ',', $append_emails ) );
513
  }
514
 
515
  public function fetch_billing_email( $post_data ) {
588
  $coupon_codes[] = WJECF_Wrap( $coupon )->get_code();
589
  }
590
 
591
+ $this->log( 'debug', "Autocoupons: " . implode(", ", $coupon_codes ) );
592
  }
593
 
594
  return $this->_autocoupons;
603
  private function sort_auto_coupons( $coupon_a, $coupon_b ) {
604
  $prio_a = $this->get_coupon_priority( $coupon_a );
605
  $prio_b = $this->get_coupon_priority( $coupon_b );
606
+ //$this->log( 'debug', "A: $prio_a B: $prio_b " );
607
  if ( $prio_a == $prio_b ) {
608
+ return WJECF_Wrap( $coupon_a )->get_code() < WJECF_Wrap( $coupon_b )->get_code() ? -1 : 1; //By title ASC
609
  } else {
610
  return $prio_a > $prio_b ? -1 : 1; //By prio DESC
611
  }
includes/WJECF_Bootstrap.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined('ABSPATH') ) die();
4
+
5
+ /**
6
+ * Loads the plugin
7
+ */
8
+ class WJECF_Bootstrap {
9
+
10
+ public static function execute() {
11
+ self::instance()->bootstrap();
12
+ }
13
+
14
+ protected function bootstrap() {
15
+
16
+ $this->require_once_php( 'Abstract_WJECF_Plugin' );
17
+ $this->require_once_php( 'WJECF_Options' );
18
+ $this->require_once_php( 'WJECF_Sanitizer' );
19
+
20
+ $this->require_once_php( 'WJECF_Controller' );
21
+ $pro = $this->try_include_php( 'pro/WJECF_Pro_Controller' );
22
+ $this->require_once_php( 'WJECF_WC' );
23
+
24
+ $this->require_once_php( 'admin/WJECF_Admin_Html' );
25
+ $this->add_plugin('admin/WJECF_Admin');
26
+ $this->try_add_plugin('admin/WJECF_Admin_Data_Update');
27
+
28
+ $this->try_add_plugin('admin/WJECF_Admin_Settings');
29
+ $this->try_add_plugin('WJECF_AutoCoupon');
30
+ $this->try_add_plugin('WJECF_WPML');
31
+
32
+ if ( $pro ) {
33
+ $this->try_include_php( 'pro/WJECF_Pro_API' );
34
+ $this->try_add_plugin('pro/admin/WJECF_Pro_Admin_Auto_Update');
35
+
36
+ $this->try_add_plugin('pro/WJECF_Pro_Free_Products/WJECF_Pro_Free_Products');
37
+ $this->try_add_plugin('pro/WJECF_Pro_Coupon_Queueing');
38
+ $this->try_add_plugin('pro/WJECF_Pro_Product_Filter');
39
+ $this->try_add_plugin('pro/WJECF_Pro_Limit_Discount_Quantities');
40
+ }
41
+
42
+ WJECF()->start();
43
+
44
+ //WP-cli for debugging
45
+ if ( defined( 'WP_CLI' ) && WP_CLI ) {
46
+ if ( $this->try_include_php( 'WJECF_Debug_CLI' ) ) {
47
+ WJECF_Debug_CLI::add_command();
48
+ }
49
+ }
50
+
51
+ }
52
+
53
+ /**
54
+ * Singleton Instance
55
+ *
56
+ * @static
57
+ * @return Singleton Instance
58
+ */
59
+ public static function instance() {
60
+ if ( is_null( self::$_instance ) ) {
61
+ self::$_instance = new self();
62
+ }
63
+ return self::$_instance;
64
+ }
65
+ protected static $_instance = null;
66
+
67
+
68
+ /**
69
+ * require_once( $path + '.php' )
70
+ * @param string $path Path to the php file (excluding extension) relative to the current path
71
+ * @return bool True if succesful
72
+ */
73
+ protected function require_once_php( $path ) {
74
+ $fullpath = $this->get_path( $path ) . '.php';
75
+ require_once( $fullpath );
76
+ }
77
+
78
+ /**
79
+ * tries to include_once( $path + '.php' )
80
+ * @param string $path Path to the php file (excluding extension) relative to the current path
81
+ * @return bool True if succesful
82
+ */
83
+ protected function try_include_php( $path ) {
84
+ $fullpath = $this->get_path( $path ) . '.php';
85
+
86
+ if ( ! file_exists( $fullpath ) ) {
87
+ return false;
88
+ }
89
+
90
+ include_once( $fullpath );
91
+ return true;
92
+ }
93
+
94
+ /**
95
+ * Loads the class file and adds the plugin to WJECF(). Throws exception on failure.
96
+ * @param string $path Path to the php file (excluding extension) relative to the current path
97
+ * @return void
98
+ */
99
+ protected function add_plugin( $path ) {
100
+ $class_name = basename( $path );
101
+
102
+ $this->require_once_php( $path );
103
+
104
+ if ( ! WJECF()->add_plugin( $class_name ) ) {
105
+ throw new Exception( sprintf( 'Unable to add plugin %s', $class_name ) );
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Tries loading the class file and adding the plugin to WJECF().
111
+ * @param string $path Path to the php file (excluding extension) relative to the current path
112
+ * @return bool True if succesful
113
+ */
114
+ protected function try_add_plugin( $path ) {
115
+ $class_name = basename( $path );
116
+ return $this->try_include_php( $path ) && WJECF()->add_plugin( $class_name );
117
+ }
118
+
119
+ /**
120
+ * Gets the path relative to the includes/ directory
121
+ * @param string $path
122
+ * @return string
123
+ */
124
+ private function get_path( $path ) {
125
+ return plugin_dir_path( __FILE__ ) . $path;
126
+ }
127
+
128
+ }
includes/{wjecf-controller.php → WJECF_Controller.php} RENAMED
@@ -17,14 +17,7 @@ class WJECF_Controller {
17
  const E_WC_COUPON_PAYMENT_METHOD_NOT_MET = 79105;
18
  const E_WC_COUPON_NOT_FOR_THIS_USER = 79106;
19
 
20
- protected $debug_mode = false;
21
- protected $log = array();
22
- public $options = false;
23
-
24
- //Plugin data
25
- public $plugin_path; // Has trailing slash
26
- public $plugin_url; // Has trailing slash
27
- public $version; // Use for js
28
 
29
  /**
30
  * Singleton Instance
@@ -41,23 +34,19 @@ class WJECF_Controller {
41
  protected static $_instance = null;
42
 
43
 
44
- public function __construct() {
45
- $this->debug_mode = false && defined( 'WP_DEBUG' ) && WP_DEBUG;
46
- //Paths
47
- $this->plugin_path = plugin_dir_path( dirname(__FILE__) );
48
- $this->plugin_url = plugins_url( '/', dirname( __FILE__ ) );
49
-
50
- $filename = $this->is_pro() ? "woocommerce-jos-autocoupon-pro.php" : "woocommerce-jos-autocoupon.php" ;
51
-
52
- //Version
53
- $default_headers = array(
54
- 'Version' => 'Version',
55
  );
56
- $plugin_data = get_file_data( $this->plugin_path . $filename, $default_headers, 'plugin' );
57
- $this->version = $plugin_data['Version'];
58
  }
59
 
60
  public function start() {
 
61
  add_action('init', array( $this, 'init_hook' ));
62
  }
63
 
@@ -85,7 +74,7 @@ class WJECF_Controller {
85
  foreach( $plugin->get_plugin_dependencies() as $dependency_name ) {
86
  $dependency = $this->get_plugin( $dependency_name );
87
  if ( ! $dependency || ! $dependency->plugin_is_enabled() ) {
88
- error_log('Unable to initialize ' . $name . ' because it requires ' . $dependency_name );
89
  continue;
90
  }
91
  }
@@ -99,10 +88,7 @@ class WJECF_Controller {
99
  }
100
 
101
  public function controller_init() {
102
-
103
- $this->log( "INIT " . ( is_ajax() ? "AJAX" : is_admin() ? "ADMIN" : "FRONTEND" ) . " " . $_SERVER['REQUEST_URI'] );
104
-
105
- $this->init_options();
106
 
107
  //Frontend hooks
108
 
@@ -114,8 +100,9 @@ class WJECF_Controller {
114
  }
115
 
116
  add_filter('woocommerce_coupon_error', array( $this, 'woocommerce_coupon_error' ), 10, 3 );
117
- add_action('woocommerce_coupon_loaded', array( $this, 'woocommerce_coupon_loaded' ), 10, 1);
118
  add_filter('woocommerce_coupon_get_discount_amount', array( $this, 'woocommerce_coupon_get_discount_amount' ), 10, 5);
 
119
  add_action( 'wp_footer', array( $this, 'render_log' ) ); //Log
120
  }
121
 
@@ -132,13 +119,14 @@ class WJECF_Controller {
132
  }
133
 
134
  if ( ! class_exists( $class_name ) ) {
 
135
  return false; //Not found
136
  }
137
 
138
- $the_plugin = new $class_name();
139
- foreach( $the_plugin->get_plugin_dependencies() as $dependency ) {
140
  if ( ! class_exists( $dependency ) ) {
141
- $this->log( 'Unknown dependency: ' . $dependency . ' for plugin ' . $class_name );
142
  return false;
143
  }
144
 
@@ -146,25 +134,37 @@ class WJECF_Controller {
146
  continue; //dependency is al geladen
147
  }
148
 
149
- $this->add_plugin( $dependency );
150
  }
151
 
152
  //Assert dependencies
153
  try {
154
- $the_plugin->assert_dependencies();
155
  } catch (Exception $ex) {
156
- $msg = sprintf('Failed loading %s: %s', $class_name, $ex->getMessage() );
 
 
 
157
  if ( $wjecf_admin = WJECF()->get_plugin('WJECF_Admin') ) {
158
  $wjecf_admin->enqueue_notice( $msg, 'error' );
159
- } else {
160
  }
161
- error_log("PRINTR".print_r($wjecf_admin, true));
162
- error_log( $msg );
163
  return false;
164
  }
165
 
166
- $this->plugins[ $class_name ] = $the_plugin;
167
- $this->log( 'Loaded plugin: ' . $class_name );
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
  return true;
170
  }
@@ -184,13 +184,36 @@ class WJECF_Controller {
184
  } else {
185
  return false;
186
  }
187
- }
188
-
189
- public function init_options() {
190
- $this->options = get_option( 'wjecf_options' );
191
- if (false === $this->options) {
192
- $this->options = array( 'db_version' => 0 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  }
 
 
 
 
 
 
 
 
 
194
  }
195
 
196
  /* FRONTEND HOOKS */
@@ -204,17 +227,18 @@ class WJECF_Controller {
204
  echo '<div class="error"><p>' . $msg . '</p></div>';
205
  }
206
 
207
- //2.2.2
208
- public function woocommerce_coupon_loaded ( $coupon ) {
209
- if ( ! is_admin() ) {
210
- //2.2.2 Allow coupon even if minimum spend not reached
211
- if ( WJECF_Wrap( $coupon )->get_meta( '_wjecf_allow_below_minimum_spend' ) == 'yes' ) {
212
- //HACK: Overwrite the minimum amount with 0 so WooCommerce will allow the coupon
213
- $coupon->wjecf_minimum_amount_for_discount = WJECF_Wrap( $coupon )->get_minimum_amount();
214
- $coupon->minimum_amount = 0;
215
- }
216
- }
217
- }
 
218
 
219
  //2.2.2
220
  public function woocommerce_coupon_get_discount_amount ( $discount, $discounting_amount, $cart_item, $single, $coupon ) {
@@ -334,7 +358,7 @@ class WJECF_Controller {
334
  //check if every single category is in the cart
335
  foreach( apply_filters( 'wjecf_get_product_cat_ids', $wrap_coupon->get_product_categories() ) as $cat_id ) {
336
  if ( ! in_array( $cat_id, $cart_product_cats ) ) {
337
- $this->log( $cat_id . " is not in " . print_r($cart_product_cats, true));
338
  throw new Exception( WC_Coupon::E_WC_COUPON_NOT_APPLICABLE );
339
  }
340
  }
@@ -522,17 +546,18 @@ class WJECF_Controller {
522
  return false;
523
  }
524
 
525
- if ( ! $coupon->is_type( WJECF_WC()->wc_get_cart_coupon_types() ) ) {
526
- return $coupon->is_valid_for_product( $product, $values );
527
- }
528
 
529
  //$coupon->is_valid_for_product() only works for fixed_product or percent_product discounts
530
- //It's not, so we create a temporary duplicate
531
- $duplicate_coupon = WJECF_WC()->get_coupon( WJECF_Wrap( $coupon )->get_code() );
532
- WJECF_Wrap( $duplicate_coupon )->set_discount_type( 'fixed_product' );
533
- return $duplicate_coupon->is_valid_for_product( $product, $values );
534
- }
535
 
 
 
 
 
536
 
537
 
538
  // =====================
@@ -544,11 +569,7 @@ class WJECF_Controller {
544
  */
545
  public function get_coupon_shipping_method_ids( $coupon ) {
546
  $v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_shipping_methods' );
547
- if ($v == '') {
548
- $v = array();
549
- }
550
-
551
- return $v;
552
  }
553
 
554
  /**
@@ -558,11 +579,7 @@ class WJECF_Controller {
558
  */
559
  public function get_coupon_payment_method_ids( $coupon ) {
560
  $v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_payment_methods' );
561
- if ($v == '') {
562
- $v = array();
563
- }
564
-
565
- return $v;
566
  }
567
 
568
  /**
@@ -572,14 +589,7 @@ class WJECF_Controller {
572
  */
573
  public function get_coupon_customer_ids( $coupon ) {
574
  $v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_customer_ids' );
575
-
576
- if ($v == '') {
577
- $v = array();
578
- } else {
579
- $v = array_map( 'intval', explode(",", $v ) );
580
- }
581
-
582
- return $v;
583
  }
584
 
585
  /**
@@ -589,11 +599,7 @@ class WJECF_Controller {
589
  */
590
  public function get_coupon_customer_roles( $coupon ) {
591
  $v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_customer_roles' );
592
- if ($v == '') {
593
- $v = array();
594
- }
595
-
596
- return $v;
597
  }
598
 
599
  /**
@@ -603,11 +609,7 @@ class WJECF_Controller {
603
  */
604
  public function get_coupon_excluded_customer_roles( $coupon ) {
605
  $v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_excluded_customer_roles' );
606
- if ($v == '') {
607
- $v = array();
608
- }
609
-
610
- return $v;
611
  }
612
 
613
  public function is_pro() {
@@ -651,6 +653,37 @@ class WJECF_Controller {
651
  // END - OVERWRITE INFO MESSAGES
652
  // ===========================================================================
653
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
654
 
655
  private $_session_data = null;
656
  /**
@@ -688,19 +721,20 @@ class WJECF_Controller {
688
 
689
  /**
690
  * Get overwritable template filename
 
 
691
  * @param string $template_name
692
  * @return string Template filename
693
  */
694
  public function get_template_filename( $template_name ) {
695
  $template_path = 'woocommerce-auto-added-coupons';
696
 
697
- $plugin_template_path = plugin_dir_path( dirname(__FILE__) ) . 'templates/';
698
-
699
  //Get template overwritten file
700
  $template = locate_template( trailingslashit( $template_path ) . $template_name );
701
 
702
  // Get default template
703
  if ( ! $template ) {
 
704
  $template = $plugin_template_path . $template_name;
705
  }
706
 
@@ -716,50 +750,166 @@ class WJECF_Controller {
716
  extract( $variables );
717
  include( $this->get_template_filename( $template_name ) );
718
  }
719
-
 
 
 
 
720
  /**
721
- * Log message for debugging
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
722
  * @param string $string The message to log
723
  * @param int $skip_backtrace Defaults to 0, amount of items to skip in backtrace to fetch class and method name
724
  */
725
- public function log( $string, $skip_backtrace = 0) {
726
- if ( $this->debug_mode ) {
727
- $nth = 1 + $skip_backtrace;
728
- $bt = debug_backtrace();
729
- $class = $bt[$nth]['class'];
730
- $function = $bt[$nth]['function'];
731
-
732
- $row = array(
733
- 'time' => time(),
734
- 'class' => $class,
735
- 'function' => $function,
736
- 'filter' => current_filter(),
737
- 'message' => $string,
738
- );
739
- $this->log[] = $row;
740
- error_log( $row['filter'] . ' ' . $row['class'] . '::' . $row['function'] . ' ' . $row['message'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
741
  }
 
 
 
 
 
 
742
  }
743
 
744
  /**
745
  * Output the log as html
746
  */
747
  public function render_log() {
748
- if ( $this->debug_mode && current_user_can( 'manage_options' ) && defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG_DISPLAY ) {
749
- echo "<table class='soft79_wjecf_log'>";
750
- foreach( $this->log as $row ) {
751
- $cells = array(
752
- date("H:i:s", $row['time']),
753
- esc_html( $row['filter'] ),
754
- esc_html( $row['class'] . '::' . $row['function'] ),
755
- esc_html( $row['message'] ),
756
- );
757
- echo "<tr><td>" . implode( "</td><td>", $cells ) . "</td></tr>";
758
- }
759
- $colspan = isset( $cells ) ? count( $cells ) : 1;
760
- echo "<tr><td colspan='" . $colspan . "'>Current coupons in cart: " . implode( ", ", WC()->cart->applied_coupons ) . "</td></tr>";
761
- echo "</table>";
 
 
762
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
763
  }
764
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
765
  }
17
  const E_WC_COUPON_PAYMENT_METHOD_NOT_MET = 79105;
18
  const E_WC_COUPON_NOT_FOR_THIS_USER = 79106;
19
 
20
+ private $options = null;
 
 
 
 
 
 
 
21
 
22
  /**
23
  * Singleton Instance
34
  protected static $_instance = null;
35
 
36
 
37
+ public function __construct() {
38
+ $this->options = new WJECF_Options(
39
+ 'wjecf_options',
40
+ array(
41
+ 'db_version' => 0, // integer
42
+ 'debug_mode' => false, // true or false
43
+ 'disabled_plugins' => array() // e.g. [ 'WJECF_AutoCoupon' ]
44
+ )
 
 
 
45
  );
 
 
46
  }
47
 
48
  public function start() {
49
+ $this->debug_mode = $this->get_option('debug_mode'); // && defined( 'WP_DEBUG' ) && WP_DEBUG;
50
  add_action('init', array( $this, 'init_hook' ));
51
  }
52
 
74
  foreach( $plugin->get_plugin_dependencies() as $dependency_name ) {
75
  $dependency = $this->get_plugin( $dependency_name );
76
  if ( ! $dependency || ! $dependency->plugin_is_enabled() ) {
77
+ $this->log( 'error', 'Unable to initialize ' . $name . ' because it requires ' . $dependency_name );
78
  continue;
79
  }
80
  }
88
  }
89
 
90
  public function controller_init() {
91
+ $this->log( 'debug', "INIT " . ( is_ajax() ? "AJAX" : is_admin() ? "ADMIN" : "FRONTEND" ) . " " . $_SERVER['REQUEST_URI'] );
 
 
 
92
 
93
  //Frontend hooks
94
 
100
  }
101
 
102
  add_filter('woocommerce_coupon_error', array( $this, 'woocommerce_coupon_error' ), 10, 3 );
103
+ //REMOVED IN 2.4.4: add_action('woocommerce_coupon_loaded', array( $this, 'woocommerce_coupon_loaded' ), 10, 1);
104
  add_filter('woocommerce_coupon_get_discount_amount', array( $this, 'woocommerce_coupon_get_discount_amount' ), 10, 5);
105
+
106
  add_action( 'wp_footer', array( $this, 'render_log' ) ); //Log
107
  }
108
 
119
  }
120
 
121
  if ( ! class_exists( $class_name ) ) {
122
+ $this->log( 'warning', 'Unknown plugin: ' . $class_name );
123
  return false; //Not found
124
  }
125
 
126
+ $plugin = new $class_name();
127
+ foreach( $plugin->get_plugin_dependencies() as $dependency ) {
128
  if ( ! class_exists( $dependency ) ) {
129
+ $this->log( 'warning', 'Unknown dependency: ' . $dependency . ' for plugin ' . $class_name );
130
  return false;
131
  }
132
 
134
  continue; //dependency is al geladen
135
  }
136
 
137
+ $this->add_plugin( $dependency );
138
  }
139
 
140
  //Assert dependencies
141
  try {
142
+ $plugin->assert_dependencies();
143
  } catch (Exception $ex) {
144
+ $msg = sprintf('Failed loading %s. %s', $class_name, $ex->getMessage() );
145
+
146
+ $this->log( 'error', $msg );
147
+
148
  if ( $wjecf_admin = WJECF()->get_plugin('WJECF_Admin') ) {
149
  $wjecf_admin->enqueue_notice( $msg, 'error' );
 
150
  }
 
 
151
  return false;
152
  }
153
 
154
+
155
+ $this->plugins[ $class_name ] = $plugin;
156
+ $this->log( 'debug', 'Loaded plugin: ' . $class_name );
157
+
158
+ return true;
159
+ }
160
+
161
+
162
+ /**
163
+ * Description
164
+ * @param type $plugin
165
+ * @return bool true if succesful
166
+ */
167
+ private function load_dependencies( $plugin ) {
168
 
169
  return true;
170
  }
184
  } else {
185
  return false;
186
  }
187
+ }
188
+
189
+ /* OPTIONS */
190
+
191
+ public function get_options() {
192
+ return $this->options->get();
193
+ }
194
+
195
+ public function get_option( $key, $default = null ) {
196
+ return $this->options->get( $key, $default );
197
+ }
198
+
199
+ public function set_option( $key, $value ) {
200
+ $this->options->set( $key, $value );
201
+ }
202
+
203
+ public function save_options() {
204
+ if ( ! is_admin() ) {
205
+ $this->log( 'error', 'WJECF Options must only be saved from admin.' );
206
+ return;
207
  }
208
+ $this->options->save();
209
+ }
210
+
211
+ public function sanitizer() {
212
+ return WJECF_Sanitizer::instance();
213
+ }
214
+
215
+ public function add_action_once( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
216
+ WJECF_Hook_Once::action( $tag, $function_to_add, $priority, $accepted_args );
217
  }
218
 
219
  /* FRONTEND HOOKS */
227
  echo '<div class="error"><p>' . $msg . '</p></div>';
228
  }
229
 
230
+ //REMOVED IN 2.4.4: Use coupon queueing instead:
231
+ // //2.2.2
232
+ // public function woocommerce_coupon_loaded ( $coupon ) {
233
+ // if ( $this->allow_overwrite_coupon_values() ) {
234
+ // //2.2.2 Allow coupon even if minimum spend not reached
235
+ // if ( WJECF_Wrap( $coupon )->get_meta( '_wjecf_allow_below_minimum_spend' ) == 'yes' ) {
236
+ // //HACK: Overwrite the minimum amount with 0 so WooCommerce will allow the coupon
237
+ // $coupon->wjecf_minimum_amount_for_discount = WJECF_Wrap( $coupon )->get_minimum_amount();
238
+ // $coupon->minimum_amount = 0;
239
+ // }
240
+ // }
241
+ // }
242
 
243
  //2.2.2
244
  public function woocommerce_coupon_get_discount_amount ( $discount, $discounting_amount, $cart_item, $single, $coupon ) {
358
  //check if every single category is in the cart
359
  foreach( apply_filters( 'wjecf_get_product_cat_ids', $wrap_coupon->get_product_categories() ) as $cat_id ) {
360
  if ( ! in_array( $cat_id, $cart_product_cats ) ) {
361
+ $this->log( 'debug', $cat_id . " is not in " . print_r($cart_product_cats, true));
362
  throw new Exception( WC_Coupon::E_WC_COUPON_NOT_APPLICABLE );
363
  }
364
  }
546
  return false;
547
  }
548
 
549
+ //Get the original coupon, without values overwritten by WJECF
550
+ $duplicate_coupon = $this->get_original_coupon( $coupon );
 
551
 
552
  //$coupon->is_valid_for_product() only works for fixed_product or percent_product discounts
553
+ if ( ! $duplicate_coupon->is_type( WJECF_WC()->wc_get_product_coupon_types() ) ) {
554
+ WJECF_Wrap( $duplicate_coupon )->set_discount_type( 'fixed_product' );
555
+ }
 
 
556
 
557
+ $valid = $duplicate_coupon->is_valid_for_product( $product, $values );
558
+ //$this->log( sprintf("%s valid for %s? %s", WJECF_Wrap( $coupon )->get_code(), WJECF_Wrap( $product )->get_name(), $valid ? 'yes':'no' ) );
559
+ return $valid;
560
+ }
561
 
562
 
563
  // =====================
569
  */
570
  public function get_coupon_shipping_method_ids( $coupon ) {
571
  $v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_shipping_methods' );
572
+ return is_array( $v ) ? $v : array();
 
 
 
 
573
  }
574
 
575
  /**
579
  */
580
  public function get_coupon_payment_method_ids( $coupon ) {
581
  $v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_payment_methods' );
582
+ return is_array( $v ) ? $v : array();
 
 
 
 
583
  }
584
 
585
  /**
589
  */
590
  public function get_coupon_customer_ids( $coupon ) {
591
  $v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_customer_ids' );
592
+ return WJECF()->sanitizer()->sanitize( $v, 'int[]' );
 
 
 
 
 
 
 
593
  }
594
 
595
  /**
599
  */
600
  public function get_coupon_customer_roles( $coupon ) {
601
  $v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_customer_roles' );
602
+ return is_array( $v ) ? $v : array();
 
 
 
 
603
  }
604
 
605
  /**
609
  */
610
  public function get_coupon_excluded_customer_roles( $coupon ) {
611
  $v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_excluded_customer_roles' );
612
+ return is_array( $v ) ? $v : array();
 
 
 
 
613
  }
614
 
615
  public function is_pro() {
653
  // END - OVERWRITE INFO MESSAGES
654
  // ===========================================================================
655
 
656
+ /**
657
+ * @since 2.4.4
658
+ *
659
+ * Get a coupon, but inhibit the woocommerce_coupon_loaded to overwrite values.
660
+ * @param WC_Coupon|string $coupon The coupon code or a WC_Coupon object
661
+ * @return WC_Coupon The coupon object
662
+ */
663
+ public function get_original_coupon( $coupon ) {
664
+ //Prevent returning the same instance
665
+ if ( $coupon instanceof WC_Coupon ) {
666
+ $coupon = WJECF_Wrap( $coupon )->get_code();
667
+ }
668
+ $this->inhibit_overwrite++;
669
+ $coupon = WJECF_WC()->get_coupon( $coupon );
670
+ $this->inhibit_overwrite--;
671
+ return $coupon;
672
+ }
673
+
674
+ private $inhibit_overwrite = 0;
675
+
676
+ /**
677
+ * @since 2.4.4
678
+ *
679
+ * May coupon values be overwritten by this plugin upon load?
680
+ * @return bool
681
+ */
682
+ public function allow_overwrite_coupon_values() {
683
+ return ( $this->inhibit_overwrite == 0 ) && ! is_admin();
684
+ }
685
+
686
+ //============
687
 
688
  private $_session_data = null;
689
  /**
721
 
722
  /**
723
  * Get overwritable template filename
724
+ *
725
+ * Template can be overwritten in wp-content/themes/YOUR_THEME/woocommerce-auto-added-coupons/
726
  * @param string $template_name
727
  * @return string Template filename
728
  */
729
  public function get_template_filename( $template_name ) {
730
  $template_path = 'woocommerce-auto-added-coupons';
731
 
 
 
732
  //Get template overwritten file
733
  $template = locate_template( trailingslashit( $template_path ) . $template_name );
734
 
735
  // Get default template
736
  if ( ! $template ) {
737
+ $plugin_template_path = plugin_dir_path( dirname(__FILE__) ) . 'templates/';
738
  $template = $plugin_template_path . $template_name;
739
  }
740
 
750
  extract( $variables );
751
  include( $this->get_template_filename( $template_name ) );
752
  }
753
+
754
+ // ========================
755
+ // INFO ABOUT WJECF PLUGIN
756
+ // ========================
757
+
758
  /**
759
+ * Filename of this plugin including the containing directory.
760
+ * @return string
761
+ */
762
+ public function plugin_file() {
763
+ $filename = $this->is_pro() ? "woocommerce-jos-autocoupon-pro.php" : "woocommerce-jos-autocoupon.php" ;
764
+ return trailingslashit( basename( dirname( dirname( __FILE__ ) ) ) ) . $filename;
765
+ }
766
+
767
+ /**
768
+ * url to the base directory of this plugin (wp-content/woocommerce-jos-autocoupon/) with trailing slash
769
+ * @return string
770
+ */
771
+ public function plugin_url( $suffix = '' ) {
772
+ return plugins_url( '/', dirname( __FILE__ ) ) . $suffix;
773
+ }
774
+
775
+ public function plugin_version() {
776
+ return WJECF_VERSION;
777
+ // //Version
778
+ //$plugin_path = plugin_dir_path( dirname( __FILE__ ) ); //Has trailing slash
779
+ // $default_headers = array(
780
+ // 'Version' => 'Version',
781
+ // );
782
+ // $plugin_data = get_file_data( $plugin_path . $filename, $default_headers, 'plugin' );
783
+ // return $plugin_data['Version'];
784
+ }
785
+
786
+ // ========================
787
+ // LOGGING
788
+ // ========================
789
+
790
+ private $debug_mode = false;
791
+ private $log_output = array();
792
+
793
+ /**
794
+ * Log a message for debugging.
795
+ *
796
+ * If debug_mode is false; messages with level 'debug' will be ignored.
797
+ *
798
+ * @param string $level The level of the message. e.g. 'debug' or 'warning'
799
  * @param string $string The message to log
800
  * @param int $skip_backtrace Defaults to 0, amount of items to skip in backtrace to fetch class and method name
801
  */
802
+ public function log( $level, $message = null, $skip_backtrace = 0) {
803
+ if ( ! $this->debug_mode && $level === 'debug' ) return;
804
+
805
+ //Backwards compatibility; $level was introduced in 2.4.4
806
+ if ( $message == null ) {
807
+ $message = $level;
808
+ $level = 'debug';
809
+ } else if ( is_int( $message ) && ! $this->is_valid_log_level( $level ) ) {
810
+ $skip_backtrace = $message;
811
+ $message = $level;
812
+ $level = 'debug';
813
+ }
814
+
815
+ if ( ! $this->debug_mode && $level === 'debug' ) return;
816
+
817
+ $nth = 1 + $skip_backtrace;
818
+ $bt = debug_backtrace();
819
+ $class = $bt[$nth]['class'];
820
+ $function = $bt[$nth]['function'];
821
+
822
+ $row = array(
823
+ 'level' => $level,
824
+ 'time' => time(),
825
+ 'class' => $class,
826
+ 'function' => $function,
827
+ 'filter' => current_filter(),
828
+ 'message' => $message,
829
+ );
830
+
831
+ $nice_str = $row['filter'] . ' ' . $row['class'] . '::' . $row['function'] . ' ' . $row['message'];
832
+
833
+ //Since WC2.7
834
+ if ( function_exists( 'wc_get_logger' ) ) {
835
+ $logger = wc_get_logger();
836
+ $context = array( 'source' => 'WooCommerce Extended Coupon Features' );
837
+ $logger->log( $level, $nice_str, $context );
838
+ } else {
839
+ //Legacy
840
+ error_log( $level . ': ' . $nice_str );
841
  }
842
+
843
+ $this->log_output[] = $row;
844
+ }
845
+
846
+ private function is_valid_log_level( $level ) {
847
+ return in_array( $level, array( 'debug', 'informational', 'notice', 'warning', 'error', 'critical', 'alert', 'emergency' ) );
848
  }
849
 
850
  /**
851
  * Output the log as html
852
  */
853
  public function render_log() {
854
+ if ( ! $this->debug_mode ) return;
855
+ if ( ! current_user_can( 'manage_options' ) ) return;
856
+ //if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) return;
857
+ //if ( ! defined( 'WP_DEBUG_DISPLAY' ) || ! WP_DEBUG_DISPLAY ) return;
858
+ if ( empty ( $this->log_output ) ) return;
859
+
860
+ echo "<table class='soft79_wjecf_log'>";
861
+ foreach( $this->log_output as $row ) {
862
+ $cells = array(
863
+ date("H:i:s", $row['time']),
864
+ esc_html( $row['level'] ),
865
+ esc_html( $row['filter'] ),
866
+ esc_html( $row['class'] . '::' . $row['function'] ),
867
+ esc_html( $row['message'] ),
868
+ );
869
+ echo "<tr><td>" . implode( "</td><td>", $cells ) . "</td></tr>";
870
  }
871
+ $colspan = isset( $cells ) ? count( $cells ) : 1;
872
+ echo "<tr><td colspan='" . $colspan . "'>Current coupons in cart: " . implode( ", ", WC()->cart->applied_coupons ) . "</td></tr>";
873
+ echo "</table>";
874
+ }
875
+
876
+ }
877
+
878
+ /**
879
+ * Class that allows an action or filter to be executed only once
880
+ */
881
+ class WJECF_Hook_Once {
882
+
883
+ private $tag;
884
+ private $function_to_add;
885
+ private $priority;
886
+ private $accepted_args;
887
+
888
+ private function __construct( $tag, $function_to_add, $priority, $accepted_args ) {
889
+ $this->tag = $tag;
890
+ $this->function_to_add = $function_to_add;
891
+ $this->priority = $priority;
892
+ $this->accepted_args = $accepted_args;
893
  }
894
 
895
+ //Must be public for WC
896
+ public function execute() {
897
+ remove_action( $this->tag, array( $this, 'execute' ), $this->priority ); //unhook the action
898
+
899
+ $args = func_get_args();
900
+ $retval = call_user_func_array( $this->function_to_add, $args );
901
+ return $retval;
902
+ }
903
+
904
+ /**
905
+ * Same as WordPress add_action(), but ensures the callback is triggered only once
906
+ * @param string $tag
907
+ * @param callable $function_to_add
908
+ * @param int $priority
909
+ * @param int $accepted_args
910
+ */
911
+ public static function action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
912
+ $me = new WJECF_Hook_Once( $tag, $function_to_add, $priority, $accepted_args );
913
+ add_action( $tag, array( $me, 'execute' ), $priority, $accepted_args );
914
+ }
915
  }
includes/WJECF_Debug_CLI.php CHANGED
@@ -4,13 +4,84 @@ defined('ABSPATH') or die();
4
 
5
  class WJECF_Debug_CLI extends WP_CLI_Command {
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  /**
8
- * Display some debugging information
9
  */
10
- public function debug() {
11
- WP_CLI::log( sprintf("WJECF Version: %s", WJECF()->version ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
- $coupon = WJECF_WC()->get_coupon('auto-cheapest-item');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  $args = array(
16
  'posts_per_page' => -1,
@@ -38,6 +109,12 @@ class WJECF_Debug_CLI extends WP_CLI_Command {
38
  $this->execute_test_for_product( $product );
39
  }
40
 
 
 
 
 
 
 
41
  }
42
 
43
  protected function execute_test_for_coupon( $coupon ) {
@@ -81,7 +158,7 @@ class WJECF_Debug_CLI extends WP_CLI_Command {
81
  $results = array();
82
  $results['new'] = $wrap_new->get_product_or_variation_id();
83
  $results['legacy'] = $wrap_leg->get_product_or_variation_id();
84
- $results['old'] = $product->variation_id;
85
  $this->assert_same( $results, sprintf('Same variation id %s', current( $results ) ) );
86
 
87
  $results = array();
@@ -101,6 +178,18 @@ class WJECF_Debug_CLI extends WP_CLI_Command {
101
 
102
  }
103
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  protected function assert_same( $results, $test_description ) {
105
  $success = true;
106
  foreach( $results as $result ) {
@@ -111,9 +200,13 @@ class WJECF_Debug_CLI extends WP_CLI_Command {
111
  $prev_result = $result;
112
  }
113
 
 
 
114
  if ( $success ) {
 
115
  WP_CLI::success( $test_description );
116
  } else {
 
117
  foreach( $results as $key => $result ) {
118
  WP_CLI::log( sprintf("%s : %s", $key, $this->dd( $result ) ) );
119
  }
@@ -125,17 +218,4 @@ class WJECF_Debug_CLI extends WP_CLI_Command {
125
  return print_r( $variable, true );
126
  }
127
 
128
-
129
- // /**
130
- // * Display expiry information for the given product.
131
- // *
132
- // * ## OPTIONS
133
- // *
134
- // * <product_id>...
135
- // * : The product ID.
136
- // *
137
- // */
138
- // public function product( $args ) {
139
- // }
140
-
141
  }
4
 
5
  class WJECF_Debug_CLI extends WP_CLI_Command {
6
 
7
+ public static function add_command() {
8
+ if ( defined( 'WP_CLI' ) && WP_CLI ) {
9
+ WP_CLI::add_command( 'wjecf', __CLASS__ );
10
+ }
11
+ }
12
+
13
+ public function plugin_info() {
14
+ WP_CLI::log( sprintf("WJECF Version: %s", WJECF()->plugin_version() ) );
15
+ WP_CLI::log( sprintf("WJECF File: %s", WJECF()->plugin_file() ) );
16
+ WP_CLI::log( sprintf("WJECF Url: %s", WJECF()->plugin_url() ) );
17
+
18
+ }
19
+
20
+ public function test_api( $args ) {
21
+ require_once( 'pro/wjecf-pro-api-example.php' );
22
+
23
+ if ( count( $args ) > 0 ) {
24
+ $all = $args;
25
+ } else {
26
+ $all = WJECF_API()->get_all_auto_coupons();
27
+ }
28
+
29
+ foreach( $all as $coupon ) {
30
+ $values = WJECF_API_Test_Coupon( $coupon );
31
+ foreach( $values as $key => $value ) {
32
+ WP_CLI::log( sprintf( "%s: %s", $key, print_r( $value, true ) ) );
33
+ }
34
+ }
35
+ }
36
+
37
  /**
38
+ * Test the sanitizers
39
  */
40
+ public function test_sanitizer() {
41
+ $array_tests = array(
42
+ array(),
43
+ array(0),
44
+ array(1,0,2.0,"3")
45
+ );
46
+ foreach( $array_tests as $array ) {
47
+ $comma = join( ',', $array );
48
+ $ints_array = array_map( 'intval', $array);
49
+ $ints_comma = join( ',', $ints_array );
50
+
51
+ $this->single_test_sanitizer( $comma, 'int[]', $ints_array );
52
+ $this->single_test_sanitizer( $array, 'int[]', $ints_array );
53
+
54
+ $this->single_test_sanitizer( $comma, 'int,', $ints_comma );
55
+ $this->single_test_sanitizer( $array, 'int,', $ints_comma );
56
+ }
57
+
58
+ $this->single_test_sanitizer( null, 'int[]', array() );
59
 
60
+ $this->single_test_sanitizer( null, 'int,', '' );
61
+ $this->single_test_sanitizer( '', 'int,', '' );
62
+
63
+ $this->single_test_sanitizer( null, 'int', null );
64
+ $this->single_test_sanitizer( '', 'int', null );
65
+ $this->single_test_sanitizer( '1.234', 'int', 1 );
66
+
67
+ $this->single_test_sanitizer( '1.234', 'decimal', '1.234' );
68
+ $this->single_test_sanitizer( null, 'decimal', null );
69
+ }
70
+
71
+ private function single_test_sanitizer( $value, $rule, $expected ) {
72
+ //$msg = sprintf( "Sanitized %s: %s to %s", $rule, print_r( $value, true ), print_r( $expected, true ) );
73
+ $msg = sprintf(
74
+ "Sanitized %s: %s to %s",
75
+ $rule, $value === null ? 'null' : $value,
76
+ $expected === null ? 'null' : $expected
77
+ );
78
+ $this->assert( WJECF()->sanitizer()->sanitize( $value, $rule ) === $expected, $msg);
79
+
80
+ }
81
+ /**
82
+ * Tests if the wrappers return the same values for WooCommerce 3.0 and older WC versions
83
+ */
84
+ public function test_wrappers() {
85
 
86
  $args = array(
87
  'posts_per_page' => -1,
109
  $this->execute_test_for_product( $product );
110
  }
111
 
112
+ $msg = sprintf("%d tests executed. Fails: %d Passes: %d", $this->tests, $this->fails, $this->passes );
113
+ if ( $this->fails != 0 )
114
+ WP_CLI::error( $msg );
115
+ else
116
+ WP_CLI::success( $msg );
117
+
118
  }
119
 
120
  protected function execute_test_for_coupon( $coupon ) {
158
  $results = array();
159
  $results['new'] = $wrap_new->get_product_or_variation_id();
160
  $results['legacy'] = $wrap_leg->get_product_or_variation_id();
161
+ $results['old'] = $product->variation_id;
162
  $this->assert_same( $results, sprintf('Same variation id %s', current( $results ) ) );
163
 
164
  $results = array();
178
 
179
  }
180
 
181
+ protected $tests = 0;
182
+ protected $fails = 0;
183
+ protected $passess = 0;
184
+
185
+ protected function assert( $true, $test_description ) {
186
+ if ( $true !== true ) {
187
+ WP_CLI::error( $test_description );
188
+ die();
189
+ }
190
+ WP_CLI::success( $test_description );
191
+ }
192
+
193
  protected function assert_same( $results, $test_description ) {
194
  $success = true;
195
  foreach( $results as $result ) {
200
  $prev_result = $result;
201
  }
202
 
203
+ $this->tests++;
204
+
205
  if ( $success ) {
206
+ $this->passes++;
207
  WP_CLI::success( $test_description );
208
  } else {
209
+ $this->fails++;
210
  foreach( $results as $key => $result ) {
211
  WP_CLI::log( sprintf("%s : %s", $key, $this->dd( $result ) ) );
212
  }
218
  return print_r( $variable, true );
219
  }
220
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  }
includes/WJECF_Options.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ /**
5
+ * Manages an Array of values that can be saved in the WP options table
6
+ */
7
+ class WJECF_Options {
8
+
9
+ private $options = null; // [ 'key' => 'value' ]
10
+ private $defaults = array(); // [ 'key' => 'value' ]
11
+
12
+ private $option_name;
13
+
14
+ /**
15
+ * Description
16
+ * @param string $option_name
17
+ * @param array $defaults Default values
18
+ * @param bool $auto_reload_on_save If true, the options shall be reloaded after safe
19
+ * @return type
20
+ */
21
+ public function __construct( $option_name, $defaults = array(), $auto_reload_on_save = true ) {
22
+ $this->option_name = $option_name;
23
+ $this->defaults = $defaults;
24
+
25
+ if ( $auto_reload_on_save ) {
26
+ //reload options directly after save
27
+ add_action( 'update_option_' . $option_name, array( $this, 'invalidate' ), 1, 0 );
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Forces reloading of the options; invalidates the current values
33
+ * @return void
34
+ */
35
+ public function invalidate() {
36
+ $this->options = null;
37
+ }
38
+
39
+ /**
40
+ * The option_name used in the WP options table
41
+ * @return string
42
+ */
43
+ public function get_option_name() {
44
+ return $this->option_name;
45
+ }
46
+
47
+ /**
48
+ * Loads the options from the database
49
+ * @return void
50
+ */
51
+ protected function load_options() {
52
+ $options = get_option( $this->option_name );
53
+ if (false === $options) {
54
+ $this->options = $this->defaults;
55
+ } else {
56
+ $this->options = array_merge( $this->defaults, $options );
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Get option [ $key ]. If $key is not given, return all options.
62
+ * @param string $key
63
+ * @param mixed $default The default value to return (only if $key is given)
64
+ * @return mixed The value of the option
65
+ */
66
+ public function get( $key = null, $default = null ) {
67
+ if ( ! isset( $this->options ) ) {
68
+ $this->load_options();
69
+ }
70
+
71
+ //Return all options
72
+ if ( is_null( $key ) ) {
73
+ return $this->options;
74
+ }
75
+
76
+ //Return option[$key]
77
+ $value = isset( $this->options[$key] ) ? $this->options[$key] : $default;
78
+ return $value;
79
+ }
80
+
81
+ /**
82
+ * Set option [ $key ]
83
+ * @param string $key
84
+ * @param mixed $value
85
+ */
86
+ public function set( $key, $value ) {
87
+ if ( ! isset( $this->options ) ) {
88
+ $this->load_options();
89
+ }
90
+ $this->options[$key] = $value;
91
+ }
92
+
93
+ /**
94
+ * Save options to the database
95
+ */
96
+ public function save() {
97
+ update_option( $this->option_name , $this->options, false );
98
+ }
99
+ }
includes/WJECF_Sanitizer.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class WJECF_Sanitizer {
4
+
5
+ /**
6
+ * Singleton Instance
7
+ *
8
+ * @static
9
+ * @return Singleton Instance
10
+ */
11
+ public static function instance() {
12
+ if ( is_null( self::$_instance ) ) {
13
+ self::$_instance = new self();
14
+ }
15
+ return self::$_instance;
16
+ }
17
+ protected static $_instance = null;
18
+
19
+ /**
20
+ * Sanitizes form input for database output
21
+ *
22
+ * @param mixed $value
23
+ * @param string $requested_format The output format requested
24
+ * @param mixed|null $fallback_value Value to return in case of invalid value
25
+ * @return mixed Sanitized
26
+ */
27
+ public function sanitize( $value, $requested_format, $fallback_value = null ) {
28
+
29
+ switch ($requested_format) {
30
+ case '':
31
+ return (string) $value;
32
+
33
+ case 'html':
34
+ return wp_kses_post( $value );
35
+
36
+ case 'clean':
37
+ //applies sanitize_text_field; or recursively if it's an array
38
+ return wc_clean( $value );
39
+
40
+ case 'int,':
41
+ case 'int[]':
42
+ if ( is_array( $value ) ) {
43
+ $values = $value;
44
+ } elseif ( $value === '' || $value === null || $value === false ) {
45
+ $values = array();
46
+ } else {
47
+ $values = explode( ',', $value ); // int[] also accepts comma separated string
48
+ }
49
+ $retval = array();
50
+ foreach( $values as $value) {
51
+ $sane = $this->sanitize( $value, 'int' );
52
+ if ( $sane !== null ) $retval[] = $sane;
53
+ }
54
+ if ($requested_format === 'int,') {
55
+ return implode( ',', $retval );
56
+ }
57
+ return $retval;
58
+
59
+ case 'int':
60
+ return is_numeric( $value ) ? intval( $value ) : $fallback_value;
61
+
62
+ case 'yesno':
63
+ return $value === 'yes' ? 'yes' : 'no';
64
+
65
+ case 'decimal':
66
+ $value = wc_format_decimal( $value );
67
+ return ( $value === '' || $value === false ) ? $fallback_value : $value;
68
+ }
69
+
70
+ throw new Exception("Unknown sanitization rule " . $requested_format);
71
+ }
72
+ }
includes/{wjecf-wc.php → WJECF_WC.php} RENAMED
@@ -36,6 +36,9 @@ class WJECF_WC {
36
  $object = new WC_Product( $object );
37
  }
38
  }
 
 
 
39
 
40
 
41
  if ( $object instanceof WC_Coupon ) {
@@ -102,190 +105,165 @@ class WJECF_WC {
102
  return wc_get_cart_coupon_types();
103
  }
104
  return array( 'fixed_cart', 'percent' );
105
- }
106
 
107
  /**
108
- * @since 2.4.0 for WC 2.7 compatibility
109
- *
110
- * Get a WC_Coupon object
111
- * @param WC_Coupon|string $coupon The coupon code or a WC_Coupon object
112
- * @return WC_Coupon The coupon object
113
  */
114
- public function get_coupon( $coupon ) {
115
- if ( is_numeric( $coupon ) ) {
116
- //By id
117
- global $wpdb;
118
- $coupon = $wpdb->get_var( $wpdb->prepare( "SELECT post_title FROM $wpdb->posts WHERE id = %s AND post_type = 'shop_coupon' AND post_status = 'publish'", $coupon ) );
119
- }
120
- if ( ! ( $coupon instanceof WC_Coupon ) ) {
121
- //By code
122
- $coupon = new WC_Coupon( $coupon );
123
  }
124
- return $coupon;
125
- }
126
-
127
- //ADMIN
128
 
129
- /**
130
- * Display a WooCommerce help tip
131
- * @param string $tip The tip to display
132
- * @return string
133
- */
134
- public function wc_help_tip( $tip ) {
135
- //Since WC 2.5.0
136
- if ( function_exists( 'wc_help_tip' ) ) {
137
- return wc_help_tip( $tip );
138
- }
139
 
140
- return '<img class="help_tip" style="margin-top: 21px;" data-tip="' . esc_attr( $tip ) . '" src="' . esc_url( WC()->plugin_url() ) . '/assets/images/help.png" height="16" width="16" />';
141
- }
 
 
 
142
 
143
- /**
144
- * Renders a product selection <input>. Will use either select2 v4 (WC3.0+) select2 v3 (WC2.3+) or chosen (< WC2.3)
145
- * @param string $dom_id
146
- * @param string $field_name
147
- * @param array $selected_ids Array of integers
148
- * @param string|null $placeholder
149
- * @return void
150
- */
151
- public function render_admin_product_selector( $dom_id, $field_name, $selected_ids, $placeholder = null ) {
152
- $product_key_values = array();
153
- foreach ( $selected_ids as $product_id ) {
154
- $product = wc_get_product( $product_id );
155
- if ( is_object( $product ) ) {
156
- $product_key_values[ esc_attr( $product_id ) ] = wp_kses_post( $product->get_formatted_name() );
157
- }
158
  }
159
 
160
- if ( $placeholder === null ) $placeholder = __( 'Search for a product…', 'woocommerce' );
161
 
162
- //In WooCommerce version 2.3.0 chosen was replaced by select2
163
- //In WooCommerce version 3.0 select2 v3 was replaced by select2 v4
164
- if ( $this->check_woocommerce_version('3.0') ) {
165
- $this->render_admin_select2_v4_product_selector( $dom_id, $field_name, $product_key_values, $placeholder );
166
- } elseif ( $this->check_woocommerce_version('2.3.0') ) {
167
- $this->render_admin_select2_product_selector( $dom_id, $field_name, $product_key_values, $placeholder );
168
- } else {
169
- $this->render_admin_chosen_product_selector( $dom_id, $field_name, $product_key_values, $placeholder );
170
  }
171
- }
172
 
 
 
 
 
173
 
174
- /**
175
- * Renders a product selection <input>.
176
- * Chosen (Legacy)
177
- * @param string $dom_id
178
- * @param string $field_name
179
- * @param array $selected_ids Array of integers
180
- * @param string|null $placeholder
181
- */
182
- private function render_admin_chosen_product_selector( $dom_id, $field_name, $selected_keys_and_values, $placeholder ) {
183
- // $selected_keys_and_values must be an array of [ id => name ]
184
-
185
- echo '<select id="' . esc_attr( $dom_id ) . '" name="' . esc_attr( $field_name ) . '[]" class="ajax_chosen_select_products_and_variations" multiple="multiple" data-placeholder="' . esc_attr( $placeholder ) . '">';
186
- foreach ( $selected_keys_and_values as $product_id => $product_name ) {
187
- echo '<option value="' . $product_id . '" selected="selected">' . $product_name . '</option>';
188
  }
 
189
  echo '</select>';
190
  }
191
 
192
  /**
193
- * @since 2.4.1 for WC 3.0 compatibility
194
- *
195
- * Renders a product selection <input>.
196
- * Select2 version 3 (Since WC 2.3.0)
197
- * @param string $dom_id
198
- * @param string $field_name
199
- * @param array $selected_ids Array of integers
200
- * @param string|null $placeholder
201
- */
202
- private function render_admin_select2_product_selector( $dom_id, $field_name, $selected_keys_and_values, $placeholder ) {
203
- // $selected_keys_and_values must be an array of [ id => name ]
204
-
205
- $json_encoded = esc_attr( json_encode( $selected_keys_and_values ) );
206
- echo '<input type="hidden" class="wc-product-search" data-multiple="true" style="width: 50%;" name="'
207
- . esc_attr( $field_name ) . '" data-placeholder="'
208
- . esc_attr( $placeholder ) . '" data-action="woocommerce_json_search_products_and_variations" data-selected="'
209
- . $json_encoded . '" value="' . implode( ',', array_keys( $selected_keys_and_values ) ) . '" />';
210
-
211
- }
212
-
213
- /**
214
- * Renders a product selection <input>.
215
- * Select2 version 4 (Since WC 3.0)
216
- * @param string $dom_id
217
- * @param string $field_name
218
- * @param string $selected_keys_and_values
219
- * @param string $placeholder
220
  */
221
- private function render_admin_select2_v4_product_selector( $dom_id, $field_name, $selected_keys_and_values, $placeholder ) {
222
- // $selected_keys_and_values must be an array of [ id => name ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
 
224
- $json_encoded = esc_attr( json_encode( $selected_keys_and_values ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
 
226
- echo '<select id="'. esc_attr( $dom_id ) .'" class="wc-product-search" name="'
227
- . esc_attr( $field_name ) . '[]" multiple="multiple" style="width: 50%;" data-placeholder="'
228
- . esc_attr( $placeholder ) . '" data-action="woocommerce_json_search_products_and_variations">';
 
 
229
 
230
- foreach ( $selected_keys_and_values as $product_id => $product_name ) {
231
- echo '<option value="' . esc_attr( $product_id ) . '"' . selected( true, true, false ) . '>' . wp_kses_post( $product_name ) . '</option>';
 
 
 
232
  }
233
 
234
- echo '</select>';
235
  }
236
 
237
-
238
  /**
239
- * Renders a customer selection <input>. Will use either select2 v4 (WC3.0+) or select2 v3 (WC2.3+)
240
- * @param string $dom_id
241
- * @param string $field_name
242
- * @param array $selected_customer_ids Array of integers
243
- * @param string|null $placeholder
244
- * @return void
245
  */
246
- public function render_admin_customer_selector( $dom_id, $field_name, $selected_customer_ids, $placeholder = null ) {
247
- $selected_keys_and_values = array();
248
- foreach ( $selected_customer_ids as $customer_id ) {
249
- $customer = get_userdata( $customer_id );
250
- if ( is_object( $customer ) ) {
251
- $selected_keys_and_values[ $customer_id ] = $customer->display_name . ' (#' . $customer->ID . ' &ndash; ' . sanitize_email( $customer->user_email ) . ')';
252
- }
253
  }
254
- if ( $placeholder === null ) $placeholder = __( 'Any customer', 'woocommerce-jos-autocoupon' );
255
-
256
- //In WooCommerce version 2.3.0 chosen was replaced by select2
257
- //In WooCommerce version 3.0 select2 v3 was replaced by select2 v4
258
- if ( $this->check_woocommerce_version('3.0') ) {
259
- $this->render_admin_select2_v4_customer_selector( $dom_id, $field_name, $selected_keys_and_values, $placeholder );
260
- } else {
261
- $this->render_admin_select2_customer_selector( $dom_id, $field_name, $selected_keys_and_values, $placeholder );
262
  }
263
- }
264
-
265
- private function render_admin_select2_customer_selector( $dom_id, $field_name, $selected_keys_and_values, $placeholder ) {
266
- // $selected_keys_and_values must be an array of [ id => name ] .e.g. [ 12 => 'John Smith (#12 john.smith@example.com)' ]
267
-
268
- $json_encoded = esc_attr( json_encode( $selected_keys_and_values ) );
269
- echo '<input type="hidden" class="wc-customer-search" data-multiple="true" style="width: 50%;" name="'
270
- . esc_attr( $field_name ) . '" data-placeholder="'
271
- . esc_attr( $placeholder ) . '" data-action="woocommerce_json_search_customers" data-selected="'
272
- . $json_encoded . '" value="' . implode( ',', array_keys( $selected_keys_and_values ) ) . '" />';
273
- }
274
-
275
- private function render_admin_select2_v4_customer_selector( $dom_id, $field_name, $selected_keys_and_values, $placeholder ) {
276
- // $selected_keys_and_values must be an array of [ id => name ]
277
-
278
- $json_encoded = esc_attr( json_encode( $selected_keys_and_values ) );
279
-
280
- echo '<select id="'. esc_attr( $dom_id ) .'" class="wc-customer-search" name="'
281
- . esc_attr( $field_name ) . '[]" multiple="multiple" style="width: 50%;" data-placeholder="'
282
- . esc_attr( $placeholder ) . '" data-action="woocommerce_json_search_customers">';
283
-
284
- foreach ( $selected_keys_and_values as $key => $value ) {
285
- echo '<option value="' . esc_attr( $key ) . '"' . selected( true, true, false ) . '>' . wp_kses_post( $value ) . '</option>';
286
  }
287
-
288
- echo '</select>';
289
  }
290
 
291
 
@@ -357,9 +335,10 @@ class WJECF_Wrap {
357
  //error_log('Wrapping ' . get_class( $object ) );
358
  }
359
 
 
360
  public function get_id() {
361
  //Since WC 2.7
362
- if ( is_callable( array( $this->object, 'get_id' ) ) ) {
363
  return $this->object->get_id();
364
  }
365
  return $this->object->id;
@@ -371,22 +350,22 @@ class WJECF_Wrap {
371
 
372
  /**
373
  * Get Meta Data by Key.
 
 
 
 
 
374
  * @since 2.4.0
375
  * @param string $key
376
  * @param bool $single return first found meta, or all
377
  * @return mixed
378
  */
379
- public function get_meta( $meta_key, $single = true ) {
380
- if ( is_callable( array( $this->object, 'get_meta' ) ) ) {
381
  return $this->get_meta_wc27( $meta_key, $single );
382
  }
383
 
384
  return $this->get_meta_legacy( $meta_key, $single );
385
-
386
- //return get_post_meta( $this->object->id, $meta_key, $single );
387
- //If no value found:
388
- //If $single is true, an empty string is returned.
389
- //If $single is false, an empty array is returned.
390
  }
391
 
392
  protected function get_meta_wc27( $meta_key, $single = true ) {
@@ -400,14 +379,36 @@ class WJECF_Wrap {
400
  }
401
 
402
  return wp_list_pluck( array_values( $values ), 'value' ); //when not using array_values; the index might not start with 0
403
- }
404
-
405
- protected $meta_cache = array();
406
 
407
  protected function get_meta_legacy( $meta_key, $single = true ) {
408
  throw new Exception( sprintf( '%s::get_meta_legacy not implemented', get_class( $this ) ) );
409
  }
410
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
411
  }
412
 
413
  /**
@@ -420,7 +421,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
420
  }
421
 
422
  public function get_code() {
423
- if ( is_callable( array( $this->object, 'get_code' ) ) ) {
424
  return $this->object->get_code();
425
  }
426
 
@@ -428,7 +429,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
428
  }
429
 
430
  public function get_amount() {
431
- if ( is_callable( array( $this->object, 'get_amount' ) ) ) {
432
  return $this->object->get_amount();
433
  }
434
 
@@ -436,7 +437,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
436
  }
437
 
438
  public function get_individual_use() {
439
- if ( is_callable( array( $this->object, 'get_individual_use' ) ) ) {
440
  return $this->object->get_individual_use();
441
  }
442
 
@@ -444,7 +445,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
444
  }
445
 
446
  public function get_limit_usage_to_x_items() {
447
- if ( is_callable( array( $this->object, 'get_limit_usage_to_x_items' ) ) ) {
448
  return $this->object->get_limit_usage_to_x_items();
449
  }
450
 
@@ -452,7 +453,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
452
  }
453
 
454
  public function set_limit_usage_to_x_items( $limit_usage_to_x_items ) {
455
- if ( is_callable( array( $this->object, 'set_limit_usage_to_x_items' ) ) ) {
456
  $this->object->set_limit_usage_to_x_items( $limit_usage_to_x_items );
457
  } else {
458
  $this->object->limit_usage_to_x_items = $limit_usage_to_x_items;
@@ -460,7 +461,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
460
  }
461
 
462
  public function get_discount_type() {
463
- if ( is_callable( array( $this->object, 'get_discount_type' ) ) ) {
464
  return $this->object->get_discount_type();
465
  }
466
 
@@ -468,7 +469,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
468
  }
469
 
470
  public function set_discount_type( $discount_type ) {
471
- if ( is_callable( array( $this->object, 'set_discount_type' ) ) ) {
472
  $this->object->set_discount_type( $discount_type );
473
  } else {
474
  $this->object->discount_type = $discount_type;
@@ -478,7 +479,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
478
 
479
 
480
  public function get_email_restrictions() {
481
- if ( is_callable( array( $this->object, 'get_email_restrictions' ) ) ) {
482
  return $this->object->get_email_restrictions();
483
  }
484
 
@@ -486,7 +487,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
486
  }
487
 
488
  public function get_product_ids() {
489
- if ( is_callable( array( $this->object, 'get_product_ids' ) ) ) {
490
  return $this->object->get_product_ids();
491
  }
492
 
@@ -494,7 +495,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
494
  }
495
 
496
  public function get_free_shipping() {
497
- if ( is_callable( array( $this->object, 'get_free_shipping' ) ) ) {
498
  return $this->object->get_free_shipping();
499
  }
500
 
@@ -502,7 +503,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
502
  }
503
 
504
  public function get_product_categories() {
505
- if ( is_callable( array( $this->object, 'get_product_categories' ) ) ) {
506
  return $this->object->get_product_categories();
507
  }
508
 
@@ -510,7 +511,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
510
  }
511
 
512
  public function get_minimum_amount() {
513
- if ( is_callable( array( $this->object, 'get_minimum_amount' ) ) ) {
514
  return $this->object->get_minimum_amount();
515
  }
516
 
@@ -524,7 +525,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
524
  * @throws WC_Data_Exception
525
  */
526
  public function set_excluded_product_ids( $excluded_product_ids ) {
527
- if ( is_callable( array( $this->object, 'set_excluded_product_ids' ) ) ) {
528
  $this->object->set_excluded_product_ids( $excluded_product_ids );
529
  } else {
530
  //NOTE: Prior to WC2.7 it was called exclude_ instead of excluded_
@@ -539,7 +540,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
539
  * @throws WC_Data_Exception
540
  */
541
  public function set_excluded_product_categories( $excluded_product_categories ) {
542
- if ( is_callable( array( $this->object, 'set_excluded_product_categories' ) ) ) {
543
  $this->object->set_excluded_product_categories( $excluded_product_categories );
544
  } else {
545
  //NOTE: Prior to WC2.7 it was called exclude_ instead of excluded_
@@ -554,7 +555,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
554
  * @throws WC_Data_Exception
555
  */
556
  public function set_exclude_sale_items( $exclude_sale_items ) {
557
- if ( is_callable( array( $this->object, 'set_exclude_sale_items' ) ) ) {
558
  $this->object->set_exclude_sale_items( $exclude_sale_items );
559
  } else {
560
  //NOTE: Prior to WC2.7 it was yes/no instead of boolean
@@ -576,26 +577,10 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
576
  return ( $this->object->discount_type == $type || ( is_array( $type ) && in_array( $this->object->discount_type, $type ) ) ) ? true : false;
577
  }
578
 
579
- /**
580
- * Update single meta data item by meta key.
581
- * Call save() afterwards!
582
- * @since 2.4.0
583
- * @param string $key
584
- * @param mixed $value The value; use null to clear
585
- */
586
- public function set_meta( $meta_key, $value ) {
587
- if ( is_callable( array( $this->object, 'update_meta_data' ) ) ) {
588
- if ( $value === null ) {
589
- $this->object->delete_meta_data( $meta_key );
590
- } else {
591
- $this->object->update_meta_data( $meta_key, $value );
592
- }
593
- return;
594
- }
595
-
596
  $this->maybe_get_custom_fields();
597
  //WJECF()->log('...setting legacy meta ' . $meta_key );
598
- $this->legacy_custom_fields[ $meta_key ] = $value;
599
  $this->legacy_unsaved_keys[] = $meta_key;
600
  }
601
 
@@ -605,14 +590,14 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
605
  */
606
  public function save() {
607
  //WJECF()->log('Saving ' . $this->get_id() );
608
- if ( is_callable( array( $this->object, 'save' ) ) ) {
609
  return $this->object->save();
610
  }
611
 
612
  //Save the unsaved...
613
  foreach( $this->legacy_unsaved_keys as $meta_key ) {
614
  //WJECF()->log('...saving legacy meta ' . $meta_key );
615
- $value = $this->legacy_custom_fields[ $meta_key ];
616
  if ( $value === null ) {
617
  delete_post_meta( $this->get_id(), $meta_key );
618
  } else {
@@ -624,7 +609,7 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
624
  return $this->get_id();
625
  }
626
 
627
- protected $legacy_custom_fields = null;
628
  protected $legacy_unsaved_keys = array();
629
 
630
  protected function maybe_get_custom_fields() {
@@ -655,7 +640,29 @@ class WJECF_Wrap_Coupon extends WJECF_Wrap {
655
 
656
  class WJECF_Wrap_Product extends WJECF_Wrap {
657
 
658
- public function is_variation() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
659
  return $this->object instanceof WC_Product_Variation;
660
  }
661
 
@@ -690,7 +697,7 @@ class WJECF_Wrap_Product extends WJECF_Wrap {
690
  return false;
691
  }
692
 
693
- if ( is_callable( array( $this->object, 'get_parent_id' ) ) ) {
694
  return $this->object->get_parent_id();
695
  } else {
696
  return wp_get_post_parent_id( $this->object->variation_id );
@@ -706,10 +713,10 @@ class WJECF_Wrap_Product extends WJECF_Wrap {
706
  return false;
707
  }
708
 
709
- if ( is_callable( array( $this->object, 'get_id' ) ) ) {
710
  //WP_CLI::log( "get_variation_id:WC27 " . get_class( $this->object ) );
711
  return $this->object->get_id();
712
- } elseif ( is_callable( array( $this->object, 'get_variation_id' ) ) ) {
713
  //WP_CLI::log( "get_variation_id:LEGACY " . get_class( $this->object ) );
714
  return $this->object->get_variation_id();
715
  }
@@ -719,7 +726,7 @@ class WJECF_Wrap_Product extends WJECF_Wrap {
719
 
720
 
721
  public function get_name() {
722
- if ( is_callable( array( $this->object, 'get_name' ) ) ) {
723
  return $this->object->get_name();
724
  } else {
725
  return $this->object->post->post_title;
@@ -727,7 +734,7 @@ class WJECF_Wrap_Product extends WJECF_Wrap {
727
  }
728
 
729
  public function get_description() {
730
- if ( is_callable( array( $this->object, 'get_description' ) ) ) {
731
  return $this->object->get_description();
732
  } else {
733
  return $this->object->post->post_content;
@@ -735,7 +742,7 @@ class WJECF_Wrap_Product extends WJECF_Wrap {
735
  }
736
 
737
  public function get_short_description() {
738
- if ( is_callable( array( $this->object, 'get_short_description' ) ) ) {
739
  return $this->object->get_short_description();
740
  } else {
741
  return $this->object->post->post_excerpt;
@@ -743,7 +750,7 @@ class WJECF_Wrap_Product extends WJECF_Wrap {
743
  }
744
 
745
  public function get_tag_ids() {
746
- if ( is_callable( array( $this->object, 'get_tag_ids' ) ) ) {
747
  return $this->object->get_tag_ids();
748
  } else {
749
  return $this->legacy_get_term_ids( 'product_tag' );
@@ -758,4 +765,17 @@ class WJECF_Wrap_Product extends WJECF_Wrap {
758
  return wp_list_pluck( $terms, 'term_id' );
759
  }
760
 
 
 
 
 
 
 
 
 
 
 
 
 
 
761
  }
36
  $object = new WC_Product( $object );
37
  }
38
  }
39
+ if ( is_string( $object ) ) {
40
+ $object = WJECF_WC()->get_coupon( $object );
41
+ }
42
 
43
 
44
  if ( $object instanceof WC_Coupon ) {
105
  return wc_get_cart_coupon_types();
106
  }
107
  return array( 'fixed_cart', 'percent' );
108
+ }
109
 
110
  /**
111
+ * Output a list of variation attributes for use in the cart forms.
112
+ *
113
+ * @param array $args
114
+ * @since 2.5.1
 
115
  */
116
+ public function wc_dropdown_variation_attribute_options( $args = array() ) {
117
+ if ( function_exists( 'wc_dropdown_variation_attribute_options' ) ) {
118
+ return wc_dropdown_variation_attribute_options( $args );
 
 
 
 
 
 
119
  }
 
 
 
 
120
 
121
+ //Copied from WC2.4.0 wc-template-functions.php
122
+ $args = wp_parse_args( $args, array(
123
+ 'options' => false,
124
+ 'attribute' => false,
125
+ 'product' => false,
126
+ 'selected' => false,
127
+ 'name' => '',
128
+ 'id' => '',
129
+ 'show_option_none' => __( 'Choose an option', 'woocommerce' )
130
+ ) );
131
 
132
+ $options = $args['options'];
133
+ $product = $args['product'];
134
+ $attribute = $args['attribute'];
135
+ $name = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute );
136
+ $id = $args['id'] ? $args['id'] : sanitize_title( $attribute );
137
 
138
+ if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
139
+ $attributes = $product->get_variation_attributes();
140
+ $options = $attributes[ $attribute ];
 
 
 
 
 
 
 
 
 
 
 
 
141
  }
142
 
143
+ echo '<select id="' . esc_attr( $id ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '">';
144
 
145
+ if ( $args['show_option_none'] ) {
146
+ echo '<option value="">' . esc_html( $args['show_option_none'] ) . '</option>';
 
 
 
 
 
 
147
  }
 
148
 
149
+ if ( ! empty( $options ) ) {
150
+ if ( $product && taxonomy_exists( $attribute ) ) {
151
+ // Get terms if this is a taxonomy - ordered. We need the names too.
152
+ $terms = wc_get_product_terms( $product->id, $attribute, array( 'fields' => 'all' ) );
153
 
154
+ foreach ( $terms as $term ) {
155
+ if ( in_array( $term->slug, $options ) ) {
156
+ echo '<option value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $args['selected'] ), $term->slug, false ) . '>' . apply_filters( 'woocommerce_variation_option_name', $term->name ) . '</option>';
157
+ }
158
+ }
159
+ } else {
160
+ foreach ( $options as $option ) {
161
+ // This handles < 2.4.0 bw compatibility where text attributes were not sanitized.
162
+ $selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false );
163
+ echo '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>';
164
+ }
165
+ }
 
 
166
  }
167
+
168
  echo '</select>';
169
  }
170
 
171
  /**
172
+ * Get attibutes/data for an individual variation from the database and maintain it's integrity.
173
+ * @since 2.5.1
174
+ * @param int $variation_id
175
+ * @return array
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  */
177
+ public function wc_get_product_variation_attributes( $variation_id ) {
178
+ if ( function_exists( 'wc_get_product_variation_attributes' ) ) {
179
+ return wc_get_product_variation_attributes( $variation_id );
180
+ }
181
+
182
+ //Copied from WC2.4.0 wc-product-functions.php
183
+
184
+ // Build variation data from meta
185
+ $all_meta = get_post_meta( $variation_id );
186
+ $parent_id = wp_get_post_parent_id( $variation_id );
187
+ $parent_attributes = array_filter( (array) get_post_meta( $parent_id, '_product_attributes', true ) );
188
+ $found_parent_attributes = array();
189
+ $variation_attributes = array();
190
+
191
+ // Compare to parent variable product attributes and ensure they match
192
+ foreach ( $parent_attributes as $attribute_name => $options ) {
193
+ $attribute = 'attribute_' . sanitize_title( $attribute_name );
194
+ $found_parent_attributes[] = $attribute;
195
+ if ( ! array_key_exists( $attribute, $variation_attributes ) ) {
196
+ $variation_attributes[ $attribute ] = ''; // Add it - 'any' will be asumed
197
+ }
198
+ }
199
 
200
+ // Get the variation attributes from meta
201
+ foreach ( $all_meta as $name => $value ) {
202
+ // Only look at valid attribute meta, and also compare variation level attributes and remove any which do not exist at parent level
203
+ if ( 0 !== strpos( $name, 'attribute_' ) || ! in_array( $name, $found_parent_attributes ) ) {
204
+ unset( $variation_attributes[ $name ] );
205
+ continue;
206
+ }
207
+ /**
208
+ * Pre 2.4 handling where 'slugs' were saved instead of the full text attribute.
209
+ * Attempt to get full version of the text attribute from the parent.
210
+ */
211
+ if ( sanitize_title( $value[0] ) === $value[0] && version_compare( get_post_meta( $parent_id, '_product_version', true ), '2.4.0', '<' ) ) {
212
+ foreach ( $parent_attributes as $attribute ) {
213
+ if ( $name !== 'attribute_' . sanitize_title( $attribute['name'] ) ) {
214
+ continue;
215
+ }
216
+ $text_attributes = wc_get_text_attributes( $attribute['value'] );
217
+
218
+ foreach ( $text_attributes as $text_attribute ) {
219
+ if ( sanitize_title( $text_attribute ) === $value[0] ) {
220
+ $value[0] = $text_attribute;
221
+ break;
222
+ }
223
+ }
224
+ }
225
+ }
226
 
227
+ $variation_attributes[ $name ] = $value[0];
228
+ }
229
+
230
+ return $variation_attributes;
231
+ }
232
 
233
+ public function find_matching_product_variation( $product, $match_attributes = array() ) {
234
+ if ( $this->check_woocommerce_version( '3.0') ) {
235
+ $data_store = WC_Data_Store::load( 'product' );
236
+ $variation_id = $data_store->find_matching_product_variation( $product, $match_attributes );
237
+ return $variation_id;
238
  }
239
 
240
+ return $product->get_matching_variation( $match_attributes );
241
  }
242
 
 
243
  /**
244
+ * @since 2.4.0 for WC 2.7 compatibility
245
+ *
246
+ * Get a WC_Coupon object
247
+ * @param WC_Coupon|string|WP_Post $coupon The coupon code or a WC_Coupon object
248
+ * @return WC_Coupon The coupon object
 
249
  */
250
+ public function get_coupon( $coupon ) {
251
+ if ( $coupon instanceof WP_Post ) {
252
+ $coupon = $coupon->ID;
 
 
 
 
253
  }
254
+ if ( is_numeric( $coupon ) && ! $this->check_woocommerce_version( '3.0' ) ) {
255
+ //By id; not neccesary for WC3.0; as the WC_Coupon constructor accepts an id
256
+ global $wpdb;
257
+ $coupon_code = $wpdb->get_var( $wpdb->prepare( "SELECT post_title FROM $wpdb->posts WHERE id = %d AND post_type = 'shop_coupon'", $coupon ) );
258
+ if ( $coupon_code !== null) {
259
+ $coupon = $coupon_code;
260
+ }
 
261
  }
262
+ if ( ! ( $coupon instanceof WC_Coupon ) ) {
263
+ //By code
264
+ $coupon = new WC_Coupon( $coupon );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  }
266
+ return $coupon;
 
267
  }
268
 
269
 
335
  //error_log('Wrapping ' . get_class( $object ) );
336
  }
337
 
338
+ public $use_wc27 = true;
339
  public function get_id() {
340
  //Since WC 2.7
341
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_id' ) ) ) {
342
  return $this->object->get_id();
343
  }
344
  return $this->object->id;
350
 
351
  /**
352
  * Get Meta Data by Key.
353
+ *
354
+ * If no value found:
355
+ * If $single is true, an empty string is returned.
356
+ * If $single is false, an empty array is returned.
357
+ *
358
  * @since 2.4.0
359
  * @param string $key
360
  * @param bool $single return first found meta, or all
361
  * @return mixed
362
  */
363
+ public final function get_meta( $meta_key, $single = true ) {
364
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_meta' ) ) ) {
365
  return $this->get_meta_wc27( $meta_key, $single );
366
  }
367
 
368
  return $this->get_meta_legacy( $meta_key, $single );
 
 
 
 
 
369
  }
370
 
371
  protected function get_meta_wc27( $meta_key, $single = true ) {
379
  }
380
 
381
  return wp_list_pluck( array_values( $values ), 'value' ); //when not using array_values; the index might not start with 0
382
+ }
 
 
383
 
384
  protected function get_meta_legacy( $meta_key, $single = true ) {
385
  throw new Exception( sprintf( '%s::get_meta_legacy not implemented', get_class( $this ) ) );
386
  }
387
 
388
+ /**
389
+ * Update single meta data item by meta key.
390
+ * Call save() if the values must to be persisted.
391
+ * @since 2.4.0
392
+ * @param string $meta_key
393
+ * @param mixed $value The value; use null to clear
394
+ */
395
+ public final function set_meta( $meta_key, $value ) {
396
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'update_meta_data' ) ) ) {
397
+ if ( $value === null ) {
398
+ $this->object->delete_meta_data( $meta_key );
399
+ } else {
400
+ $this->object->update_meta_data( $meta_key, $value );
401
+ }
402
+ return;
403
+ }
404
+
405
+ $this->set_meta_legacy( $meta_key, $value );
406
+ }
407
+
408
+ protected function set_meta_legacy( $meta_key, $value ) {
409
+ throw new Exception( sprintf( '%s::set_meta_legacy not implemented', get_class( $this ) ) );
410
+ }
411
+
412
  }
413
 
414
  /**
421
  }
422
 
423
  public function get_code() {
424
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_code' ) ) ) {
425
  return $this->object->get_code();
426
  }
427
 
429
  }
430
 
431
  public function get_amount() {
432
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_amount' ) ) ) {
433
  return $this->object->get_amount();
434
  }
435
 
437
  }
438
 
439
  public function get_individual_use() {
440
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_individual_use' ) ) ) {
441
  return $this->object->get_individual_use();
442
  }
443
 
445
  }
446
 
447
  public function get_limit_usage_to_x_items() {
448
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_limit_usage_to_x_items' ) ) ) {
449
  return $this->object->get_limit_usage_to_x_items();
450
  }
451
 
453
  }
454
 
455
  public function set_limit_usage_to_x_items( $limit_usage_to_x_items ) {
456
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'set_limit_usage_to_x_items' ) ) ) {
457
  $this->object->set_limit_usage_to_x_items( $limit_usage_to_x_items );
458
  } else {
459
  $this->object->limit_usage_to_x_items = $limit_usage_to_x_items;
461
  }
462
 
463
  public function get_discount_type() {
464
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_discount_type' ) ) ) {
465
  return $this->object->get_discount_type();
466
  }
467
 
469
  }
470
 
471
  public function set_discount_type( $discount_type ) {
472
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'set_discount_type' ) ) ) {
473
  $this->object->set_discount_type( $discount_type );
474
  } else {
475
  $this->object->discount_type = $discount_type;
479
 
480
 
481
  public function get_email_restrictions() {
482
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_email_restrictions' ) ) ) {
483
  return $this->object->get_email_restrictions();
484
  }
485
 
487
  }
488
 
489
  public function get_product_ids() {
490
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_product_ids' ) ) ) {
491
  return $this->object->get_product_ids();
492
  }
493
 
495
  }
496
 
497
  public function get_free_shipping() {
498
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_free_shipping' ) ) ) {
499
  return $this->object->get_free_shipping();
500
  }
501
 
503
  }
504
 
505
  public function get_product_categories() {
506
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_product_categories' ) ) ) {
507
  return $this->object->get_product_categories();
508
  }
509
 
511
  }
512
 
513
  public function get_minimum_amount() {
514
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_minimum_amount' ) ) ) {
515
  return $this->object->get_minimum_amount();
516
  }
517
 
525
  * @throws WC_Data_Exception
526
  */
527
  public function set_excluded_product_ids( $excluded_product_ids ) {
528
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'set_excluded_product_ids' ) ) ) {
529
  $this->object->set_excluded_product_ids( $excluded_product_ids );
530
  } else {
531
  //NOTE: Prior to WC2.7 it was called exclude_ instead of excluded_
540
  * @throws WC_Data_Exception
541
  */
542
  public function set_excluded_product_categories( $excluded_product_categories ) {
543
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'set_excluded_product_categories' ) ) ) {
544
  $this->object->set_excluded_product_categories( $excluded_product_categories );
545
  } else {
546
  //NOTE: Prior to WC2.7 it was called exclude_ instead of excluded_
555
  * @throws WC_Data_Exception
556
  */
557
  public function set_exclude_sale_items( $exclude_sale_items ) {
558
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'set_exclude_sale_items' ) ) ) {
559
  $this->object->set_exclude_sale_items( $exclude_sale_items );
560
  } else {
561
  //NOTE: Prior to WC2.7 it was yes/no instead of boolean
577
  return ( $this->object->discount_type == $type || ( is_array( $type ) && in_array( $this->object->discount_type, $type ) ) ) ? true : false;
578
  }
579
 
580
+ protected function set_meta_legacy( $meta_key, $value ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
581
  $this->maybe_get_custom_fields();
582
  //WJECF()->log('...setting legacy meta ' . $meta_key );
583
+ $this->legacy_custom_fields[ $meta_key ] = array( $value );
584
  $this->legacy_unsaved_keys[] = $meta_key;
585
  }
586
 
590
  */
591
  public function save() {
592
  //WJECF()->log('Saving ' . $this->get_id() );
593
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'save' ) ) ) {
594
  return $this->object->save();
595
  }
596
 
597
  //Save the unsaved...
598
  foreach( $this->legacy_unsaved_keys as $meta_key ) {
599
  //WJECF()->log('...saving legacy meta ' . $meta_key );
600
+ $value = reset( $this->legacy_custom_fields[ $meta_key ] );
601
  if ( $value === null ) {
602
  delete_post_meta( $this->get_id(), $meta_key );
603
  } else {
609
  return $this->get_id();
610
  }
611
 
612
+ protected $legacy_custom_fields = null; // [ 'meta_key' => [ array_of_values ] ]
613
  protected $legacy_unsaved_keys = array();
614
 
615
  protected function maybe_get_custom_fields() {
640
 
641
  class WJECF_Wrap_Product extends WJECF_Wrap {
642
 
643
+ protected $legacy_custom_fields = null; // [ 'meta_key' => [ array_of_values ] ]
644
+ protected $legacy_unsaved_keys = array();
645
+
646
+ protected function get_meta_legacy( $meta_key, $single = true ) {
647
+ if ( isset( $this->legacy_custom_fields[ $meta_key ] ) ) {
648
+ $values = $this->legacy_custom_fields[ $meta_key ];
649
+ //WP_CLI::log( "LEGACY:" . print_r( $values, true ));
650
+ if ($single) {
651
+ return maybe_unserialize( reset( $values ) ); //reset yields the first
652
+ }
653
+ $values = array_map( 'maybe_unserialize', $values );
654
+ return $values;
655
+ }
656
+
657
+ return $single ? '' : array();
658
+ }
659
+
660
+ public function set_meta_legacy( $meta_key, $value ) {
661
+ $this->legacy_custom_fields[ $meta_key ] = array( 0 => $value );
662
+ $this->legacy_unsaved_keys[] = $meta_key;
663
+ }
664
+
665
+ private function is_variation() {
666
  return $this->object instanceof WC_Product_Variation;
667
  }
668
 
697
  return false;
698
  }
699
 
700
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_parent_id' ) ) ) {
701
  return $this->object->get_parent_id();
702
  } else {
703
  return wp_get_post_parent_id( $this->object->variation_id );
713
  return false;
714
  }
715
 
716
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_id' ) ) ) {
717
  //WP_CLI::log( "get_variation_id:WC27 " . get_class( $this->object ) );
718
  return $this->object->get_id();
719
+ } elseif ( $this->use_wc27 && is_callable( array( $this->object, 'get_variation_id' ) ) ) {
720
  //WP_CLI::log( "get_variation_id:LEGACY " . get_class( $this->object ) );
721
  return $this->object->get_variation_id();
722
  }
726
 
727
 
728
  public function get_name() {
729
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_name' ) ) ) {
730
  return $this->object->get_name();
731
  } else {
732
  return $this->object->post->post_title;
734
  }
735
 
736
  public function get_description() {
737
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_description' ) ) ) {
738
  return $this->object->get_description();
739
  } else {
740
  return $this->object->post->post_content;
742
  }
743
 
744
  public function get_short_description() {
745
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_short_description' ) ) ) {
746
  return $this->object->get_short_description();
747
  } else {
748
  return $this->object->post->post_excerpt;
750
  }
751
 
752
  public function get_tag_ids() {
753
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_tag_ids' ) ) ) {
754
  return $this->object->get_tag_ids();
755
  } else {
756
  return $this->legacy_get_term_ids( 'product_tag' );
765
  return wp_list_pluck( $terms, 'term_id' );
766
  }
767
 
768
+ /**
769
+ * If set, get the default attributes for a variable product.
770
+ *
771
+ * @param string $attribute_name
772
+ * @return string
773
+ */
774
+ public function get_variation_default_attribute( $attribute_name ) {
775
+ if ( $this->use_wc27 && is_callable( array( $this->object, 'get_variation_default_attribute' ) ) ) {
776
+ return $this->object->get_variation_default_attribute( $attribute_name );
777
+ }
778
+ return '';
779
+ }
780
+
781
  }
includes/{wjecf-wpml.php → WJECF_WPML.php} RENAMED
File without changes
includes/admin/WJECF_Admin.php ADDED
@@ -0,0 +1,471 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ defined('ABSPATH') or die();
4
+
5
+ if ( ! class_exists('WJECF_Admin') ) {
6
+
7
+ class WJECF_Admin extends Abstract_WJECF_Plugin {
8
+
9
+ public function __construct() {
10
+ $this->set_plugin_data( array(
11
+ 'description' => __( 'Admin interface of WooCommerce Extended Coupon Features.', 'woocommerce-jos-autocoupon' ),
12
+ 'dependencies' => array(),
13
+ 'can_be_disabled' => false
14
+ ) );
15
+ }
16
+
17
+ public function init_admin_hook() {
18
+ add_action( 'admin_notices', array( $this, 'admin_notices'));
19
+
20
+ if ( ! WJECF_WC()->check_woocommerce_version('2.3.0') ) {
21
+ $this->enqueue_notice( '<p>' .
22
+ __( '<strong>WooCommerce Extended Coupon Features:</strong> You are using an old version of WooCommerce. Updating of WooCommerce is recommended as using an outdated version might cause unexpected behaviour in combination with modern plugins.' )
23
+ . '</p>', 'notice-warning' );
24
+ }
25
+ //Admin hooks
26
+ add_filter( 'plugin_row_meta', array( $this, 'wjecf_plugin_meta' ), 10, 2 );
27
+ add_action( 'admin_head', array( $this, 'on_admin_head'));
28
+
29
+ add_filter( 'woocommerce_coupon_data_tabs', array( $this, 'admin_coupon_options_tabs' ), 20, 1);
30
+ add_action( 'woocommerce_coupon_data_panels', array( $this, 'admin_coupon_options_panels' ), 10, 0 );
31
+ add_action( 'woocommerce_process_shop_coupon_meta', array( $this, 'process_shop_coupon_meta' ), 10, 2 );
32
+
33
+ //Removed in 2.5.0: add_action( 'wjecf_coupon_metabox_products', array( $this, 'admin_coupon_metabox_products' ), 10, 2 );
34
+ //Moved to here:
35
+ add_action('woocommerce_coupon_options_usage_restriction', array( $this, 'on_woocommerce_coupon_options_usage_restriction' ), 20, 1);
36
+
37
+ add_action( 'wjecf_coupon_metabox_checkout', array( $this, 'admin_coupon_metabox_checkout' ), 10, 2 );
38
+ add_action( 'wjecf_coupon_metabox_customer', array( $this, 'admin_coupon_metabox_customer' ), 10, 2 );
39
+ //add_action( 'wjecf_coupon_metabox_misc', array( $this, 'admin_coupon_metabox_misc' ), 10, 2 );
40
+
41
+ $this->add_inline_style( '
42
+ #woocommerce-coupon-data .wjecf-not-wide { width:50% }
43
+ ');
44
+ }
45
+
46
+ // ===========================================================================
47
+ // START - ADMIN NOTICES
48
+ // Allows notices to be displayed on the admin pages
49
+ // ===========================================================================
50
+
51
+ private $notices = array();
52
+
53
+ /**
54
+ * Enqueue a notice to display on the admin page
55
+ * @param stirng $html Please embed in <p> tags
56
+ * @param string $class
57
+ */
58
+ public function enqueue_notice( $html, $class = 'notice-info' ) {
59
+ $this->notices[] = array( 'class' => $class, 'html' => $html );
60
+ }
61
+
62
+ public function admin_notices() {
63
+ foreach( $this->notices as $notice ) {
64
+ echo '<div class="notice ' . $notice['class'] . '">';
65
+ echo $notice['html'];
66
+ echo '</div>';
67
+ }
68
+ $this->notices = array();
69
+ }
70
+
71
+ // ===========================================================================
72
+ // END - ADMIN NOTICES
73
+ // ===========================================================================
74
+
75
+ //2.3.6 Inline css
76
+ private $admin_css = '';
77
+
78
+ /**
79
+ * 2.3.6
80
+ * @return void
81
+ */
82
+ function on_admin_head() {
83
+ //Output inline style for the admin pages
84
+ if ( ! empty( $this->admin_css ) ) {
85
+ echo '<style type="text/css">' . $this->admin_css . '</style>';
86
+ $this->admin_css = '';
87
+ }
88
+
89
+ //Enqueue scripts
90
+ wp_enqueue_script( "wjecf-admin", WJECF()->plugin_url() . "assets/js/wjecf-admin.js", array( 'jquery' ), WJECF()->plugin_version() );
91
+ wp_localize_script( 'wjecf-admin', 'wjecf_admin_i18n', array(
92
+ 'label_and' => __( '(AND)', 'woocommerce-jos-autocoupon' ),
93
+ 'label_or' => __( '(OR)', 'woocommerce-jos-autocoupon' )
94
+ ) );
95
+
96
+ }
97
+
98
+ //Add tabs to the coupon option page
99
+ public function admin_coupon_options_tabs( $tabs ) {
100
+
101
+ $tabs['extended_features_checkout'] = array(
102
+ 'label' => __( 'Checkout', 'woocommerce-jos-autocoupon' ),
103
+ 'target' => 'wjecf_coupondata_checkout',
104
+ 'class' => 'wjecf_coupondata_checkout',
105
+ );
106
+
107
+ $tabs['extended_features_misc'] = array(
108
+ 'label' => __( 'Miscellaneous', 'woocommerce-jos-autocoupon' ),
109
+ 'target' => 'wjecf_coupondata_misc',
110
+ 'class' => 'wjecf_coupondata_misc',
111
+ );
112
+
113
+ return $tabs;
114
+ }
115
+
116
+ //Add panels to the coupon option page
117
+ public function admin_coupon_options_panels() {
118
+ global $thepostid, $post;
119
+ $thepostid = empty( $thepostid ) ? $post->ID : $thepostid;
120
+ ?>
121
+ <div id="wjecf_coupondata_checkout" class="panel woocommerce_options_panel">
122
+ <?php
123
+ do_action( 'wjecf_coupon_metabox_checkout', $thepostid, $post );
124
+ do_action( 'wjecf_coupon_metabox_customer', $thepostid, $post );
125
+ $this->admin_coupon_data_footer();
126
+ ?>
127
+ </div>
128
+ <div id="wjecf_coupondata_misc" class="panel woocommerce_options_panel">
129
+ <?php
130
+ //Allow other classes to inject options
131
+ do_action( 'wjecf_woocommerce_coupon_options_extended_features', $thepostid, $post );
132
+ do_action( 'wjecf_coupon_metabox_misc', $thepostid, $post );
133
+ $this->admin_coupon_data_footer();
134
+ ?>
135
+ </div>
136
+ <?php
137
+ }
138
+
139
+ public function admin_coupon_data_footer() {
140
+ $documentation_url = plugins_url( 'docs/index.html', dirname( __FILE__ ) );
141
+ if ( ! WJECF()->is_pro() ) {
142
+ $documentation_url = 'http://www.soft79.nl/documentation/wjecf';
143
+ ?>
144
+ <h3><?php _e( 'Do you find WooCommerce Extended Coupon Features useful?', 'woocommerce-jos-autocoupon'); ?></h3>
145
+ <p class="form-field"><label for="wjecf_donate_button"><?php
146
+ echo esc_html( __('Express your gratitude', 'woocommerce-jos-autocoupon' ) );
147
+ ?></label>
148
+ <a id="wjecf_donate_button" href="<?php echo $this->get_donate_url(); ?>" target="_blank" class="button button-primary">
149
+ <?php
150
+ echo esc_html( __('Donate to the developer', 'woocommerce-jos-autocoupon' ) );
151
+ ?></a><br>
152
+ Or get the PRO version at <a href="http://www.soft79.nl" target="_blank">www.soft79.nl</a>.
153
+ </p>
154
+ <?php
155
+ }
156
+ //Documentation link
157
+ echo '<h3>' . __( 'Documentation', 'woocommerce-jos-autocoupon' ) . '</h3>';
158
+ echo '<p><a href="' . $documentation_url . '" target="_blank">' .
159
+ __( 'WooCommerce Extended Coupon Features Documentation', 'woocommerce-jos-autocoupon' ) . '</a></p>';
160
+
161
+ }
162
+
163
+ // //Tab 'extended features'
164
+ //public function admin_coupon_metabox_products( $thepostid, $post ) {
165
+
166
+ //since 2.5.0 moved to the 'Usage restriction' tab
167
+ public function on_woocommerce_coupon_options_usage_restriction() {
168
+ global $thepostid, $post;
169
+ $thepostid = empty( $thepostid ) ? $post->ID : $thepostid;
170
+
171
+ //See WooCommerce class-wc-meta-box-coupon-data.php function ouput
172
+
173
+ echo "<h3>" . esc_html( __( 'Matching products', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
174
+ //=============================
175
+ // AND instead of OR the products
176
+ WJECF_Admin_Html::render_select_with_default( array(
177
+ 'id' => '_wjecf_products_and',
178
+ 'label' => __( 'Products Operator', 'woocommerce-jos-autocoupon' ),
179
+ 'options' => array( 'no' => __( 'OR', 'woocommerce-jos-autocoupon' ), 'yes' => __( 'AND', 'woocommerce-jos-autocoupon' ) ),
180
+ 'default_value' => 'no',
181
+ 'class' => 'wjecf-not-wide',
182
+ /* translators: OLD TEXT: 'Check this box if ALL of the products (see tab \'usage restriction\') must be in the cart to use this coupon (instead of only one of the products).' */
183
+ 'description' => __( 'Use AND if ALL of the products must be in the cart to use this coupon (instead of only one of the products).', 'woocommerce-jos-autocoupon' ),
184
+ 'desc_tip' => true
185
+ ) );
186
+
187
+ //=============================
188
+ // 2.2.3.1 AND instead of OR the categories
189
+ WJECF_Admin_Html::render_select_with_default( array(
190
+ 'id' => '_wjecf_categories_and',
191
+ 'label' => __( 'Categories Operator', 'woocommerce-jos-autocoupon' ),
192
+ 'options' => array( 'no' => __( 'OR', 'woocommerce-jos-autocoupon' ), 'yes' => __( 'AND', 'woocommerce-jos-autocoupon' ) ),
193
+ 'default_value' => 'no',
194
+ 'class' => 'wjecf-not-wide',
195
+ /* translators: OLD TEXT: 'Check this box if products from ALL of the categories (see tab \'usage restriction\') must be in the cart to use this coupon (instead of only one from one of the categories).' */
196
+ 'description' => __( 'Use AND if products from ALL of the categories must be in the cart to use this coupon (instead of only one from one of the categories).', 'woocommerce-jos-autocoupon' ),
197
+ 'desc_tip' => true
198
+ ) );
199
+
200
+
201
+
202
+ // Minimum quantity of matching products (product/category)
203
+ woocommerce_wp_text_input( array(
204
+ 'id' => '_wjecf_min_matching_product_qty',
205
+ 'label' => __( 'Minimum quantity of matching products', 'woocommerce-jos-autocoupon' ),
206
+ 'placeholder' => __( 'No minimum', 'woocommerce' ),
207
+ 'description' => __( 'Minimum quantity of the products that match the given product or category restrictions (see tab \'usage restriction\'). If no product or category restrictions are specified, the total number of products is used.', 'woocommerce-jos-autocoupon' ),
208
+ 'data_type' => 'decimal',
209
+ 'desc_tip' => true
210
+ ) );
211
+
212
+ // Maximum quantity of matching products (product/category)
213
+ woocommerce_wp_text_input( array(
214
+ 'id' => '_wjecf_max_matching_product_qty',
215
+ 'label' => __( 'Maximum quantity of matching products', 'woocommerce-jos-autocoupon' ),
216
+ 'placeholder' => __( 'No maximum', 'woocommerce' ),
217
+ 'description' => __( 'Maximum quantity of the products that match the given product or category restrictions (see tab \'usage restriction\'). If no product or category restrictions are specified, the total number of products is used.', 'woocommerce-jos-autocoupon' ),
218
+ 'data_type' => 'decimal',
219
+ 'desc_tip' => true
220
+ ) );
221
+
222
+ // Minimum subtotal of matching products (product/category)
223
+ woocommerce_wp_text_input( array(
224
+ 'id' => '_wjecf_min_matching_product_subtotal',
225
+ 'label' => __( 'Minimum subtotal of matching products', 'woocommerce-jos-autocoupon' ),
226
+ 'placeholder' => __( 'No minimum', 'woocommerce' ),
227
+ 'description' => __( 'Minimum price subtotal of the products that match the given product or category restrictions (see tab \'usage restriction\').', 'woocommerce-jos-autocoupon' ),
228
+ 'data_type' => 'price',
229
+ 'desc_tip' => true
230
+ ) );
231
+
232
+ // Maximum subtotal of matching products (product/category)
233
+ woocommerce_wp_text_input( array(
234
+ 'id' => '_wjecf_max_matching_product_subtotal',
235
+ 'label' => __( 'Maximum subtotal of matching products', 'woocommerce-jos-autocoupon' ),
236
+ 'placeholder' => __( 'No maximum', 'woocommerce' ),
237
+ 'description' => __( 'Maximum price subtotal of the products that match the given product or category restrictions (see tab \'usage restriction\').', 'woocommerce-jos-autocoupon' ),
238
+ 'data_type' => 'price',
239
+ 'desc_tip' => true
240
+ ) );
241
+ }
242
+
243
+ public function admin_coupon_metabox_checkout( $thepostid, $post ) {
244
+
245
+ echo "<h3>" . esc_html( __( 'Checkout', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
246
+
247
+ //=============================
248
+ // Shipping methods
249
+ ?>
250
+ <p class="form-field"><label for="wjecf_shipping_methods"><?php _e( 'Shipping methods', 'woocommerce-jos-autocoupon' ); ?></label>
251
+ <select id="wjecf_shipping_methods" name="_wjecf_shipping_methods[]" style="width: 50%;" class="wc-enhanced-select" multiple="multiple" data-placeholder="<?php _e( 'Any shipping method', 'woocommerce-jos-autocoupon' ); ?>">
252
+ <?php
253
+ $coupon_shipping_method_ids = WJECF()->get_coupon_shipping_method_ids( $thepostid );
254
+ $shipping_methods = WC()->shipping->load_shipping_methods();
255
+
256
+ if ( $shipping_methods ) foreach ( $shipping_methods as $shipping_method ) {
257
+ echo '<option value="' . esc_attr( $shipping_method->id ) . '"' . selected( in_array( $shipping_method->id, $coupon_shipping_method_ids ), true, false ) . '>' . esc_html( $shipping_method->method_title ) . '</option>';
258
+ }
259
+ ?>
260
+ </select><?php echo WJECF_Admin_Html::wc_help_tip( __( 'One of these shipping methods must be selected in order for this coupon to be valid.', 'woocommerce-jos-autocoupon' ) ); ?>
261
+ </p>
262
+ <?php
263
+
264
+ //=============================
265
+ // Payment methods
266
+ ?>
267
+ <p class="form-field"><label for="wjecf_payment_methods"><?php _e( 'Payment methods', 'woocommerce-jos-autocoupon' ); ?></label>
268
+ <select id="wjecf_payment_methods" name="_wjecf_payment_methods[]" style="width: 50%;" class="wc-enhanced-select" multiple="multiple" data-placeholder="<?php _e( 'Any payment method', 'woocommerce-jos-autocoupon' ); ?>">
269
+ <?php
270
+ $coupon_payment_method_ids = WJECF()->get_coupon_payment_method_ids( $thepostid );
271
+ //DONT USE WC()->payment_gateways->available_payment_gateways() AS IT CAN CRASH IN UNKNOWN OCCASIONS
272
+ $payment_methods = WC()->payment_gateways->payment_gateways();
273
+ if ( $payment_methods ) foreach ( $payment_methods as $payment_method ) {
274
+ if ('yes' === $payment_method->enabled) {
275
+ echo '<option value="' . esc_attr( $payment_method->id ) . '"' . selected( in_array( $payment_method->id, $coupon_payment_method_ids ), true, false ) . '>' . esc_html( $payment_method->title ) . '</option>';
276
+ }
277
+ }
278
+ ?>
279
+ </select><?php echo WJECF_Admin_Html::wc_help_tip( __( 'One of these payment methods must be selected in order for this coupon to be valid.', 'woocommerce-jos-autocoupon' ) ); ?>
280
+ </p>
281
+ <?php
282
+ }
283
+
284
+ public function admin_coupon_metabox_customer( $thepostid, $post ) {
285
+
286
+ //=============================
287
+ //Title: "CUSTOMER RESTRICTIONS"
288
+ echo "<h3>" . esc_html( __( 'Customer restrictions', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
289
+ echo "<p><span class='description'>" . __( 'If both a customer and a role restriction are supplied, matching either one of them will suffice.' , 'woocommerce-jos-autocoupon' ) . "</span></p>\n";
290
+
291
+ //=============================
292
+ // User ids
293
+ ?>
294
+ <p class="form-field"><label><?php _e( 'Allowed Customers', 'woocommerce-jos-autocoupon' ); ?></label>
295
+ <?php
296
+ $coupon_customer_ids = WJECF()->get_coupon_customer_ids( $thepostid );
297
+ WJECF_Admin_Html::render_admin_customer_selector( 'wjecf_customer_ids', '_wjecf_customer_ids', $coupon_customer_ids );
298
+ echo WJECF_Admin_Html::wc_help_tip( __( 'Only these customers may use this coupon.', 'woocommerce-jos-autocoupon' ) );
299
+ ?>
300
+ </p>
301
+ <?php
302
+
303
+ //=============================
304
+ // User roles
305
+ ?>
306
+ <p class="form-field"><label for="wjecf_customer_roles"><?php _e( 'Allowed User Roles', 'woocommerce-jos-autocoupon' ); ?></label>
307
+ <select id="wjecf_customer_roles" name="_wjecf_customer_roles[]" style="width: 50%;" class="wc-enhanced-select" multiple="multiple" data-placeholder="<?php _e( 'Any role', 'woocommerce-jos-autocoupon' ); ?>">
308
+ <?php
309
+ $coupon_customer_roles = WJECF()->get_coupon_customer_roles( $thepostid );
310
+
311
+ $available_customer_roles = array_reverse( get_editable_roles() );
312
+ foreach ( $available_customer_roles as $role_id => $role ) {
313
+ $role_name = translate_user_role($role['name'] );
314
+
315
+ echo '<option value="' . esc_attr( $role_id ) . '"'
316
+ . selected( in_array( $role_id, $coupon_customer_roles ), true, false ) . '>'
317
+ . esc_html( $role_name ) . '</option>';
318
+ }
319
+ ?>
320
+ </select>
321
+ <?php echo WJECF_Admin_Html::wc_help_tip( __( 'Only these User Roles may use this coupon.', 'woocommerce-jos-autocoupon' ) ); ?>
322
+ </p>
323
+ <?php
324
+
325
+ //=============================
326
+ // Excluded user roles
327
+ ?>
328
+ <p class="form-field"><label for="wjecf_excluded_customer_roles"><?php _e( 'Disallowed User Roles', 'woocommerce-jos-autocoupon' ); ?></label>
329
+ <select id="wjecf_customer_roles" name="_wjecf_excluded_customer_roles[]" style="width: 50%;" class="wc-enhanced-select" multiple="multiple" data-placeholder="<?php _e( 'Any role', 'woocommerce-jos-autocoupon' ); ?>">
330
+ <?php
331
+ $coupon_excluded_customer_roles = WJECF()->get_coupon_excluded_customer_roles( $thepostid );
332
+
333
+ foreach ( $available_customer_roles as $role_id => $role ) {
334
+ $role_name = translate_user_role($role['name'] );
335
+
336
+ echo '<option value="' . esc_attr( $role_id ) . '"'
337
+ . selected( in_array( $role_id, $coupon_excluded_customer_roles ), true, false ) . '>'
338
+ . esc_html( $role_name ) . '</option>';
339
+ }
340
+ ?>
341
+ </select>
342
+ <?php echo WJECF_Admin_Html::wc_help_tip( __( 'These User Roles will be specifically excluded from using this coupon.', 'woocommerce-jos-autocoupon' ) ); ?>
343
+ </p>
344
+ <?php
345
+ }
346
+
347
+ // //REMOVED in 2.4.4: Use coupon queueing instead
348
+ // public function admin_coupon_metabox_misc( $thepostid, $post ) {
349
+ // echo "<h3>" . esc_html( __( 'Miscellaneous', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
350
+
351
+ // //=============================
352
+ // //2.2.2 Allow if minimum spend not met
353
+ // woocommerce_wp_checkbox( array(
354
+ // 'id' => '_wjecf_allow_below_minimum_spend',
355
+ // 'label' => __( 'Allow when minimum spend not reached', 'woocommerce-jos-autocoupon' ),
356
+ // 'description' => '<b>' . __( 'EXPERIMENTAL: ', 'woocommerce-jos-autocoupon' ) . '</b>' . __( 'Check this box to allow the coupon to be in the cart even when minimum spend (see tab \'usage restriction\') is not reached. Value of the discount will be 0 until minimum spend is reached.', 'woocommerce-jos-autocoupon' ),
357
+ // ) );
358
+ // }
359
+
360
+ public function admin_coupon_meta_fields( $coupon ) {
361
+ $fields = array(
362
+ '_wjecf_min_matching_product_qty' => 'int',
363
+ '_wjecf_max_matching_product_qty' => 'int',
364
+ '_wjecf_min_matching_product_subtotal' => 'decimal',
365
+ '_wjecf_max_matching_product_subtotal' => 'decimal',
366
+ '_wjecf_products_and' => 'yesno',
367
+ '_wjecf_categories_and' => 'yesno',
368
+ '_wjecf_shipping_methods' => 'clean',
369
+ '_wjecf_payment_methods' => 'clean',
370
+ '_wjecf_customer_ids' => 'int,',
371
+ '_wjecf_customer_roles' => 'clean',
372
+ '_wjecf_excluded_customer_roles' => 'clean',
373
+ );
374
+
375
+ //Espagueti
376
+ if ( WJECF()->is_pro() ) {
377
+ $fields = array_merge( $fields, WJECF()->admin_coupon_meta_fields( $coupon ) );
378
+ }
379
+ return $fields;
380
+ }
381
+
382
+ /**
383
+ * Get an array with all the metafields for all the WJECF plugins
384
+ *
385
+ * @see Abstract_WJECF_Plugin::admin_coupon_meta_fields()
386
+ *
387
+ * @param type $coupon
388
+ * @return type
389
+ */
390
+ function get_all_coupon_meta_fields( $coupon ) {
391
+ //Collect the meta_fields of all the WJECF plugins
392
+ $fields = array();
393
+ foreach ( WJECF()->get_plugins() as $name => $plugin ) {
394
+ if ( $plugin->plugin_is_enabled() ) {
395
+ $fields = array_merge( $fields, $plugin->admin_coupon_meta_fields( $coupon ) );
396
+ }
397
+ }
398
+ return $fields;
399
+ }
400
+
401
+ function process_shop_coupon_meta( $post_id, $post ) {
402
+ $coupon = WJECF_WC()->get_coupon( $post );
403
+ $wrap_coupon = WJECF_Wrap( $coupon );
404
+ $sanitizer = WJECF()->sanitizer();
405
+
406
+ $fields = $this->get_all_coupon_meta_fields( $coupon );
407
+ foreach( $fields as $key => $rule ) {
408
+ //If array contains [ 'callback' => callback, 'args' => args[] ]
409
+ //Then that callback will be called with the given args (optional)
410
+
411
+ if ( is_array( $rule ) && isset( $rule['callback'] ) && is_callable( $rule['callback'] ) ) {
412
+ $args = array( 'key' => $key );
413
+ if ( isset( $rule['args'] ) ) $args = array_merge( $args, $rule['args'] );
414
+
415
+ $value = call_user_func( $rule['callback'], $args );
416
+ } else {
417
+ $value = $sanitizer->sanitize( isset( $_POST[$key] ) ? $_POST[$key] : null, $rule );
418
+ }
419
+ if ( $value === '' ) $value = null; //Don't save empty entries
420
+
421
+ $wrap_coupon->set_meta( $key, $value ); //Always single
422
+
423
+ //error_log(sprintf("%s => %s", $key, is_array($value) ? 'array' : $value));
424
+ }
425
+
426
+ $wrap_coupon->save();
427
+ }
428
+
429
+
430
+
431
+ /**
432
+ * 2.3.6
433
+ * Add inline style (css) to the admin page. Must be called BEFORE admin_head !
434
+ * @param string $css
435
+ * @return void
436
+ */
437
+ public function add_inline_style( $css ) {
438
+ $this->admin_css .= $css;
439
+ }
440
+
441
+
442
+ /**
443
+ *
444
+ * 2.3.4
445
+ * Parse an array or comma separated string; make sure they are valid ints and return as comma separated string
446
+ * @deprecated 2.5.1 Use WJECF()->sanitizer->sanitize( ..., 'int[]' ) instead
447
+ * @param array|string $int_array
448
+ * @return string comma separated int array
449
+ */
450
+ public function comma_separated_int_array( $int_array ) {
451
+ _deprecated_function( 'comma_separated_int_array', '2.5.1', 'WJECF()->sanitizer->sanitize()' );
452
+ return WJECF()->sanitizer->sanitize( $int_array, 'int[]' );
453
+ }
454
+
455
+ /**
456
+ * Add donate-link to plugin page
457
+ */
458
+ function wjecf_plugin_meta( $links, $file ) {
459
+ if ( strpos( $file, 'woocommerce-jos-autocoupon.php' ) !== false ) {
460
+ $links = array_merge( $links, array( '<a href="' . WJECF_Admin::get_donate_url() . '" title="Support the development" target="_blank">Donate</a>' ) );
461
+ }
462
+ return $links;
463
+ }
464
+
465
+
466
+ public static function get_donate_url() {
467
+ return "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=5T9XQBCS2QHRY&lc=NL&item_name=Jos%20Koenis&item_number=wordpress%2dplugin&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted";
468
+ }
469
+ }
470
+
471
+ }
includes/admin/{wjecf-admin-auto-upgrade.php → WJECF_Admin_Data_Update.php} RENAMED
@@ -1,31 +1,32 @@
1
  <?php
2
 
3
- class WJECF_Admin_Auto_Upgrade extends Abstract_WJECF_Plugin {
4
 
5
  public function __construct() {
6
  $this->set_plugin_data( array(
7
- 'description' => __( 'Automatically upgrade data when a new version of this plugin is installed.', 'woocommerce-jos-autocoupon' ),
8
  'dependencies' => array(),
9
  'can_be_disabled' => true
10
  ) );
11
  }
12
 
13
  public function init_admin_hook() {
14
- $this->auto_upgrade();
15
  }
16
 
17
- //Upgrade options on version change
18
- public function auto_upgrade() {
19
  if ( ! class_exists('WC_Coupon') ) {
20
  return;
21
  }
22
 
23
- //WJECF()->options['db_version'] = 1;update_option( 'wjecf_options' , WJECF()->options, false ); // Will force all upgrades
24
  global $wpdb;
25
- $prev_version = WJECF()->options['db_version'];
26
-
 
27
  //DB_VERSION 1: Since 2.1.0-b5
28
- if ( WJECF()->options['db_version'] < 1 ) {
29
  //RENAME meta_key _wjecf_matching_product_qty TO _wjecf_min_matching_product_qty
30
  $where = array("meta_key" => "_wjecf_matching_product_qty");
31
  $set = array('meta_key' => "_wjecf_min_matching_product_qty");
@@ -36,22 +37,23 @@ class WJECF_Admin_Auto_Upgrade extends Abstract_WJECF_Plugin {
36
  $set = array('meta_key' => "_wjecf_is_auto_coupon");
37
  $wpdb->update( _get_meta_table('post'), $set, $where );
38
  //Now we're version 1
39
- WJECF()->options['db_version'] = 1;
40
  } //DB VERSION 1
41
 
42
  //DB_VERSION 2: Since 2.3.3-b3 No changes; but used to omit message if 2.3.3-b3 has been installed before
43
- if ( WJECF()->options['db_version'] < 2 ) {
44
- WJECF()->options['db_version'] = 2;
45
  }
46
 
47
- if ( WJECF()->options['db_version'] > 2 ) {
48
  WJECF_ADMIN()->enqueue_notice( '<p>' . __( '<strong>WooCommerce Extended Coupon Features:</strong> Please note, you\'re using an older version of this plugin, while the data was upgraded to a newer version.' , 'woocommerce-jos-autocoupon' ) . '</p>', 'notice-warning');
49
  }
50
 
51
  //An upgrade took place?
52
- if ( WJECF()->options['db_version'] != $prev_version ) {
53
  // Set version and write options to database
54
- update_option( 'wjecf_options' , WJECF()->options, false );
 
55
 
56
  WJECF_ADMIN()->enqueue_notice( '<p>' . __( '<strong>WooCommerce Extended Coupon Features:</strong> Data succesfully upgraded to the newest version.', 'woocommerce-jos-autocoupon' ) . '</p>', 'notice-success');
57
  }
@@ -61,18 +63,21 @@ class WJECF_Admin_Auto_Upgrade extends Abstract_WJECF_Plugin {
61
 
62
  // if( ! empty( $this->admin_notice_allow_cart_excluded_couponcodes ) )
63
  // {
64
- // $html = '<div class="notice notice-warning">';
65
- // $html .= '<p>';
66
- // $html .= __( '<strong>WooCommerce Extended Coupon Features:</strong> The following coupons use the deprecated option \'Allow discount on cart with excluded items\'. Please review and save them.', 'woocommerce-jos-autocoupon' );
67
- // $html .= '<ul>';
68
- // foreach( $this->admin_notice_allow_cart_excluded_couponcodes as $post_id => $coupon_code ) {
69
- // $html .= '<li><a class="post-edit-link" href="' . esc_url( get_edit_post_link( $post_id ) ) . '">' . $coupon_code . '</a></li>';
70
- // }
71
- // $html .= '</ul>';
72
- // $html .= '</p>';
73
- // $html .= '</div>';
74
- // echo $html;
75
  // }
76
  // }
 
77
  }
 
 
78
  ?>
1
  <?php
2
 
3
+ class WJECF_Admin_Data_Update extends Abstract_WJECF_Plugin {
4
 
5
  public function __construct() {
6
  $this->set_plugin_data( array(
7
+ 'description' => __( 'Automatically update data when a new version of this plugin is installed.', 'woocommerce-jos-autocoupon' ),
8
  'dependencies' => array(),
9
  'can_be_disabled' => true
10
  ) );
11
  }
12
 
13
  public function init_admin_hook() {
14
+ $this->auto_data_update();
15
  }
16
 
17
+ //Upgrade database on version change
18
+ public function auto_data_update() {
19
  if ( ! class_exists('WC_Coupon') ) {
20
  return;
21
  }
22
 
23
+ //WJECF()->set_option('db_version', 0); // Will force all upgrades
24
  global $wpdb;
25
+ $prev_version = WJECF()->get_option('db_version');
26
+ $current_version = $prev_version;
27
+
28
  //DB_VERSION 1: Since 2.1.0-b5
29
+ if ( $current_version < 1 ) {
30
  //RENAME meta_key _wjecf_matching_product_qty TO _wjecf_min_matching_product_qty
31
  $where = array("meta_key" => "_wjecf_matching_product_qty");
32
  $set = array('meta_key' => "_wjecf_min_matching_product_qty");
37
  $set = array('meta_key' => "_wjecf_is_auto_coupon");
38
  $wpdb->update( _get_meta_table('post'), $set, $where );
39
  //Now we're version 1
40
+ $current_version = 1;
41
  } //DB VERSION 1
42
 
43
  //DB_VERSION 2: Since 2.3.3-b3 No changes; but used to omit message if 2.3.3-b3 has been installed before
44
+ if ( $current_version < 2 ) {
45
+ $current_version = 2;
46
  }
47
 
48
+ if ( $current_version > 2 ) {
49
  WJECF_ADMIN()->enqueue_notice( '<p>' . __( '<strong>WooCommerce Extended Coupon Features:</strong> Please note, you\'re using an older version of this plugin, while the data was upgraded to a newer version.' , 'woocommerce-jos-autocoupon' ) . '</p>', 'notice-warning');
50
  }
51
 
52
  //An upgrade took place?
53
+ if ( $current_version != $prev_version ) {
54
  // Set version and write options to database
55
+ WJECF()->set_option( 'db_version', $current_version );
56
+ WJECF()->save_options();
57
 
58
  WJECF_ADMIN()->enqueue_notice( '<p>' . __( '<strong>WooCommerce Extended Coupon Features:</strong> Data succesfully upgraded to the newest version.', 'woocommerce-jos-autocoupon' ) . '</p>', 'notice-success');
59
  }
63
 
64
  // if( ! empty( $this->admin_notice_allow_cart_excluded_couponcodes ) )
65
  // {
66
+ // $html = '<div class="notice notice-warning">';
67
+ // $html .= '<p>';
68
+ // $html .= __( '<strong>WooCommerce Extended Coupon Features:</strong> The following coupons use the deprecated option \'Allow discount on cart with excluded items\'. Please review and save them.', 'woocommerce-jos-autocoupon' );
69
+ // $html .= '<ul>';
70
+ // foreach( $this->admin_notice_allow_cart_excluded_couponcodes as $post_id => $coupon_code ) {
71
+ // $html .= '<li><a class="post-edit-link" href="' . esc_url( get_edit_post_link( $post_id ) ) . '">' . $coupon_code . '</a></li>';
72
+ // }
73
+ // $html .= '</ul>';
74
+ // $html .= '</p>';
75
+ // $html .= '</div>';
76
+ // echo $html;
77
  // }
78
  // }
79
+
80
  }
81
+
82
+
83
  ?>
includes/admin/WJECF_Admin_Html.php ADDED
@@ -0,0 +1,333 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * HTML Output functions for admin
5
+ */
6
+ class WJECF_Admin_Html {
7
+
8
+
9
+ /**
10
+ * 2.3.6
11
+ * Renders a <SELECT> that has a default value. Relies on woocommerce_wp_select
12
+ *
13
+ * field['default_value']: The default value (if omitted the first option will be default)
14
+ * field['append_default_label']: If true or omitted the text '(DEFAULT)' will be appended to the default option caption
15
+ *
16
+ * @param array $field see wc-meta-box-functions.php:woocommerce_wp_select
17
+ * @return void
18
+ */
19
+ public static function render_select_with_default( $field ) {
20
+ global $thepostid, $post;
21
+ $thepostid = empty( $thepostid ) ? $post->ID : $thepostid;
22
+
23
+ reset( $field['options'] ); //move to first for key()
24
+ $default_value = isset( $field['default_value'] ) ? $field['default_value'] : key( $field['options'] );
25
+ $append_default_label = isset( $field['append_default_label'] ) ? $field['append_default_label'] : true;
26
+
27
+ if ( $append_default_label ) {
28
+ $field['options'][$default_value] = sprintf( __( '%s (Default)', 'woocommerce-jos-autocoupon' ), $field['options'][$default_value] );
29
+ }
30
+
31
+ if ( ! isset( $field['value'] ) ) {
32
+ $field['value'] = get_post_meta( $thepostid, $field['id'], true );
33
+ }
34
+ if ( empty( $field['value'] ) ) {
35
+ $field['value'] = $default_value;
36
+ }
37
+
38
+ woocommerce_wp_select( $field );
39
+ }
40
+
41
+ public static function render_admin_cat_selector( $dom_id, $field_name, $selected_ids, $placeholder = null ) {
42
+ if ( $placeholder === null ) $placeholder = __( 'Search for a product…', 'woocommerce' );
43
+
44
+ // Categories
45
+ ?>
46
+ <select id="<?php esc_attr_e( $dom_id ) ?>" name="<?php esc_attr_e( $field_name ) ?>[]" style="width: 50%;" class="wc-enhanced-select" multiple="multiple" data-placeholder="<?php esc_attr_e( $placeholder ); ?>">
47
+ <?php
48
+ $categories = get_terms( 'product_cat', 'orderby=name&hide_empty=0' );
49
+
50
+ if ( $categories ) foreach ( $categories as $cat ) {
51
+ echo '<option value="' . esc_attr( $cat->term_id ) . '"' . selected( in_array( $cat->term_id, $selected_ids ), true, false ) . '>' . esc_html( $cat->name ) . '</option>';
52
+ }
53
+ ?>
54
+ </select>
55
+ <?php
56
+ }
57
+
58
+
59
+ /**
60
+ * Display a WooCommerce help tip
61
+ * @param string $tip The tip to display
62
+ * @return string
63
+ */
64
+ public static function wc_help_tip( $tip ) {
65
+ //Since WC 2.5.0
66
+ if ( function_exists( 'wc_help_tip' ) ) {
67
+ return wc_help_tip( $tip );
68
+ }
69
+
70
+ return '<img class="help_tip" style="margin-top: 21px;" data-tip="' . esc_attr( $tip ) . '" src="' . esc_url( WC()->plugin_url() ) . '/assets/images/help.png" height="16" width="16" />';
71
+ }
72
+
73
+ /**
74
+ * Renders a product selection <input>. Will use either select2 v4 (WC3.0+) select2 v3 (WC2.3+) or chosen (< WC2.3)
75
+ * @param string $dom_id
76
+ * @param string $field_name
77
+ * @param array $selected_ids Array of integers
78
+ * @param string|null $placeholder
79
+ * @return void
80
+ */
81
+ public static function render_admin_product_selector( $dom_id, $field_name, $selected_ids, $placeholder = null ) {
82
+ $product_key_values = array();
83
+ foreach ( $selected_ids as $product_id ) {
84
+ $product = wc_get_product( $product_id );
85
+ if ( is_object( $product ) ) {
86
+ $product_key_values[ esc_attr( $product_id ) ] = wp_kses_post( $product->get_formatted_name() );
87
+ }
88
+ }
89
+
90
+ if ( $placeholder === null ) $placeholder = __( 'Search for a product…', 'woocommerce' );
91
+
92
+ //In WooCommerce version 2.3.0 chosen was replaced by select2
93
+ //In WooCommerce version 3.0 select2 v3 was replaced by select2 v4
94
+ if ( WJECF_WC()->check_woocommerce_version('3.0') ) {
95
+ self::render_admin_select2_v4_product_selector( $dom_id, $field_name, $product_key_values, $placeholder );
96
+ } elseif ( WJECF_WC()->check_woocommerce_version('2.3.0') ) {
97
+ self::render_admin_select2_product_selector( $dom_id, $field_name, $product_key_values, $placeholder );
98
+ } else {
99
+ self::render_admin_chosen_product_selector( $dom_id, $field_name, $product_key_values, $placeholder );
100
+ }
101
+ }
102
+
103
+
104
+ /**
105
+ * Renders a product selection <input>.
106
+ * Chosen (Legacy)
107
+ * @param string $dom_id
108
+ * @param string $field_name
109
+ * @param array $selected_ids Array of integers
110
+ * @param string|null $placeholder
111
+ */
112
+ private static function render_admin_chosen_product_selector( $dom_id, $field_name, $selected_keys_and_values, $placeholder ) {
113
+ // $selected_keys_and_values must be an array of [ id => name ]
114
+
115
+ echo '<select id="' . esc_attr( $dom_id ) . '" name="' . esc_attr( $field_name ) . '[]" class="ajax_chosen_select_products_and_variations" multiple="multiple" data-placeholder="' . esc_attr( $placeholder ) . '">';
116
+ foreach ( $selected_keys_and_values as $product_id => $product_name ) {
117
+ echo '<option value="' . $product_id . '" selected="selected">' . $product_name . '</option>';
118
+ }
119
+ echo '</select>';
120
+ }
121
+
122
+ /**
123
+ * @since 2.4.1 for WC 3.0 compatibility
124
+ *
125
+ * Renders a product selection <input>.
126
+ * Select2 version 3 (Since WC 2.3.0)
127
+ * @param string $dom_id
128
+ * @param string $field_name
129
+ * @param array $selected_ids Array of integers
130
+ * @param string|null $placeholder
131
+ */
132
+ private static function render_admin_select2_product_selector( $dom_id, $field_name, $selected_keys_and_values, $placeholder ) {
133
+ // $selected_keys_and_values must be an array of [ id => name ]
134
+
135
+ $json_encoded = esc_attr( json_encode( $selected_keys_and_values ) );
136
+ echo '<input type="hidden" class="wc-product-search" data-multiple="true" style="width: 50%;" name="'
137
+ . esc_attr( $field_name ) . '" data-placeholder="'
138
+ . esc_attr( $placeholder ) . '" data-action="woocommerce_json_search_products_and_variations" data-selected="'
139
+ . $json_encoded . '" value="' . implode( ',', array_keys( $selected_keys_and_values ) ) . '" />';
140
+
141
+ }
142
+
143
+ /**
144
+ * Renders a product selection <input>.
145
+ * Select2 version 4 (Since WC 3.0)
146
+ * @param string $dom_id
147
+ * @param string $field_name
148
+ * @param string $selected_keys_and_values
149
+ * @param string $placeholder
150
+ */
151
+ private static function render_admin_select2_v4_product_selector( $dom_id, $field_name, $selected_keys_and_values, $placeholder ) {
152
+ // $selected_keys_and_values must be an array of [ id => name ]
153
+
154
+ $json_encoded = esc_attr( json_encode( $selected_keys_and_values ) );
155
+
156
+ echo '<select id="'. esc_attr( $dom_id ) .'" class="wc-product-search" name="'
157
+ . esc_attr( $field_name ) . '[]" multiple="multiple" style="width: 50%;" data-placeholder="'
158
+ . esc_attr( $placeholder ) . '" data-action="woocommerce_json_search_products_and_variations">';
159
+
160
+ foreach ( $selected_keys_and_values as $product_id => $product_name ) {
161
+ echo '<option value="' . esc_attr( $product_id ) . '"' . selected( true, true, false ) . '>' . wp_kses_post( $product_name ) . '</option>';
162
+ }
163
+
164
+ echo '</select>';
165
+ }
166
+
167
+
168
+ /**
169
+ * Renders a customer selection <input>. Will use either select2 v4 (WC3.0+) or select2 v3 (WC2.3+)
170
+ * @param string $dom_id
171
+ * @param string $field_name
172
+ * @param array $selected_customer_ids Array of integers
173
+ * @param string|null $placeholder
174
+ * @return void
175
+ */
176
+ public static function render_admin_customer_selector( $dom_id, $field_name, $selected_customer_ids, $placeholder = null ) {
177
+ $selected_keys_and_values = array();
178
+ foreach ( $selected_customer_ids as $customer_id ) {
179
+ $customer = get_userdata( $customer_id );
180
+ if ( is_object( $customer ) ) {
181
+ $selected_keys_and_values[ $customer_id ] = $customer->display_name . ' (#' . $customer->ID . ' &ndash; ' . sanitize_email( $customer->user_email ) . ')';
182
+ }
183
+ }
184
+ if ( $placeholder === null ) $placeholder = __( 'Any customer', 'woocommerce-jos-autocoupon' );
185
+
186
+ //In WooCommerce version 2.3.0 chosen was replaced by select2
187
+ //In WooCommerce version 3.0 select2 v3 was replaced by select2 v4
188
+ if ( WJECF_WC()->check_woocommerce_version('3.0') ) {
189
+ self::render_admin_select2_v4_customer_selector( $dom_id, $field_name, $selected_keys_and_values, $placeholder );
190
+ } else {
191
+ self::render_admin_select2_customer_selector( $dom_id, $field_name, $selected_keys_and_values, $placeholder );
192
+ }
193
+ }
194
+
195
+ private static function render_admin_select2_customer_selector( $dom_id, $field_name, $selected_keys_and_values, $placeholder ) {
196
+ // $selected_keys_and_values must be an array of [ id => name ] .e.g. [ 12 => 'John Smith (#12 john.smith@example.com)' ]
197
+
198
+ $json_encoded = esc_attr( json_encode( $selected_keys_and_values ) );
199
+ echo '<input type="hidden" class="wc-customer-search" data-multiple="true" style="width: 50%;" name="'
200
+ . esc_attr( $field_name ) . '" data-placeholder="'
201
+ . esc_attr( $placeholder ) . '" data-action="woocommerce_json_search_customers" data-selected="'
202
+ . $json_encoded . '" value="' . implode( ',', array_keys( $selected_keys_and_values ) ) . '" />';
203
+ }
204
+
205
+ private static function render_admin_select2_v4_customer_selector( $dom_id, $field_name, $selected_keys_and_values, $placeholder ) {
206
+ // $selected_keys_and_values must be an array of [ id => name ]
207
+
208
+ $json_encoded = esc_attr( json_encode( $selected_keys_and_values ) );
209
+
210
+ echo '<select id="'. esc_attr( $dom_id ) .'" class="wc-customer-search" name="'
211
+ . esc_attr( $field_name ) . '[]" multiple="multiple" style="width: 50%;" data-placeholder="'
212
+ . esc_attr( $placeholder ) . '" data-action="woocommerce_json_search_customers">';
213
+
214
+ foreach ( $selected_keys_and_values as $key => $value ) {
215
+ echo '<option value="' . esc_attr( $key ) . '"' . selected( true, true, false ) . '>' . wp_kses_post( $value ) . '</option>';
216
+ }
217
+
218
+ echo '</select>';
219
+ }
220
+
221
+ // ============================================
222
+ // Simple html output
223
+
224
+
225
+ /**
226
+ * Renders a <input type='text' />
227
+ * $args should be an array in this form:
228
+ * [ 'type' => 'text', name' => 'field-name', 'id' => 'dom-id', 'value' => 'value', 'class' => 'css-class' ]
229
+ * @param array $args
230
+ */
231
+ public static function render_input( $args )
232
+ {
233
+ if ( ! isset( $args['type'] ) ) throw new Exception('Type field is obligatory.');
234
+
235
+ $fields = array();
236
+ switch ( $args['type'] ) {
237
+ case 'text':
238
+ $fields['type'] = 'text';
239
+ if ( isset( $args['value'] ) ) $fields['value'] = esc_attr( $args['value'] );
240
+ break;
241
+
242
+ case 'hidden':
243
+ $fields['type'] = 'hidden';
244
+ if ( isset( $args['value'] ) ) $fields['value'] = esc_attr( $args['value'] );
245
+ break;
246
+
247
+ case 'radio':
248
+ $fields['type'] = 'radio';
249
+ if ( isset( $args['checked'] ) && $args['checked'] ) $fields['checked'] = esc_attr( $args['checked'] );
250
+ if ( isset( $args['disabled'] ) && $args['disabled'] ) $fields['disabled'] = 'disabled';
251
+
252
+ if ( isset( $args['value'] ) ) $fields['value'] = esc_attr( $args['value'] );
253
+ break;
254
+
255
+ case 'checkbox':
256
+ $fields['type'] = 'checkbox';
257
+ if ( isset( $args['disabled'] ) && $args['disabled'] ) $fields['disabled'] = 'disabled';
258
+
259
+ $fields['value'] = isset( $args['cbvalue'] ) ? $args['cbvalue'] : 'yes';
260
+ if ( isset( $args['value'] ) && (string) $args['value'] === (string) $fields['value'] ) {
261
+ $fields['checked'] = "checked";
262
+ }
263
+
264
+ if ( ! empty( $field['description'] ) && false === $field['desc_tip'] ) {
265
+ echo '<span class="description">' . wp_kses_post( $field['description'] ) . '</span>';
266
+ }
267
+ break;
268
+
269
+ default:
270
+ throw new Exception( sprintf( 'Unknown field type "%s" is obligatory.', $args['type'] ) );
271
+ }
272
+
273
+ //var_dump($args);
274
+ if ( isset( $args['name'] ) ) $fields['name'] = esc_attr( $args['name'] );
275
+ if ( isset( $args['id'] ) ) $fields['id'] = esc_attr( $args['id'] );
276
+ if ( isset( $args['class'] ) ) $fields['class'] = esc_attr( $args['class'] );
277
+
278
+ self::render_tag( 'input', $fields );
279
+ }
280
+
281
+ /**
282
+ * Renders a html tag:
283
+ * e.g. <name field="value">contents</name>
284
+ *
285
+ * This function does not escape the fields! Keys must be valid attribute names and values MUST be properly escaped!!!
286
+ *
287
+ * @param string $name
288
+ * @param array $fields E.g. [ 'class' => 'clearfix' ] yields: class="clearfix"
289
+ * @param string|null $contents If null the html tag will be self closing
290
+ * @return void
291
+ */
292
+ public static function render_tag( $name, $fields = array(), $contents = null ) {
293
+ echo self::tag( $name, $fields, $contents );
294
+ }
295
+
296
+ /**
297
+ * Returns a html tag:
298
+ * e.g. <name field="value">contents</name>
299
+ *
300
+ * This function does not escape the fields! Keys must be valid attribute names and values MUST be properly escaped!!!
301
+ *
302
+ * @param string $name
303
+ * @param array $fields E.g. [ 'class' => 'clearfix' ] yields: class="clearfix"
304
+ * @param string|null $contents If null the html tag will be self closing
305
+ * @return string
306
+ */
307
+ protected static function tag( $name, $fields = array(), $contents = null ) {
308
+ if ( is_null( $contents ) ) {
309
+ return sprintf( "<%s %s/>", $name, self::extract_attributes( $fields ) );
310
+ } else {
311
+ return sprintf( "<%s %s>%s</%s>", $name, self::extract_attributes( $fields ), $contents, $name );
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Extracts fields to attributes for html tags.
317
+ * E.g. [ 'class' => 'clearfix' ] yields: class="clearfix"
318
+ *
319
+ * This function does not escape the fields! Keys must be valid attribute names and values MUST be properly escaped!!!
320
+ *
321
+ * @param array $fields
322
+ * @return string
323
+ */
324
+ protected static function extract_attributes( $fields ) {
325
+ //NOTE: attrib and value MUST be properly escaped!!!
326
+ $extracted = "";
327
+ foreach( $fields as $field => $value ) {
328
+ $extracted .= sprintf( '%s="%s" ', $field, $value );
329
+ }
330
+ return $extracted;
331
+ }
332
+
333
+ }
includes/admin/WJECF_Admin_Settings.php ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ defined('ABSPATH') or die();
4
+
5
+ if ( class_exists('WJECF_Admin') ) {
6
+ return;
7
+ }
8
+
9
+ class WJECF_Admin_Settings extends Abstract_WJECF_Plugin {
10
+ const DOM_PREFIX = 'wjecf-';
11
+ const SETTINGS_PAGE = 'wjecf_settings'; // In the wp_options table
12
+ const OPTION_NAME = 'wjecf_options'; // In the wp_options table
13
+
14
+ public function __construct() {
15
+ $this->set_plugin_data( array(
16
+ 'description' => __( 'Settings page of WooCommerce Extended Coupon Features.', 'woocommerce-jos-autocoupon' ),
17
+ 'dependencies' => array(),
18
+ 'can_be_disabled' => false
19
+ ) );
20
+ }
21
+
22
+ public function init_admin_hook() {
23
+ //return;
24
+ add_action( 'admin_menu', array( $this, 'action_admin_menu' ) );
25
+ add_action( 'admin_init', array( $this, 'action_admin_init' ) );
26
+ }
27
+
28
+ public function action_admin_menu() {
29
+ add_options_page( __( 'WooCommerce Extended Coupon Features', 'woocommerce-jos-autocoupon' ), __( 'WooCommerce Extended Coupon Features', 'woocommerce-jos-autocoupon' ), 'manage_options', self::SETTINGS_PAGE, array( &$this, 'action_admin_config_page' ) );
30
+ }
31
+
32
+ public function action_admin_config_page() {
33
+ ?>
34
+ <h2><?php _e( 'WooCommerce Extended Coupon Features', 'woocommerce-jos-autocoupon' ); ?></h2>
35
+ <form method="post" action="options.php">
36
+ <?php
37
+ settings_fields( self::SETTINGS_PAGE );
38
+ do_settings_sections( self::SETTINGS_PAGE );
39
+ submit_button();
40
+ ?>
41
+ </form>
42
+ <?php
43
+ }
44
+
45
+
46
+ public function action_admin_init() {
47
+ $page = self::SETTINGS_PAGE;
48
+
49
+ register_setting( self::SETTINGS_PAGE, self::OPTION_NAME, array( $this, 'validate_settings' ) );
50
+
51
+ // Section DEBUG
52
+ add_settings_section(
53
+ self::DOM_PREFIX . 'section_debug',
54
+ __( 'Advanced settings', 'woocommerce-jos-autocoupon' ),
55
+ array( &$this, 'render_section' ),
56
+ $page
57
+ );
58
+
59
+ add_settings_field(
60
+ self::DOM_PREFIX . 'debug_mode',
61
+ __( 'Debug mode', 'woocommerce-jos-autocoupon' ),
62
+ array( $this, 'render_setting_debug_mode' ),
63
+ $page,
64
+ self::DOM_PREFIX . 'section_debug'
65
+ );
66
+
67
+ if ( WJECF()->get_option( 'debug_mode' ) === true ) {
68
+ foreach ( WJECF()->get_plugins() as $name => $plugin ) {
69
+ if ( $plugin->get_plugin_data('can_be_disabled') || WJECF()->get_option('debug_mode') ) {
70
+ add_settings_field(
71
+ self::DOM_PREFIX . 'plugin-' . $name,
72
+ $plugin->get_plugin_class_name(),
73
+ array( $this, 'render_setting_plugin' ),
74
+ $page,
75
+ self::DOM_PREFIX . 'section_debug', //section
76
+ array(
77
+ 'plugin' => $plugin,
78
+ ) //arguments
79
+ );
80
+ }
81
+ }
82
+ } else {
83
+ $disabled_plugins = WJECF()->get_option('disabled_plugins');
84
+ if ( ! empty( $disabled_plugins ) ) {
85
+ add_settings_field(
86
+ self::DOM_PREFIX . 'disabled_plugins',
87
+ __( 'Disabled plugins', 'woocommerce-jos-autocoupon' ),
88
+ array( $this, 'render_setting_disabled_plugins' ),
89
+ $page,
90
+ self::DOM_PREFIX . 'section_debug' //section
91
+ );
92
+ }
93
+ }
94
+
95
+
96
+ }
97
+
98
+ public function validate_settings( $input ) {
99
+
100
+ $options = WJECF()->get_options();
101
+
102
+ //disabled_plugins
103
+ if ( is_array( $input['disabled_plugins'] ) ) {
104
+ foreach( $input['disabled_plugins'] as $class_name => $disabled ) {
105
+
106
+ $plugin = WJECF()->get_plugin( $class_name );
107
+ if ( $plugin === false ) {
108
+ continue; //unknown / invalid plugin
109
+ }
110
+
111
+ //Never disable those
112
+ if ( ! $plugin->get_plugin_data('can_be_disabled') ) $disabled = 'no';
113
+
114
+ //false if not found; otherwise the index
115
+ $index = array_search( $class_name, $options['disabled_plugins'] );
116
+
117
+ if ( $disabled == 'yes' && $index === false ) {
118
+ $options['disabled_plugins'][] = $class_name;
119
+ }
120
+ elseif ( $disabled == 'no' && $index !== false )
121
+ {
122
+ unset( $options['disabled_plugins'][$index] );
123
+ }
124
+ }
125
+ }
126
+
127
+ //debug_mode
128
+ $options['debug_mode'] = isset( $input['debug_mode'] ) && $input['debug_mode'] === 'yes';
129
+
130
+ return $options;
131
+
132
+ }
133
+
134
+ public function render_section( $section ) {
135
+ switch ( $section['id'] ) {
136
+
137
+ case self::DOM_PREFIX . 'section_debug':
138
+ $body = __( 'When debug mode is enabled, extensive logging will be active and WJECF Plugins can be enabled/disabled. If there are compatibility issues with WooCommerce plugins, you can try disabling WJECF Plugins. Please don\'t keep debug mode enabled on a production environment when it is not necessary. Log can be found <a href="%s">here</a>.' , 'woocommerce-jos-autocoupon' );
139
+ $body = sprintf( $body, admin_url( 'admin.php?page=wc-status&tab=logs' ) );
140
+ printf( '<p>%s</p>', $body );
141
+ break;
142
+
143
+ }
144
+
145
+ }
146
+
147
+ /**
148
+ *
149
+ * Renders the enable/disable checkbox for a plugin
150
+ *
151
+ * Arguments: [ 'plugin' => WJECF_Plugin object ]
152
+ *
153
+ * @param array $arguments
154
+ * @return void
155
+ */
156
+ public function render_setting_plugin( $arguments ) {
157
+ //var_dump($arguments);
158
+
159
+ $plugin = $arguments['plugin'];
160
+ $plugin_name = $plugin->get_plugin_class_name();
161
+ $plugin_disabled = $plugin->get_plugin_data('can_be_disabled') && in_array( $plugin_name, WJECF()->get_option( 'disabled_plugins' ) );
162
+
163
+ //This field yields the value if the checbox is not checked
164
+ //Don't draw this if plugin can't be disabled; as a disabled checkbox will not return a value
165
+ $args = array(
166
+ 'type' => 'hidden',
167
+ 'id' => self::DOM_PREFIX . 'plugin-' . $plugin_name . '-enabled',
168
+ 'name' => sprintf( "%s[disabled_plugins][%s]", self::OPTION_NAME, $plugin_name ),
169
+ 'value' => $plugin->get_plugin_data('can_be_disabled') ? 'yes' : 'no' //yes = disabled
170
+ );
171
+ WJECF_Admin_Html::render_input( $args );
172
+
173
+ $args = array(
174
+ 'type' => 'checkbox',
175
+ 'id' => self::DOM_PREFIX . 'plugin-' . $plugin_name . '-disabled',
176
+ 'name' => sprintf( "%s[disabled_plugins][%s]", self::OPTION_NAME, $plugin_name ),
177
+ 'value' => $plugin_disabled ? 'yes' : 'no',
178
+ 'cbvalue' => 'no' //no = enabled
179
+ );
180
+ if ( ! $plugin->get_plugin_data('can_be_disabled') ) $args['disabled'] = true;
181
+
182
+ WJECF_Admin_Html::render_input( $args );
183
+
184
+ WJECF_Admin_Html::render_tag(
185
+ 'label',
186
+ array( "for" => esc_attr( $args['id'] ) ),
187
+ __( 'Enabled', 'woocommerce' )
188
+ );
189
+ echo '<br>';
190
+
191
+ printf( '<p><i>%s</i></p>',
192
+ $plugin->get_plugin_description()
193
+ );
194
+
195
+ //echo $plugin->get_plugin_description();
196
+ //echo "</p>\n";
197
+ //echo "</li>\n";
198
+ }
199
+
200
+ public function render_setting_disabled_plugins() {
201
+ echo "<ul>";
202
+ foreach( WJECF()->get_option( 'disabled_plugins' ) as $class_name ) {
203
+ $plugin = WJECF()->get_plugin( $class_name );
204
+ if ( $plugin ) {
205
+ echo "<li><strong>" . $class_name . "</strong><br><i>" . $plugin->get_plugin_description() . "</i></li>";
206
+ }
207
+ }
208
+ echo "</ul>";
209
+ }
210
+
211
+ public function render_setting_debug_mode() {
212
+ $option_name = 'debug_mode';
213
+ $args = array(
214
+ 'type' => 'checkbox',
215
+ 'id' => self::DOM_PREFIX . $option_name,
216
+ 'name' => sprintf( "%s[%s]", self::OPTION_NAME, $option_name ),
217
+ 'value' => WJECF()->get_option( $option_name ) ? 'yes' : 'no'
218
+ );
219
+ WJECF_Admin_Html::render_input( $args );
220
+
221
+ WJECF_Admin_Html::render_tag(
222
+ 'label',
223
+ array( "for" => esc_attr( $args['id'] ) ),
224
+ __( 'Enabled', 'woocommerce' )
225
+ );
226
+
227
+ }
228
+
229
+
230
+ }
includes/admin/wjecf-admin.php DELETED
@@ -1,527 +0,0 @@
1
- <?php
2
-
3
- defined('ABSPATH') or die();
4
-
5
- if ( class_exists('WJECF_Admin') ) {
6
- return;
7
- }
8
-
9
- class WJECF_Admin extends Abstract_WJECF_Plugin {
10
-
11
- public function __construct() {
12
- $this->set_plugin_data( array(
13
- 'description' => __( 'Admin interface of WooCommerce Extended Coupon Features.', 'woocommerce-jos-autocoupon' ),
14
- 'dependencies' => array(),
15
- 'can_be_disabled' => false
16
- ) );
17
- }
18
-
19
- public function init_admin_hook() {
20
- add_action( 'admin_notices', array( $this, 'admin_notices'));
21
-
22
- if ( ! WJECF_WC()->check_woocommerce_version('2.3.0') ) {
23
- $this->enqueue_notice( '<p>' .
24
- __( '<strong>WooCommerce Extended Coupon Features:</strong> You are using an old version of WooCommerce. Updating of WooCommerce is recommended as using an outdated version might cause unexpected behaviour in combination with modern plugins.' )
25
- . '</p>', 'notice-warning' );
26
- }
27
- //Admin hooks
28
- add_filter( 'plugin_row_meta', array( $this, 'wjecf_plugin_meta' ), 10, 2 );
29
- add_action( 'admin_head', array( $this, 'on_admin_head'));
30
-
31
- add_filter( 'woocommerce_coupon_data_tabs', array( $this, 'admin_coupon_options_tabs' ), 10, 1);
32
- add_action( 'woocommerce_coupon_data_panels', array( $this, 'admin_coupon_options_panels' ), 10, 0 );
33
- add_action( 'woocommerce_process_shop_coupon_meta', array( $this, 'process_shop_coupon_meta' ), 10, 2 );
34
-
35
- add_action( 'wjecf_coupon_metabox_products', array( $this, 'admin_coupon_metabox_products' ), 10, 2 );
36
- add_action( 'wjecf_coupon_metabox_checkout', array( $this, 'admin_coupon_metabox_checkout' ), 10, 2 );
37
- add_action( 'wjecf_coupon_metabox_customer', array( $this, 'admin_coupon_metabox_customer' ), 10, 2 );
38
- add_action( 'wjecf_coupon_metabox_misc', array( $this, 'admin_coupon_metabox_misc' ), 10, 2 );
39
-
40
- WJECF_ADMIN()->add_inline_style( '
41
- #woocommerce-coupon-data .wjecf-not-wide { width:50% }
42
- ');
43
-
44
- //WORK IN PROGRESS: add_action( 'admin_menu', array( $this, 'action_admin_menu' ) );
45
- }
46
-
47
- // ===========================================================================
48
- // START - ADMIN NOTICES
49
- // Allows notices to be displayed on the admin pages
50
- // ===========================================================================
51
-
52
- private $notices = array();
53
-
54
- /**
55
- * Enqueue a notice to display on the admin page
56
- * @param stirng $html Please embed in <p> tags
57
- * @param string $class
58
- */
59
- public function enqueue_notice( $html, $class = 'notice-info' ) {
60
- $this->notices[] = array( 'class' => $class, 'html' => $html );
61
- }
62
-
63
- public function admin_notices() {
64
- foreach( $this->notices as $notice ) {
65
- echo '<div class="notice ' . $notice['class'] . '">';
66
- echo $notice['html'];
67
- echo '</div>';
68
- }
69
- }
70
-
71
- // ===========================================================================
72
- // END - ADMIN NOTICES
73
- // ===========================================================================
74
-
75
- public function action_admin_menu() {
76
- add_options_page( __( 'WooCommerce Extended Coupon Features', 'soft79-wc-pricing-rules' ), __( 'WooCommerce Extended Coupon Features', 'soft79-wc-pricing-rules' ), 'manage_options', 'wjecf_settings', array( &$this, 'action_admin_config_page' ) );
77
- }
78
-
79
- public function action_admin_config_page() {
80
- ?>
81
- <h2><?php _e( 'WooCommerce Extended Coupon Features', 'soft79-wc-pricing-rules' ); ?></h2>
82
- <form method="post" action="options.php">
83
- <?php
84
- settings_fields( 'wjecf_settings' );
85
- do_settings_sections( 'wjecf_settings' );
86
- ?>
87
- <?php submit_button(); ?>
88
- </form>
89
- <h3><?php _e( 'Plugins', 'soft79-wc-pricing-rules' ); ?></h3>
90
- <ul>
91
- <?php
92
- foreach ( WJECF()->get_plugins() as $name => $plugin ) {
93
- echo "<li><h3>" . $plugin->get_plugin_class_name() . "</h3>\n";
94
- echo "<p>" . $plugin->get_plugin_description() . "</p>\n";
95
- echo "</li>\n";
96
- }
97
- ?>
98
- </ul>
99
- <?php
100
-
101
- }
102
-
103
- //2.3.6 Inline css
104
- private $admin_css = '';
105
-
106
- /**
107
- * 2.3.6
108
- * @return void
109
- */
110
- function on_admin_head() {
111
- //Output inline style for the admin pages
112
- if ( ! empty( $this->admin_css ) ) {
113
- echo '<style type="text/css">' . $this->admin_css . '</style>';
114
- $this->admin_css = '';
115
- }
116
-
117
- //Enqueue scripts
118
- wp_enqueue_script( "wjecf-admin", WJECF()->plugin_url . "assets/js/wjecf-admin.js", array( 'jquery' ), WJECF()->version );
119
- wp_localize_script( 'wjecf-admin', 'wjecf_admin_i18n', array(
120
- 'label_and' => __( '(AND)', 'woocommerce-jos-autocoupon' ),
121
- 'label_or' => __( '(OR)', 'woocommerce-jos-autocoupon' )
122
- ) );
123
-
124
- }
125
-
126
-
127
- //Add tabs to the coupon option page
128
- public function admin_coupon_options_tabs( $tabs ) {
129
-
130
- $tabs['extended_features_products'] = array(
131
- 'label' => __( 'Products', 'woocommerce-jos-autocoupon' ),
132
- 'target' => 'wjecf_coupondata_products',
133
- 'class' => 'wjecf_coupondata_products',
134
- );
135
-
136
- $tabs['extended_features_checkout'] = array(
137
- 'label' => __( 'Checkout', 'woocommerce-jos-autocoupon' ),
138
- 'target' => 'wjecf_coupondata_checkout',
139
- 'class' => 'wjecf_coupondata_checkout',
140
- );
141
-
142
- $tabs['extended_features_misc'] = array(
143
- 'label' => __( 'Miscellaneous', 'woocommerce-jos-autocoupon' ),
144
- 'target' => 'wjecf_coupondata_misc',
145
- 'class' => 'wjecf_coupondata_misc',
146
- );
147
-
148
- return $tabs;
149
- }
150
-
151
- //Add panels to the coupon option page
152
- public function admin_coupon_options_panels() {
153
- global $thepostid, $post;
154
- $thepostid = empty( $thepostid ) ? $post->ID : $thepostid;
155
- ?>
156
- <div id="wjecf_coupondata_products" class="panel woocommerce_options_panel">
157
- <?php
158
- //Feed the panel with options
159
- do_action( 'wjecf_coupon_metabox_products', $thepostid, $post );
160
- $this->admin_coupon_data_footer();
161
- ?>
162
- </div>
163
- <div id="wjecf_coupondata_checkout" class="panel woocommerce_options_panel">
164
- <?php
165
- do_action( 'wjecf_coupon_metabox_checkout', $thepostid, $post );
166
- do_action( 'wjecf_coupon_metabox_customer', $thepostid, $post );
167
- $this->admin_coupon_data_footer();
168
- ?>
169
- </div>
170
- <div id="wjecf_coupondata_misc" class="panel woocommerce_options_panel">
171
- <?php
172
- //Allow other classes to inject options
173
- do_action( 'wjecf_woocommerce_coupon_options_extended_features', $thepostid, $post );
174
- do_action( 'wjecf_coupon_metabox_misc', $thepostid, $post );
175
- $this->admin_coupon_data_footer();
176
- ?>
177
- </div>
178
- <?php
179
- }
180
-
181
- public function admin_coupon_data_footer() {
182
- $documentation_url = plugins_url( 'docs/index.html', dirname( __FILE__ ) );
183
- if ( ! WJECF()->is_pro() ) {
184
- $documentation_url = 'http://www.soft79.nl/documentation/wjecf';
185
- ?>
186
- <h3><?php _e( 'Do you find WooCommerce Extended Coupon Features useful?', 'woocommerce-jos-autocoupon'); ?></h3>
187
- <p class="form-field"><label for="wjecf_donate_button"><?php
188
- echo esc_html( __('Express your gratitude', 'woocommerce-jos-autocoupon' ) );
189
- ?></label>
190
- <a id="wjecf_donate_button" href="<?php echo $this->get_donate_url(); ?>" target="_blank" class="button button-primary">
191
- <?php
192
- echo esc_html( __('Donate to the developer', 'woocommerce-jos-autocoupon' ) );
193
- ?></a><br>
194
- Or get the PRO version at <a href="http://www.soft79.nl" target="_blank">www.soft79.nl</a>.
195
- </p>
196
- <?php
197
- }
198
- //Documentation link
199
- echo '<h3>' . __( 'Documentation', 'woocommerce-jos-autocoupon' ) . '</h3>';
200
- echo '<p><a href="' . $documentation_url . '" target="_blank">' .
201
- __( 'WooCommerce Extended Coupon Features Documentation', 'woocommerce-jos-autocoupon' ) . '</a></p>';
202
-
203
- }
204
-
205
- //Tab 'extended features'
206
- public function admin_coupon_metabox_products( $thepostid, $post ) {
207
- //See WooCommerce class-wc-meta-box-coupon-data.php function ouput
208
-
209
- echo "<h3>" . esc_html( __( 'Matching products', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
210
- //=============================
211
- // AND instead of OR the products
212
- $this->render_select_with_default( array(
213
- 'id' => '_wjecf_products_and',
214
- 'label' => __( 'Products Operator', 'woocommerce-jos-autocoupon' ),
215
- 'options' => array( 'no' => __( 'OR', 'woocommerce-jos-autocoupon' ), 'yes' => __( 'AND', 'woocommerce-jos-autocoupon' ) ),
216
- 'default_value' => 'no',
217
- 'class' => 'wjecf-not-wide',
218
- /* translators: OLD TEXT: 'Check this box if ALL of the products (see tab \'usage restriction\') must be in the cart to use this coupon (instead of only one of the products).' */
219
- 'description' => __( 'Use AND if ALL of the products must be in the cart to use this coupon (instead of only one of the products).', 'woocommerce-jos-autocoupon' ),
220
- 'desc_tip' => true
221
- ) );
222
-
223
- //=============================
224
- // 2.2.3.1 AND instead of OR the categories
225
- $this->render_select_with_default( array(
226
- 'id' => '_wjecf_categories_and',
227
- 'label' => __( 'Categories Operator', 'woocommerce-jos-autocoupon' ),
228
- 'options' => array( 'no' => __( 'OR', 'woocommerce-jos-autocoupon' ), 'yes' => __( 'AND', 'woocommerce-jos-autocoupon' ) ),
229
- 'default_value' => 'no',
230
- 'class' => 'wjecf-not-wide',
231
- /* translators: OLD TEXT: 'Check this box if products from ALL of the categories (see tab \'usage restriction\') must be in the cart to use this coupon (instead of only one from one of the categories).' */
232
- 'description' => __( 'Use AND if products from ALL of the categories must be in the cart to use this coupon (instead of only one from one of the categories).', 'woocommerce-jos-autocoupon' ),
233
- 'desc_tip' => true
234
- ) );
235
-
236
-
237
-
238
- // Minimum quantity of matching products (product/category)
239
- woocommerce_wp_text_input( array(
240
- 'id' => '_wjecf_min_matching_product_qty',
241
- 'label' => __( 'Minimum quantity of matching products', 'woocommerce-jos-autocoupon' ),
242
- 'placeholder' => __( 'No minimum', 'woocommerce' ),
243
- 'description' => __( 'Minimum quantity of the products that match the given product or category restrictions (see tab \'usage restriction\'). If no product or category restrictions are specified, the total number of products is used.', 'woocommerce-jos-autocoupon' ),
244
- 'data_type' => 'decimal',
245
- 'desc_tip' => true
246
- ) );
247
-
248
- // Maximum quantity of matching products (product/category)
249
- woocommerce_wp_text_input( array(
250
- 'id' => '_wjecf_max_matching_product_qty',
251
- 'label' => __( 'Maximum quantity of matching products', 'woocommerce-jos-autocoupon' ),
252
- 'placeholder' => __( 'No maximum', 'woocommerce' ),
253
- 'description' => __( 'Maximum quantity of the products that match the given product or category restrictions (see tab \'usage restriction\'). If no product or category restrictions are specified, the total number of products is used.', 'woocommerce-jos-autocoupon' ),
254
- 'data_type' => 'decimal',
255
- 'desc_tip' => true
256
- ) );
257
-
258
- // Minimum subtotal of matching products (product/category)
259
- woocommerce_wp_text_input( array(
260
- 'id' => '_wjecf_min_matching_product_subtotal',
261
- 'label' => __( 'Minimum subtotal of matching products', 'woocommerce-jos-autocoupon' ),
262
- 'placeholder' => __( 'No minimum', 'woocommerce' ),
263
- 'description' => __( 'Minimum price subtotal of the products that match the given product or category restrictions (see tab \'usage restriction\').', 'woocommerce-jos-autocoupon' ),
264
- 'data_type' => 'price',
265
- 'desc_tip' => true
266
- ) );
267
-
268
- // Maximum subtotal of matching products (product/category)
269
- woocommerce_wp_text_input( array(
270
- 'id' => '_wjecf_max_matching_product_subtotal',
271
- 'label' => __( 'Maximum subtotal of matching products', 'woocommerce-jos-autocoupon' ),
272
- 'placeholder' => __( 'No maximum', 'woocommerce' ),
273
- 'description' => __( 'Maximum price subtotal of the products that match the given product or category restrictions (see tab \'usage restriction\').', 'woocommerce-jos-autocoupon' ),
274
- 'data_type' => 'price',
275
- 'desc_tip' => true
276
- ) );
277
- }
278
-
279
- public function admin_coupon_metabox_checkout( $thepostid, $post ) {
280
-
281
- echo "<h3>" . esc_html( __( 'Checkout', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
282
-
283
- //=============================
284
- // Shipping methods
285
- ?>
286
- <p class="form-field"><label for="wjecf_shipping_methods"><?php _e( 'Shipping methods', 'woocommerce-jos-autocoupon' ); ?></label>
287
- <select id="wjecf_shipping_methods" name="wjecf_shipping_methods[]" style="width: 50%;" class="wc-enhanced-select" multiple="multiple" data-placeholder="<?php _e( 'Any shipping method', 'woocommerce-jos-autocoupon' ); ?>">
288
- <?php
289
- $coupon_shipping_method_ids = WJECF()->get_coupon_shipping_method_ids( $thepostid );
290
- $shipping_methods = WC()->shipping->load_shipping_methods();
291
-
292
- if ( $shipping_methods ) foreach ( $shipping_methods as $shipping_method ) {
293
- echo '<option value="' . esc_attr( $shipping_method->id ) . '"' . selected( in_array( $shipping_method->id, $coupon_shipping_method_ids ), true, false ) . '>' . esc_html( $shipping_method->method_title ) . '</option>';
294
- }
295
- ?>
296
- </select><?php echo WJECF_WC()->wc_help_tip( __( 'One of these shipping methods must be selected in order for this coupon to be valid.', 'woocommerce-jos-autocoupon' ) ); ?>
297
- </p>
298
- <?php
299
-
300
- //=============================
301
- // Payment methods
302
- ?>
303
- <p class="form-field"><label for="wjecf_payment_methods"><?php _e( 'Payment methods', 'woocommerce-jos-autocoupon' ); ?></label>
304
- <select id="wjecf_payment_methods" name="wjecf_payment_methods[]" style="width: 50%;" class="wc-enhanced-select" multiple="multiple" data-placeholder="<?php _e( 'Any payment method', 'woocommerce-jos-autocoupon' ); ?>">
305
- <?php
306
- $coupon_payment_method_ids = WJECF()->get_coupon_payment_method_ids( $thepostid );
307
- //DONT USE WC()->payment_gateways->available_payment_gateways() AS IT CAN CRASH IN UNKNOWN OCCASIONS
308
- $payment_methods = WC()->payment_gateways->payment_gateways();
309
- if ( $payment_methods ) foreach ( $payment_methods as $payment_method ) {
310
- if ('yes' === $payment_method->enabled) {
311
- echo '<option value="' . esc_attr( $payment_method->id ) . '"' . selected( in_array( $payment_method->id, $coupon_payment_method_ids ), true, false ) . '>' . esc_html( $payment_method->title ) . '</option>';
312
- }
313
- }
314
- ?>
315
- </select><?php echo WJECF_WC()->wc_help_tip( __( 'One of these payment methods must be selected in order for this coupon to be valid.', 'woocommerce-jos-autocoupon' ) ); ?>
316
- </p>
317
- <?php
318
- }
319
-
320
- public function admin_coupon_metabox_customer( $thepostid, $post ) {
321
-
322
- //=============================
323
- //Title: "CUSTOMER RESTRICTIONS"
324
- echo "<h3>" . esc_html( __( 'Customer restrictions', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
325
- echo "<p><span class='description'>" . __( 'If both a customer and a role restriction are supplied, matching either one of them will suffice.' , 'woocommerce-jos-autocoupon' ) . "</span></p>\n";
326
-
327
- //=============================
328
- // User ids
329
- ?>
330
- <p class="form-field"><label><?php _e( 'Allowed Customers', 'woocommerce-jos-autocoupon' ); ?></label>
331
- <?php
332
- $coupon_customer_ids = WJECF()->get_coupon_customer_ids( $thepostid );
333
- WJECF_WC()->render_admin_customer_selector( 'wjecf_customer_ids', 'wjecf_customer_ids', $coupon_customer_ids );
334
- echo WJECF_WC()->wc_help_tip( __( 'Only these customers may use this coupon.', 'woocommerce-jos-autocoupon' ) );
335
- ?>
336
- </p>
337
- <?php
338
-
339
- //=============================
340
- // User roles
341
- ?>
342
- <p class="form-field"><label for="wjecf_customer_roles"><?php _e( 'Allowed User Roles', 'woocommerce-jos-autocoupon' ); ?></label>
343
- <select id="wjecf_customer_roles" name="wjecf_customer_roles[]" style="width: 50%;" class="wc-enhanced-select" multiple="multiple" data-placeholder="<?php _e( 'Any role', 'woocommerce-jos-autocoupon' ); ?>">
344
- <?php
345
- $coupon_customer_roles = WJECF()->get_coupon_customer_roles( $thepostid );
346
-
347
- $available_customer_roles = array_reverse( get_editable_roles() );
348
- foreach ( $available_customer_roles as $role_id => $role ) {
349
- $role_name = translate_user_role($role['name'] );
350
-
351
- echo '<option value="' . esc_attr( $role_id ) . '"'
352
- . selected( in_array( $role_id, $coupon_customer_roles ), true, false ) . '>'
353
- . esc_html( $role_name ) . '</option>';
354
- }
355
- ?>
356
- </select>
357
- <?php echo WJECF_WC()->wc_help_tip( __( 'Only these User Roles may use this coupon.', 'woocommerce-jos-autocoupon' ) ); ?>
358
- </p>
359
- <?php
360
-
361
- //=============================
362
- // Excluded user roles
363
- ?>
364
- <p class="form-field"><label for="wjecf_excluded_customer_roles"><?php _e( 'Disallowed User Roles', 'woocommerce-jos-autocoupon' ); ?></label>
365
- <select id="wjecf_customer_roles" name="wjecf_excluded_customer_roles[]" style="width: 50%;" class="wc-enhanced-select" multiple="multiple" data-placeholder="<?php _e( 'Any role', 'woocommerce-jos-autocoupon' ); ?>">
366
- <?php
367
- $coupon_excluded_customer_roles = WJECF()->get_coupon_excluded_customer_roles( $thepostid );
368
-
369
- foreach ( $available_customer_roles as $role_id => $role ) {
370
- $role_name = translate_user_role($role['name'] );
371
-
372
- echo '<option value="' . esc_attr( $role_id ) . '"'
373
- . selected( in_array( $role_id, $coupon_excluded_customer_roles ), true, false ) . '>'
374
- . esc_html( $role_name ) . '</option>';
375
- }
376
- ?>
377
- </select>
378
- <?php echo WJECF_WC()->wc_help_tip( __( 'These User Roles will be specifically excluded from using this coupon.', 'woocommerce-jos-autocoupon' ) ); ?>
379
- </p>
380
- <?php
381
- }
382
-
383
- public function admin_coupon_metabox_misc( $thepostid, $post ) {
384
- echo "<h3>" . esc_html( __( 'Miscellaneous', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
385
- //=============================
386
- //2.2.2 Allow if minimum spend not met
387
- woocommerce_wp_checkbox( array(
388
- 'id' => '_wjecf_allow_below_minimum_spend',
389
- 'label' => __( 'Allow when minimum spend not reached', 'woocommerce-jos-autocoupon' ),
390
- 'description' => '<b>' . __( 'EXPERIMENTAL: ', 'woocommerce-jos-autocoupon' ) . '</b>' . __( 'Check this box to allow the coupon to be in the cart even when minimum spend (see tab \'usage restriction\') is not reached. Value of the discount will be 0 until minimum spend is reached.', 'woocommerce-jos-autocoupon' ),
391
- ) );
392
- }
393
-
394
- public function process_shop_coupon_meta( $post_id, $post ) {
395
- $wrap_coupon = WJECF_Wrap( $post_id );
396
-
397
- $wjecf_min_matching_product_qty = isset( $_POST['_wjecf_min_matching_product_qty'] ) ? $_POST['_wjecf_min_matching_product_qty'] : '';
398
- $wrap_coupon->set_meta( '_wjecf_min_matching_product_qty', $wjecf_min_matching_product_qty );
399
-
400
- $wjecf_max_matching_product_qty = isset( $_POST['_wjecf_max_matching_product_qty'] ) ? $_POST['_wjecf_max_matching_product_qty'] : '';
401
- $wrap_coupon->set_meta( '_wjecf_max_matching_product_qty', $wjecf_max_matching_product_qty );
402
-
403
- //2.2.2
404
- $wjecf_min_matching_product_subtotal = isset( $_POST['_wjecf_min_matching_product_subtotal'] ) ? $_POST['_wjecf_min_matching_product_subtotal'] : '';
405
- $wrap_coupon->set_meta( '_wjecf_min_matching_product_subtotal', $wjecf_min_matching_product_subtotal );
406
-
407
- $wjecf_max_matching_product_subtotal = isset( $_POST['_wjecf_max_matching_product_subtotal'] ) ? $_POST['_wjecf_max_matching_product_subtotal'] : '';
408
- $wrap_coupon->set_meta( '_wjecf_max_matching_product_subtotal', $wjecf_max_matching_product_subtotal );
409
-
410
- $wjecf_products_and = $_POST['_wjecf_products_and'] == 'yes' ? 'yes' : 'no';
411
- $wrap_coupon->set_meta( '_wjecf_products_and', $wjecf_products_and );
412
-
413
- //2.2.3.1
414
- $wjecf_categories_and = $_POST['_wjecf_categories_and'] == 'yes' ? 'yes' : 'no';
415
- $wrap_coupon->set_meta( '_wjecf_categories_and', $wjecf_categories_and );
416
-
417
- //2.2.2
418
- $wjecf_allow_below_minimum_spend = isset( $_POST['_wjecf_allow_below_minimum_spend'] ) ? 'yes' : 'no';
419
- $wrap_coupon->set_meta( '_wjecf_allow_below_minimum_spend', $wjecf_allow_below_minimum_spend );
420
-
421
- $wjecf_shipping_methods = isset( $_POST['wjecf_shipping_methods'] ) ? $_POST['wjecf_shipping_methods'] : '';
422
- $wrap_coupon->set_meta( '_wjecf_shipping_methods', $wjecf_shipping_methods );
423
-
424
- $wjecf_payment_methods = isset( $_POST['wjecf_payment_methods'] ) ? $_POST['wjecf_payment_methods'] : '';
425
- $wrap_coupon->set_meta( '_wjecf_payment_methods', $wjecf_payment_methods );
426
-
427
- $wjecf_customer_ids = $this->comma_separated_int_array( $_POST['wjecf_customer_ids'] );
428
- $wrap_coupon->set_meta( '_wjecf_customer_ids', $wjecf_customer_ids );
429
-
430
- $wjecf_customer_roles = isset( $_POST['wjecf_customer_roles'] ) ? $_POST['wjecf_customer_roles'] : '';
431
- $wrap_coupon->set_meta( '_wjecf_customer_roles', $wjecf_customer_roles );
432
-
433
- $wjecf_excluded_customer_roles = isset( $_POST['wjecf_excluded_customer_roles'] ) ? $_POST['wjecf_excluded_customer_roles'] : '';
434
- $wrap_coupon->set_meta( '_wjecf_excluded_customer_roles', $wjecf_excluded_customer_roles );
435
-
436
- $wrap_coupon->save();
437
- }
438
-
439
- /**
440
- * 2.3.6
441
- * Add inline style (css) to the admin page. Must be called BEFORE admin_head !
442
- * @param string $css
443
- * @return void
444
- */
445
- public function add_inline_style( $css ) {
446
- $this->admin_css .= $css;
447
- }
448
-
449
-
450
- /**
451
- * 2.3.4
452
- * Parse an array or comma separated string; make sure they are valid ints and return as comma separated string
453
- * @param array|string $int_array
454
- * @return string comma separated int array
455
- */
456
- public function comma_separated_int_array( $int_array ) {
457
- //Source can be a comma separated string (select2) , or an int array (chosen)
458
- if ( ! is_array( $int_array) ) {
459
- $int_array = explode( ',', $int_array );
460
- }
461
- return implode( ',', array_filter( array_map( 'intval', $int_array ) ) );
462
- }
463
-
464
- /**
465
- * 2.3.6
466
- * Renders a <SELECT> that has a default value. Relies on woocommerce_wp_select
467
- *
468
- * field['default_value']: The default value (if omitted the first option will be default)
469
- * field['append_default_label']: If true or omitted the text '(DEFAULT)' will be appended to the default option caption
470
- *
471
- * @param array $field see wc-meta-box-functions.php:woocommerce_wp_select
472
- * @return void
473
- */
474
- public function render_select_with_default( $field ) {
475
- global $thepostid, $post;
476
- $thepostid = empty( $thepostid ) ? $post->ID : $thepostid;
477
-
478
- reset( $field['options'] ); //move to first for key()
479
- $default_value = isset( $field['default_value'] ) ? $field['default_value'] : key( $field['options'] );
480
- $append_default_label = isset( $field['append_default_label'] ) ? $field['append_default_label'] : true;
481
-
482
- if ( $append_default_label ) {
483
- $field['options'][$default_value] = sprintf( __( '%s (Default)', 'woocommerce-jos-autocoupon' ), $field['options'][$default_value] );
484
- }
485
-
486
- if ( ! isset( $field['value'] ) ) {
487
- $field['value'] = get_post_meta( $thepostid, $field['id'], true );
488
- }
489
- if ( empty( $field['value'] ) ) {
490
- $field['value'] = $default_value;
491
- }
492
-
493
- woocommerce_wp_select( $field );
494
- }
495
-
496
- public function render_admin_cat_selector( $dom_id, $field_name, $selected_ids, $placeholder = null ) {
497
- if ( $placeholder === null ) $placeholder = __( 'Search for a product…', 'woocommerce' );
498
-
499
- // Categories
500
- ?>
501
- <select id="<?php esc_attr_e( $dom_id ) ?>" name="<?php esc_attr_e( $field_name ) ?>[]" style="width: 50%;" class="wc-enhanced-select" multiple="multiple" data-placeholder="<?php esc_attr_e( $placeholder ); ?>">
502
- <?php
503
- $categories = get_terms( 'product_cat', 'orderby=name&hide_empty=0' );
504
-
505
- if ( $categories ) foreach ( $categories as $cat ) {
506
- echo '<option value="' . esc_attr( $cat->term_id ) . '"' . selected( in_array( $cat->term_id, $selected_ids ), true, false ) . '>' . esc_html( $cat->name ) . '</option>';
507
- }
508
- ?>
509
- </select>
510
- <?php
511
- }
512
-
513
- /**
514
- * Add donate-link to plugin page
515
- */
516
- function wjecf_plugin_meta( $links, $file ) {
517
- if ( strpos( $file, 'woocommerce-jos-autocoupon.php' ) !== false ) {
518
- $links = array_merge( $links, array( '<a href="' . WJECF_Admin::get_donate_url() . '" title="Support the development" target="_blank">Donate</a>' ) );
519
- }
520
- return $links;
521
- }
522
-
523
-
524
- public static function get_donate_url() {
525
- return "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=5T9XQBCS2QHRY&lc=NL&item_name=Jos%20Koenis&item_number=wordpress%2dplugin&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted";
526
- }
527
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.7.3
7
- Stable tag: 2.4.3
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -106,6 +106,29 @@ Sure! [This](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=5T9XQ
106
 
107
  == Changelog ==
108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  = 2.4.3 =
110
  * FIX: Customer selector WooCommerce 3.0.0 compatibility
111
 
4
  Tags: woocommerce, coupons, discount
5
  Requires at least: 4.0.0
6
  Tested up to: 4.7.3
7
+ Stable tag: 2.5.1
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
106
 
107
  == Changelog ==
108
 
109
+ = 2.5.1 =
110
+ * (PRO) FEATURE: Free product selection using checkboxes / numeric inputs
111
+ * (PRO) FIX: Free product selection fails if coupon code contains a space
112
+ * FIX: Draft settings not being saved
113
+ * FIX: PHP < 5.5 compatibility
114
+ * FIX: Abstract_WJECF_Plugin log function
115
+ * INTERNAL: Functions add_action_once / add_filter_once. To guarantee execution only once.
116
+ * INTERNAL: Updated the API example; also usable from CLI
117
+ * INTERNAL: Created Sanitizer for form data handling
118
+ * INTERNAL: Reorganised coupon meta handling ( Abstract_WJECF_Plugin::admin_coupon_meta_fields )
119
+
120
+ = 2.5.0 =
121
+ * (PRO) FEATURE: Auto update!
122
+ * (PRO) FEATURE: Checkbox 'Allow applying coupon when invalid'
123
+ * (PRO) FEATURE: Custom message when applying a coupon which does not yet validate
124
+ * FEATURE: Settings page
125
+ * FEATURE REMOVED: Experimental feature 'Allow when minimum spend not reached' (Use 'Allow applying coupon when invalid' instead)
126
+ * COSMETIC: Products tab is now 'Free Products' tab. Moved other items to the 'Usage restriction'-tab
127
+ * FIX: Issue with 'Allow discount on cart with excluded items'
128
+ * FIX: Notice if a free product without weight is added/removed to/from the cart
129
+ * FIX: Deprecation notice in WJECF_AutoCoupon::sort_auto_coupons
130
+ * INTERNAL: Introduced 'allow_overwrite_coupon_values'
131
+
132
  = 2.4.3 =
133
  * FIX: Customer selector WooCommerce 3.0.0 compatibility
134
 
woocommerce-jos-autocoupon.php CHANGED
@@ -3,57 +3,24 @@
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.4.3
7
  * Author: Soft79
8
  * License: GPL2
9
  */
10
 
 
 
11
  // Changelog: see readme.txt
12
 
13
  /*
14
  TODO:
15
- - stop using get_plugin_data
16
- - WORK IN PROGRESS: Admin page: Option to enable/disable functionality
17
- - Admin page: Enable/disable debugging
18
  - Apply filter for autocoupon individual_use_filter
19
  - (PRO) Eval
20
  */
21
 
22
 
23
-
24
- defined('ABSPATH') or die();
25
-
26
- if ( ! function_exists( 'wjecf_load_plugin_textdomain' ) ) {
27
-
28
- /**
29
- * Include the file once if it exists.
30
- * @param string $filename
31
- * @return void
32
- */
33
- function wjecf_optional_include( $filename ) {
34
- if ( ! file_exists( dirname( __FILE__ ) . '/' . $filename ) ) {
35
- return false;
36
- }
37
-
38
- include_once( $filename );
39
- return true;
40
- }
41
-
42
- require_once( 'includes/wjecf-wc.php' );
43
- require_once( 'includes/wjecf-controller.php' );
44
- require_once( 'includes/abstract-wjecf-plugin.php' );
45
- require_once( 'includes/admin/wjecf-admin.php' );
46
- require_once( 'includes/admin/wjecf-admin-auto-upgrade.php' );
47
- //Optional
48
- wjecf_optional_include( 'includes/wjecf-autocoupon.php' );
49
- wjecf_optional_include( 'includes/wjecf-wpml.php' );
50
- //PRO
51
- wjecf_optional_include( 'includes/wjecf-pro-controller.php' );
52
- wjecf_optional_include( 'includes/wjecf-pro-free-products.php' );
53
- wjecf_optional_include( 'includes/wjecf-pro-coupon-queueing.php' );
54
- wjecf_optional_include( 'includes/wjecf-pro-product-filter.php' );
55
- wjecf_optional_include( 'includes/wjecf-pro-limit-discount-quantities.php' );
56
- wjecf_optional_include( 'includes/wjecf-pro-api.php' );
57
 
58
  //Translations
59
  add_action( 'plugins_loaded', 'wjecf_load_plugin_textdomain' );
@@ -62,67 +29,61 @@ if ( ! function_exists( 'wjecf_load_plugin_textdomain' ) ) {
62
 
63
  load_textdomain( 'woocommerce-jos-autocoupon', WP_LANG_DIR . '/woocommerce-jos-autocoupon/woocommerce-jos-autocoupon-' . $locale . '.mo' );
64
  load_plugin_textdomain('woocommerce-jos-autocoupon', false, basename(dirname(__FILE__)) . '/languages/' );
 
65
 
66
- // //WP-cli for debugging
67
- // if ( defined( 'WP_CLI' ) && WP_CLI ) {
68
- // if ( wjecf_optional_include('includes/WJECF_Debug_CLI.php') ) {
69
- // WP_CLI::add_command( 'wjecf', 'WJECF_Debug_CLI' );
70
- // }
71
- // }
72
-
73
- // Only Initiate the plugin if WooCommerce is active
74
- if ( WJECF_WC::instance()->get_woocommerce_version() == false ) {
75
- add_action( 'admin_notices', 'wjecf_admin_notice' );
76
- function wjecf_admin_notice() {
77
- $msg = __( 'WooCommerce Extended Coupon Features is disabled because WooCommerce could not be detected.', 'woocommerce-jos-autocoupon' );
78
- echo '<div class="error"><p>' . $msg . '</p></div>';
79
- }
80
- } else {
81
-
82
- function WJECF_WC() {
83
- return WJECF_WC::instance();
84
- }
85
-
86
- function WJECF_Wrap( $object ) {
87
- return WJECF_WC::instance()->wrap( $object );
88
- }
89
-
90
- /**
91
- * Get the instance of WJECF
92
- * @return WJECF_Controller|WJECF_Pro_Controller The instance of WJECF
93
- */
94
- function WJECF() {
95
- if ( class_exists( 'WJECF_Pro_Controller' ) ) {
96
- return WJECF_Pro_Controller::instance();
97
- } else {
98
- return WJECF_Controller::instance();
99
- }
100
- }
101
-
102
- /**
103
- * Get the instance of WJECF_Admin
104
- * @return WJECF_Admin The instance of WJECF_Admin
105
- */
106
- function WJECF_ADMIN() {
107
- return WJECF()->get_plugin('WJECF_Admin');
108
- }
109
-
110
- $wjecf_extended_coupon_features = WJECF();
111
-
112
- WJECF()->add_plugin('WJECF_Admin');
113
- WJECF()->add_plugin('WJECF_Admin_Auto_Upgrade');
114
- WJECF()->add_plugin('WJECF_AutoCoupon');
115
- WJECF()->add_plugin('WJECF_WPML');
116
- if ( WJECF()->is_pro() ) {
117
- WJECF()->add_plugin('WJECF_Pro_Free_Products');
118
- WJECF()->add_plugin('WJECF_Pro_Coupon_Queueing');
119
- WJECF()->add_plugin('WJECF_Pro_Product_Filter');
120
- WJECF()->add_plugin('WJECF_Pro_Limit_Discount_Quantities');
121
- }
122
- WJECF()->start();
123
  }
124
  }
125
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  }
127
 
128
 
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.5.1
7
  * Author: Soft79
8
  * License: GPL2
9
  */
10
 
11
+ if ( ! defined('WJECF_VERSION') ) define ('WJECF_VERSION', '2.5.1');
12
+
13
  // Changelog: see readme.txt
14
 
15
  /*
16
  TODO:
 
 
 
17
  - Apply filter for autocoupon individual_use_filter
18
  - (PRO) Eval
19
  */
20
 
21
 
22
+ if ( ! defined('ABSPATH') ) die();
23
+ if ( ! function_exists( 'wjecf_load_plugin_textdomain' ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
  //Translations
26
  add_action( 'plugins_loaded', 'wjecf_load_plugin_textdomain' );
29
 
30
  load_textdomain( 'woocommerce-jos-autocoupon', WP_LANG_DIR . '/woocommerce-jos-autocoupon/woocommerce-jos-autocoupon-' . $locale . '.mo' );
31
  load_plugin_textdomain('woocommerce-jos-autocoupon', false, basename(dirname(__FILE__)) . '/languages/' );
32
+ }
33
 
34
+ /**
35
+ * Get the instance of WJECF
36
+ * @return WJECF_Controller|WJECF_Pro_Controller The instance of WJECF
37
+ */
38
+ function WJECF() {
39
+ if ( class_exists( 'WJECF_Pro_Controller' ) ) {
40
+ return WJECF_Pro_Controller::instance();
41
+ } else {
42
+ return WJECF_Controller::instance();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  }
44
  }
45
 
46
+ /**
47
+ * Get the instance of WJECF_Admin
48
+ * @return WJECF_Admin The instance of WJECF_Admin
49
+ */
50
+ function WJECF_ADMIN() {
51
+ return WJECF()->get_plugin('WJECF_Admin');
52
+ }
53
+
54
+ /**
55
+ * Get the instance of WJECF_WC
56
+ * @return WJECF_WC The instance of WJECF_WC
57
+ */
58
+ function WJECF_WC() {
59
+ return WJECF_WC::instance();
60
+ }
61
+
62
+ /**
63
+ * Get the instance if the WooCommerce Extended Coupon Features API
64
+ * @return WJECF_Pro_API The API object
65
+ */
66
+ function WJECF_API() {
67
+ return WJECF_Pro_API::instance();
68
+ }
69
+
70
+ /**
71
+ * Wraps a product or coupon in a decorator
72
+ * @param mixed $object The WC_Coupon or WC_Product instance, or the post id
73
+ * @return WJECF_Wrap
74
+ */
75
+ function WJECF_Wrap( $object ) {
76
+ return WJECF_WC::instance()->wrap( $object );
77
+ }
78
+
79
+ require_once( 'includes/WJECF_Bootstrap.php' );
80
+
81
+ WJECF_Bootstrap::execute();
82
+
83
+ //DEPRECATED. We keep $wjecf_extended_coupon_features for backwards compatibility; use WJECF_API()
84
+ $wjecf_extended_coupon_features = WJECF();
85
+
86
+
87
  }
88
 
89