Version Description
Release Date - 2018-06-04 * FIX: WJECF_Controller: Don't use wp_get_current_user() for admin-orders * FIX: WJECF_Controller: Don't use WC()->cart->subtotal for admin-orders * FIX: Possible division by zero when calculating multiplier value * FEATURE: Filter 'wjecf_coupon_multiplier_value' to allow overriding the coupon's multiplier value
Download this release
Release Info
Developer | josk79 |
Plugin | WooCommerce Extended Coupon Features |
Version | 2.6.3 |
Comparing to | |
See all releases |
Code changes from version 2.6.2 to 2.6.3
- includes/Abstract_WJECF_Plugin.php +126 -126
- includes/WJECF_AutoCoupon.php +728 -728
- includes/WJECF_Bootstrap.php +129 -129
- includes/WJECF_Controller.php +1001 -970
- includes/WJECF_Debug.php +199 -199
- includes/WJECF_Debug_CLI.php +266 -266
- includes/WJECF_Options.php +98 -98
- includes/WJECF_Sanitizer.php +71 -71
- includes/WJECF_WC.php +417 -417
- includes/WJECF_WC_Discounts.php +70 -70
- includes/WJECF_WPML.php +80 -80
- includes/WJECF_Wrap.php +496 -496
- includes/admin/WJECF_Admin.php +456 -456
- includes/admin/WJECF_Admin_Data_Update.php +82 -82
- includes/admin/WJECF_Admin_Html.php +332 -332
- includes/admin/WJECF_Admin_Settings.php +268 -268
- readme.txt +10 -2
- woocommerce-jos-autocoupon.php +3 -3
includes/Abstract_WJECF_Plugin.php
CHANGED
@@ -1,126 +1,126 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
abstract class Abstract_WJECF_Plugin {
|
4 |
-
|
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 sanitation to apply.
|
13 |
-
* Instead of a sanitation a callback can be supplied; 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
|
29 |
-
*/
|
30 |
-
public function assert_dependencies() {
|
31 |
-
foreach( $this->get_plugin_dependencies() as $dependency ) {
|
32 |
-
if ( ! isset( $this->plugins[ $dependency ] ) ) {
|
33 |
-
throw new Exception( sprintf( 'Missing dependency %s', $dependency) );
|
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 |
-
|
42 |
-
/**
|
43 |
-
* Assert minimum WJECF version number
|
44 |
-
* @param string $required_version
|
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 |
-
|
53 |
-
//
|
54 |
-
|
55 |
-
/**
|
56 |
-
* Log a message (for debugging)
|
57 |
-
*
|
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();
|
71 |
-
|
72 |
-
/**
|
73 |
-
* Information about the WJECF plugin
|
74 |
-
* @param string|null $key The data to look up. Will return an array with all data when omitted
|
75 |
-
* @return mixed
|
76 |
-
*/
|
77 |
-
protected function get_plugin_data( $key = null ) {
|
78 |
-
$default_data = array(
|
79 |
-
'description' => '',
|
80 |
-
'can_be_disabled' => false,
|
81 |
-
'hidden' => false, // Does not display on settings page
|
82 |
-
'dependencies' => array(),
|
83 |
-
'minimal_wjecf_version' => ''
|
84 |
-
);
|
85 |
-
$plugin_data = array_merge( $default_data, $this->plugin_data );
|
86 |
-
if ( $key === null ) {
|
87 |
-
return $plugin_data;
|
88 |
-
}
|
89 |
-
return $plugin_data[$key];
|
90 |
-
}
|
91 |
-
|
92 |
-
/**
|
93 |
-
* Set information about the WJECF plugin
|
94 |
-
* @param array $plugin_data The data for this plugin
|
95 |
-
* @return void
|
96 |
-
*/
|
97 |
-
protected function set_plugin_data( $plugin_data ) {
|
98 |
-
$this->plugin_data = $plugin_data;
|
99 |
-
}
|
100 |
-
|
101 |
-
/**
|
102 |
-
* Get the description if this WJECF plugin.
|
103 |
-
* @return string
|
104 |
-
*/
|
105 |
-
public function get_plugin_description() {
|
106 |
-
return $this->get_plugin_data( 'description' );
|
107 |
-
}
|
108 |
-
|
109 |
-
/**
|
110 |
-
* Get the class name of this WJECF plugin.
|
111 |
-
* @return string
|
112 |
-
*/
|
113 |
-
public function get_plugin_class_name() {
|
114 |
-
return get_class( $this );
|
115 |
-
}
|
116 |
-
|
117 |
-
public function get_plugin_dependencies() {
|
118 |
-
return $this->get_plugin_data( 'dependencies' );
|
119 |
-
}
|
120 |
-
|
121 |
-
public function plugin_is_enabled() {
|
122 |
-
if ( ! $this->get_plugin_data( 'can_be_disabled' ) ) return true;
|
123 |
-
return ! in_array( $this->get_plugin_class_name(), WJECF()->get_option('disabled_plugins') );
|
124 |
-
}
|
125 |
-
|
126 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
abstract class Abstract_WJECF_Plugin {
|
4 |
+
|
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 sanitation to apply.
|
13 |
+
* Instead of a sanitation a callback can be supplied; 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
|
29 |
+
*/
|
30 |
+
public function assert_dependencies() {
|
31 |
+
foreach( $this->get_plugin_dependencies() as $dependency ) {
|
32 |
+
if ( ! isset( $this->plugins[ $dependency ] ) ) {
|
33 |
+
throw new Exception( sprintf( 'Missing dependency %s', $dependency) );
|
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 |
+
|
42 |
+
/**
|
43 |
+
* Assert minimum WJECF version number
|
44 |
+
* @param string $required_version
|
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 |
+
|
53 |
+
//
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Log a message (for debugging)
|
57 |
+
*
|
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();
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Information about the WJECF plugin
|
74 |
+
* @param string|null $key The data to look up. Will return an array with all data when omitted
|
75 |
+
* @return mixed
|
76 |
+
*/
|
77 |
+
protected function get_plugin_data( $key = null ) {
|
78 |
+
$default_data = array(
|
79 |
+
'description' => '',
|
80 |
+
'can_be_disabled' => false,
|
81 |
+
'hidden' => false, // Does not display on settings page
|
82 |
+
'dependencies' => array(),
|
83 |
+
'minimal_wjecf_version' => ''
|
84 |
+
);
|
85 |
+
$plugin_data = array_merge( $default_data, $this->plugin_data );
|
86 |
+
if ( $key === null ) {
|
87 |
+
return $plugin_data;
|
88 |
+
}
|
89 |
+
return $plugin_data[$key];
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Set information about the WJECF plugin
|
94 |
+
* @param array $plugin_data The data for this plugin
|
95 |
+
* @return void
|
96 |
+
*/
|
97 |
+
protected function set_plugin_data( $plugin_data ) {
|
98 |
+
$this->plugin_data = $plugin_data;
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Get the description if this WJECF plugin.
|
103 |
+
* @return string
|
104 |
+
*/
|
105 |
+
public function get_plugin_description() {
|
106 |
+
return $this->get_plugin_data( 'description' );
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Get the class name of this WJECF plugin.
|
111 |
+
* @return string
|
112 |
+
*/
|
113 |
+
public function get_plugin_class_name() {
|
114 |
+
return get_class( $this );
|
115 |
+
}
|
116 |
+
|
117 |
+
public function get_plugin_dependencies() {
|
118 |
+
return $this->get_plugin_data( 'dependencies' );
|
119 |
+
}
|
120 |
+
|
121 |
+
public function plugin_is_enabled() {
|
122 |
+
if ( ! $this->get_plugin_data( 'can_be_disabled' ) ) return true;
|
123 |
+
return ! in_array( $this->get_plugin_class_name(), WJECF()->get_option('disabled_plugins') );
|
124 |
+
}
|
125 |
+
|
126 |
+
}
|
includes/WJECF_AutoCoupon.php
CHANGED
@@ -1,728 +1,728 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
defined('ABSPATH') or die();
|
4 |
-
|
5 |
-
class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
|
6 |
-
|
7 |
-
protected $options = null; // WJECF_Options object
|
8 |
-
protected $_autocoupons = null;
|
9 |
-
protected $_executed_coupon_by_url = false;
|
10 |
-
|
11 |
-
public function __construct() {
|
12 |
-
$this->set_plugin_data( array(
|
13 |
-
'description' => __( 'Allow coupons to be automatically applied to the cart when restrictions are met or by url.', 'woocommerce-jos-autocoupon' ),
|
14 |
-
'dependencies' => array(),
|
15 |
-
'can_be_disabled' => true
|
16 |
-
) );
|
17 |
-
}
|
18 |
-
|
19 |
-
public function init_hook() {
|
20 |
-
//Since 2.6.2 check for frontend request. Prevents 'Call to undefined function wc_add_notice()'.
|
21 |
-
if ( ! class_exists('WC_Coupon') || ! WJECF()->is_request( 'frontend' ) ) {
|
22 |
-
return;
|
23 |
-
}
|
24 |
-
|
25 |
-
//NOTE: WPML Causes an extra calculate_totals() !!!
|
26 |
-
|
27 |
-
//Frontend hooks - logic
|
28 |
-
if ( WJECF_WC()->check_woocommerce_version('2.3.0')) {
|
29 |
-
WJECF()->safe_add_action( 'woocommerce_after_calculate_totals', array( $this, 'update_matched_autocoupons' ) );
|
30 |
-
} else {
|
31 |
-
//WC Versions prior to 2.3.0 don't have after_calculate_totals hook, this is a fallback
|
32 |
-
WJECF()->safe_add_action( 'woocommerce_cart_updated', array( $this, 'update_matched_autocoupons' ) );
|
33 |
-
}
|
34 |
-
|
35 |
-
add_action( 'woocommerce_check_cart_items', array( $this, 'remove_unmatched_autocoupons' ) , 0, 0 ); //Remove coupon before WC does it and shows a message
|
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 ( !
|
45 |
-
//Get cart should not be called before the wp_loaded action nor the add_to_cart_action (class-wc-form-handler)
|
46 |
-
add_action( 'wp_loaded', array( &$this, 'coupon_by_url' ), 90 ); //Coupon through url
|
47 |
-
}
|
48 |
-
|
49 |
-
/**
|
50 |
-
* Mark removed autocoupons to prevent them from being automatically applied again
|
51 |
-
* (PRO Only)
|
52 |
-
* @since 2.5.4
|
53 |
-
*/
|
54 |
-
add_action( 'woocommerce_applied_coupon', array( $this, 'action_applied_coupon' ), 10, 1 );
|
55 |
-
add_action( 'woocommerce_removed_coupon', array( $this, 'action_removed_coupon' ), 10, 1 );
|
56 |
-
add_action( 'woocommerce_cart_emptied', array( $this, 'action_cart_emptied' ), 10, 0 );
|
57 |
-
}
|
58 |
-
|
59 |
-
/* ADMIN HOOKS */
|
60 |
-
public function init_admin_hook() {
|
61 |
-
add_action( 'wjecf_woocommerce_coupon_options_extended_features', array( $this, 'admin_coupon_options_extended_features' ), 20, 2 );
|
62 |
-
|
63 |
-
//Inject columns
|
64 |
-
if ( WJECF()->is_pro() ) {
|
65 |
-
WJECF()->inject_coupon_column(
|
66 |
-
'_wjecf_auto_coupon',
|
67 |
-
__( 'Auto coupon', 'woocommerce-jos-autocoupon' ),
|
68 |
-
array( $this, 'admin_render_shop_coupon_columns' ), 'coupon_code'
|
69 |
-
);
|
70 |
-
WJECF()->inject_coupon_column(
|
71 |
-
'_wjecf_individual_use',
|
72 |
-
__( 'Individual use', 'woocommerce-jos-autocoupon' ),
|
73 |
-
array( $this, 'admin_render_shop_coupon_columns' ), 'coupon_code'
|
74 |
-
);
|
75 |
-
}
|
76 |
-
|
77 |
-
add_filter( 'views_edit-shop_coupon', array( $this, 'admin_views_edit_coupon' ) );
|
78 |
-
add_filter( 'request', array( $this, 'admin_request_query' ) );
|
79 |
-
|
80 |
-
add_action( 'wjecf_admin_before_settings', array( $this, 'wjecf_admin_before_settings' ), 20 );
|
81 |
-
add_filter( 'wjecf_admin_validate_settings', array( $this, 'wjecf_admin_validate_settings' ), 10, 2 );
|
82 |
-
}
|
83 |
-
|
84 |
-
public function wjecf_admin_before_settings() {
|
85 |
-
$page = WJECF_Admin_Settings::SETTINGS_PAGE;
|
86 |
-
|
87 |
-
if ( WJECF()->is_pro() ) {
|
88 |
-
add_settings_section(
|
89 |
-
WJECF_Admin_Settings::DOM_PREFIX . 'section_autocoupon',
|
90 |
-
__( 'Auto coupons', 'woocommerce-jos-autocoupon' ),
|
91 |
-
array( $this, 'render_section' ),
|
92 |
-
$page
|
93 |
-
);
|
94 |
-
|
95 |
-
add_settings_field(
|
96 |
-
WJECF_Admin_Settings::DOM_PREFIX . 'autocoupon_allow_remove',
|
97 |
-
__( 'Allow remove \'Auto Coupons\'', 'woocommerce-jos-autocoupon' ),
|
98 |
-
array( $this, 'render_setting_allow_remove_auto_coupon' ),
|
99 |
-
$page,
|
100 |
-
WJECF_Admin_Settings::DOM_PREFIX . 'section_autocoupon'
|
101 |
-
);
|
102 |
-
}
|
103 |
-
}
|
104 |
-
|
105 |
-
public function render_section( $section ) {
|
106 |
-
switch ( $section['id'] ) {
|
107 |
-
case WJECF_Admin_Settings::DOM_PREFIX . 'section_autocoupon':
|
108 |
-
//$body = ".....";
|
109 |
-
//printf( '<p>%s</p>', $body );
|
110 |
-
break;
|
111 |
-
}
|
112 |
-
}
|
113 |
-
|
114 |
-
public function render_setting_allow_remove_auto_coupon() {
|
115 |
-
$option_name = 'autocoupon_allow_remove';
|
116 |
-
$args = array(
|
117 |
-
'type' => 'checkbox',
|
118 |
-
'id' => WJECF_Admin_Settings::DOM_PREFIX . $option_name,
|
119 |
-
'name' => sprintf( "%s[%s]", WJECF_Admin_Settings::OPTION_NAME, $option_name ),
|
120 |
-
'value' => WJECF()->get_option( $option_name, false ) ? 'yes' : 'no'
|
121 |
-
);
|
122 |
-
|
123 |
-
WJECF_Admin_Html::render_input( $args );
|
124 |
-
WJECF_Admin_Html::render_tag(
|
125 |
-
'label',
|
126 |
-
array( "for" => esc_attr( $args['id'] ) ),
|
127 |
-
__( 'Enabled', 'woocommerce' )
|
128 |
-
);
|
129 |
-
WJECF_Admin_Html::render_tag(
|
130 |
-
'p',
|
131 |
-
array( 'class' => 'description'),
|
132 |
-
__( 'Check this box to allow the customer to remove \'Auto Coupons\' from the cart.', 'woocommerce-jos-autocoupon' )
|
133 |
-
);
|
134 |
-
|
135 |
-
}
|
136 |
-
|
137 |
-
public function wjecf_admin_validate_settings( $options, $input ) {
|
138 |
-
$options['autocoupon_allow_remove'] = isset( $input['autocoupon_allow_remove'] ) && $input['autocoupon_allow_remove'] === 'yes';
|
139 |
-
return $options;
|
140 |
-
}
|
141 |
-
|
142 |
-
/**
|
143 |
-
* Output a coupon custom column value
|
144 |
-
*
|
145 |
-
* @param string $column
|
146 |
-
* @param WP_Post The coupon post object
|
147 |
-
*/
|
148 |
-
public function admin_render_shop_coupon_columns( $column, $post ) {
|
149 |
-
$wrap_coupon = WJECF_Wrap( intval( $post->ID ) );
|
150 |
-
|
151 |
-
switch ( $column ) {
|
152 |
-
case '_wjecf_auto_coupon' :
|
153 |
-
$is_auto_coupon = $wrap_coupon->get_meta( '_wjecf_is_auto_coupon', true ) == 'yes';
|
154 |
-
echo $is_auto_coupon ? __( 'Yes', 'woocommerce' ) : __( 'No', 'woocommerce' );
|
155 |
-
if ( $is_auto_coupon ) {
|
156 |
-
$prio = $wrap_coupon->get_meta( '_wjecf_coupon_priority', true );
|
157 |
-
if ( $prio ) echo " (" . intval( $prio ) . ")";
|
158 |
-
}
|
159 |
-
break;
|
160 |
-
case '_wjecf_individual_use' :
|
161 |
-
$individual = $wrap_coupon->get_individual_use();
|
162 |
-
echo $individual ? __( 'Yes', 'woocommerce' ) : __( 'No', 'woocommerce' );
|
163 |
-
break;
|
164 |
-
}
|
165 |
-
}
|
166 |
-
|
167 |
-
public function admin_views_edit_coupon( $views ) {
|
168 |
-
global $post_type, $wp_query;
|
169 |
-
|
170 |
-
$class = ( isset( $wp_query->query['meta_key'] ) && $wp_query->query['meta_key'] == '_wjecf_is_auto_coupon' ) ? 'current' : '';
|
171 |
-
$query_string = remove_query_arg(array( 'wjecf_is_auto_coupon' ));
|
172 |
-
$query_string = add_query_arg( 'wjecf_is_auto_coupon', '1', $query_string );
|
173 |
-
$views['wjecf_is_auto_coupon'] = '<a href="' . esc_url( $query_string ) . '" class="' . esc_attr( $class ) . '">' . __( 'Auto coupons', 'woocommerce-jos-autocoupon' ) . '</a>';
|
174 |
-
|
175 |
-
return $views;
|
176 |
-
}
|
177 |
-
|
178 |
-
/**
|
179 |
-
* Filters and sorting handler
|
180 |
-
*
|
181 |
-
* @param array $vars
|
182 |
-
* @return array
|
183 |
-
*/
|
184 |
-
public function admin_request_query( $vars ) {
|
185 |
-
global $typenow, $wp_query, $wp_post_statuses;
|
186 |
-
|
187 |
-
if ( 'shop_coupon' === $typenow ) {
|
188 |
-
if ( isset( $_GET['wjecf_is_auto_coupon'] ) ) {
|
189 |
-
$vars['meta_key'] = '_wjecf_is_auto_coupon';
|
190 |
-
$vars['meta_value'] = $_GET['wjecf_is_auto_coupon'] == '1' ? 'yes' : 'no';
|
191 |
-
}
|
192 |
-
}
|
193 |
-
|
194 |
-
return $vars;
|
195 |
-
}
|
196 |
-
|
197 |
-
public function admin_coupon_options_extended_features( $thepostid, $post ) {
|
198 |
-
|
199 |
-
//=============================
|
200 |
-
//Title
|
201 |
-
echo "<h3>" . esc_html( __( 'Auto coupon', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
|
202 |
-
|
203 |
-
|
204 |
-
//=============================
|
205 |
-
// Auto coupon checkbox
|
206 |
-
woocommerce_wp_checkbox( array(
|
207 |
-
'id' => '_wjecf_is_auto_coupon',
|
208 |
-
'label' => __( 'Auto coupon', 'woocommerce-jos-autocoupon' ),
|
209 |
-
'description' => __( "Automatically add the coupon to the cart if the restrictions are met. Please enter a description when you check this box, the description will be shown in the customer's cart if the coupon is applied.", 'woocommerce-jos-autocoupon' )
|
210 |
-
) );
|
211 |
-
|
212 |
-
echo '<div class="_wjecf_show_if_autocoupon">';
|
213 |
-
if ( WJECF()->is_pro() ) {
|
214 |
-
// Maximum quantity of matching products (product/category)
|
215 |
-
woocommerce_wp_text_input( array(
|
216 |
-
'id' => '_wjecf_coupon_priority',
|
217 |
-
'label' => __( 'Priority', 'woocommerce-jos-autocoupon' ),
|
218 |
-
'placeholder' => __( 'No priority', 'woocommerce' ),
|
219 |
-
'description' => __( 'When \'individual use\' is checked, auto coupons with a higher value will have priority over other auto coupons.', 'woocommerce-jos-autocoupon' ),
|
220 |
-
'data_type' => 'decimal',
|
221 |
-
'desc_tip' => true
|
222 |
-
) );
|
223 |
-
}
|
224 |
-
|
225 |
-
//=============================
|
226 |
-
// Apply without notice
|
227 |
-
woocommerce_wp_checkbox( array(
|
228 |
-
'id' => '_wjecf_apply_silently',
|
229 |
-
'label' => __( 'Apply silently', 'woocommerce-jos-autocoupon' ),
|
230 |
-
'description' => __( "Don't display a message when this coupon is automatically applied.", 'woocommerce-jos-autocoupon' ),
|
231 |
-
) );
|
232 |
-
echo '</div>';
|
233 |
-
|
234 |
-
?>
|
235 |
-
<script type="text/javascript">
|
236 |
-
//Hide/show when AUTO-COUPON value changes
|
237 |
-
function update_wjecf_apply_silently_field( animation ) {
|
238 |
-
if ( animation === undefined ) animation = 'slow';
|
239 |
-
|
240 |
-
if (jQuery("#_wjecf_is_auto_coupon").prop('checked')) {
|
241 |
-
jQuery("._wjecf_show_if_autocoupon").show( animation );
|
242 |
-
jQuery("._wjecf_hide_if_autocoupon").hide( animation );
|
243 |
-
} else {
|
244 |
-
jQuery("._wjecf_show_if_autocoupon").hide( animation );
|
245 |
-
jQuery("._wjecf_hide_if_autocoupon").show( animation );
|
246 |
-
}
|
247 |
-
}
|
248 |
-
|
249 |
-
jQuery( function( $ ) {
|
250 |
-
update_wjecf_apply_silently_field( 0 );
|
251 |
-
$("#_wjecf_is_auto_coupon").click( update_wjecf_apply_silently_field );
|
252 |
-
} );
|
253 |
-
</script>
|
254 |
-
<?php
|
255 |
-
|
256 |
-
}
|
257 |
-
|
258 |
-
public function admin_coupon_meta_fields( $coupon ) {
|
259 |
-
$fields = array(
|
260 |
-
'_wjecf_is_auto_coupon' => 'yesno',
|
261 |
-
'_wjecf_apply_silently' => 'yesno',
|
262 |
-
);
|
263 |
-
|
264 |
-
if ( WJECF()->is_pro() ) {
|
265 |
-
$fields['_wjecf_coupon_priority'] = 'int';
|
266 |
-
}
|
267 |
-
return $fields;
|
268 |
-
}
|
269 |
-
|
270 |
-
/* FRONTEND HOOKS */
|
271 |
-
|
272 |
-
/**
|
273 |
-
** Inhibit redirect to cart when apply_coupon supplied
|
274 |
-
*/
|
275 |
-
public function option_woocommerce_cart_redirect_after_add
|
276 |
-
if ( ! $this->_executed_coupon_by_url && isset( $_GET['apply_coupon'] ) ) {
|
277 |
-
$value = 'no';
|
278 |
-
}
|
279 |
-
return $value;
|
280 |
-
}
|
281 |
-
|
282 |
-
/**
|
283 |
-
* Add coupon through url
|
284 |
-
*/
|
285 |
-
public function coupon_by_url() {
|
286 |
-
$must_redirect = false;
|
287 |
-
|
288 |
-
//Apply coupon by url
|
289 |
-
if ( isset( $_GET['apply_coupon'] ) ) {
|
290 |
-
$must_redirect = true;
|
291 |
-
$this->_executed_coupon_by_url = true;
|
292 |
-
$split = explode( ",", wc_clean( $_GET['apply_coupon'] ) );
|
293 |
-
//2.2.2 Make sure a session cookie is set
|
294 |
-
if( ! WC()->session->has_session() )
|
295 |
-
{
|
296 |
-
WC()->session->set_customer_session_cookie( true );
|
297 |
-
}
|
298 |
-
|
299 |
-
$cart = WC()->cart;
|
300 |
-
foreach ( $split as $coupon_code ) {
|
301 |
-
$coupon = WJECF_WC()->get_coupon( $coupon_code );
|
302 |
-
if ( WJECF_WC()->check_woocommerce_version('2.3.0') && ! WJECF_Wrap( $coupon )->exists() ) {
|
303 |
-
wc_add_notice( $coupon->get_coupon_error( WC_Coupon::E_WC_COUPON_NOT_EXIST ), 'error' );
|
304 |
-
} else {
|
305 |
-
$valid = $coupon->is_valid();
|
306 |
-
if ( $valid ) {
|
307 |
-
$cart->add_discount( $coupon_code );
|
308 |
-
}
|
309 |
-
}
|
310 |
-
}
|
311 |
-
}
|
312 |
-
|
313 |
-
//Redirect to page without autocoupon query args
|
314 |
-
if ( $must_redirect ) {
|
315 |
-
$requested_url = is_ssl() ? 'https://' : 'http://';
|
316 |
-
$requested_url .= $_SERVER['HTTP_HOST'];
|
317 |
-
$requested_url .= $_SERVER['REQUEST_URI'];
|
318 |
-
|
319 |
-
wp_safe_redirect( remove_query_arg( array( 'apply_coupon', 'add-to-cart' ), ( $requested_url ) ) );
|
320 |
-
exit;
|
321 |
-
}
|
322 |
-
}
|
323 |
-
|
324 |
-
/**
|
325 |
-
* Overwrite the html created by wc_cart_totals_coupon_label() so a descriptive text will be shown for the discount.
|
326 |
-
* @param string $originaltext The default text created by wc_cart_totals_coupon_label()
|
327 |
-
* @param WC_Coupon $coupon The coupon data
|
328 |
-
* @return string The overwritten text
|
329 |
-
*/
|
330 |
-
function coupon_label( $originaltext, $coupon ) {
|
331 |
-
|
332 |
-
if ( $this->is_auto_coupon($coupon) ) {
|
333 |
-
return WJECF_Wrap( $coupon )->get_description();
|
334 |
-
} else {
|
335 |
-
return $originaltext;
|
336 |
-
}
|
337 |
-
}
|
338 |
-
|
339 |
-
/**
|
340 |
-
* Overwrite the html created by wc_cart_totals_coupon_html(). This function is required to remove the "Remove" link.
|
341 |
-
* @param string $originaltext The html created by wc_cart_totals_coupon_html()
|
342 |
-
* @param WC_Coupon $coupon The coupon data
|
343 |
-
* @return string The overwritten html
|
344 |
-
*/
|
345 |
-
function coupon_html( $originaltext, $coupon ) {
|
346 |
-
if ( $this->is_auto_coupon( $coupon ) && ! $this->get_option_autocoupon_allow_remove() ) {
|
347 |
-
$value = array();
|
348 |
-
|
349 |
-
if ( $amount = WC()->cart->get_coupon_discount_amount( WJECF_Wrap( $coupon )->get_code(), WC()->cart->display_cart_ex_tax ) ) {
|
350 |
-
$discount_html = '-' . wc_price( $amount );
|
351 |
-
} else {
|
352 |
-
$discount_html = '';
|
353 |
-
}
|
354 |
-
|
355 |
-
$value[] = apply_filters( 'woocommerce_coupon_discount_amount_html', $discount_html, $coupon );
|
356 |
-
|
357 |
-
if ( WJECF_Wrap( $coupon )->get_free_shipping() ) {
|
358 |
-
$value[] = __( 'Free shipping coupon', 'woocommerce' );
|
359 |
-
}
|
360 |
-
|
361 |
-
return implode( ', ', array_filter($value) ); //Remove empty array elements
|
362 |
-
} else {
|
363 |
-
return $originaltext;
|
364 |
-
}
|
365 |
-
}
|
366 |
-
|
367 |
-
function remove_unmatched_autocoupons( $valid_coupon_codes = null ) {
|
368 |
-
if ( $valid_coupon_codes === null ) {
|
369 |
-
//Get the coupons that should be in the cart
|
370 |
-
$valid_coupons = $this->get_valid_auto_coupons();
|
371 |
-
$valid_coupons = $this->individual_use_filter( $valid_coupons );
|
372 |
-
$valid_coupon_codes = array();
|
373 |
-
foreach ( $valid_coupons as $coupon ) {
|
374 |
-
$valid_coupon_codes[] = WJECF_Wrap( $coupon )->get_code();
|
375 |
-
}
|
376 |
-
}
|
377 |
-
|
378 |
-
//Remove invalids
|
379 |
-
$calc_needed = false;
|
380 |
-
foreach ( $this->get_all_auto_coupons() as $coupon ) {
|
381 |
-
$coupon_code = WJECF_Wrap( $coupon )->get_code();
|
382 |
-
if ( WC()->cart->has_discount( $coupon_code ) && ! in_array( $coupon_code, $valid_coupon_codes ) ) {
|
383 |
-
$this->log( 'debug', sprintf( "Removing %s", $coupon_code ) );
|
384 |
-
$this->ignore_removal[$coupon_code] = $coupon_code;
|
385 |
-
WC()->cart->remove_coupon( $coupon_code );
|
386 |
-
unset( $this->ignore_removal[$coupon_code] );
|
387 |
-
$calc_needed = true;
|
388 |
-
}
|
389 |
-
}
|
390 |
-
return $calc_needed;
|
391 |
-
}
|
392 |
-
|
393 |
-
|
394 |
-
// ============ BEGIN wjecf_autocoupon_removed_coupons =======================
|
395 |
-
|
396 |
-
// When a custom clicks the [remove]-button of an auto coupon, the coupon will not be applied automatically anymore...
|
397 |
-
// After that the coupon can only be applied manually by entering the coupon code.
|
398 |
-
|
399 |
-
//Will ignore the remove_coupon action for the given keys
|
400 |
-
private $ignore_removal = array( /* coupon_code => coupon_code */ );
|
401 |
-
|
402 |
-
/**
|
403 |
-
* Remove the coupon from session 'wjecf_autocoupon_removed_coupons'
|
404 |
-
* @since 2.5.4
|
405 |
-
*/
|
406 |
-
function action_applied_coupon( $coupon_code ) {
|
407 |
-
if ( ! $this->is_auto_coupon( $coupon_code ) || ! $this->get_option_autocoupon_allow_remove() ) {
|
408 |
-
return;
|
409 |
-
}
|
410 |
-
|
411 |
-
$removed_autocoupon_codes = $this->get_removed_autocoupon_codes();
|
412 |
-
if ( ! isset( $removed_autocoupon_codes[$coupon_code] ) ) {
|
413 |
-
return;
|
414 |
-
}
|
415 |
-
|
416 |
-
unset( $removed_autocoupon_codes[$coupon_code] ) ;
|
417 |
-
$this->set_removed_autocoupon_codes( $removed_autocoupon_codes );
|
418 |
-
}
|
419 |
-
|
420 |
-
/**
|
421 |
-
* Add the coupon to session 'wjecf_autocoupon_removed_coupons'
|
422 |
-
*
|
423 |
-
* @since 2.5.4
|
424 |
-
*/
|
425 |
-
function action_removed_coupon( $coupon_code ) {
|
426 |
-
if ( ! $this->is_auto_coupon( $coupon_code ) || ! $this->get_option_autocoupon_allow_remove() ) {
|
427 |
-
return;
|
428 |
-
}
|
429 |
-
//Ignore, because the auto-coupon was removed automatically (not manually by the customer)
|
430 |
-
if ( isset( $this->ignore_removal[$coupon_code] ) ) {
|
431 |
-
return;
|
432 |
-
}
|
433 |
-
|
434 |
-
$removed_autocoupon_codes = $this->get_removed_autocoupon_codes();
|
435 |
-
$removed_autocoupon_codes[$coupon_code] = $coupon_code;
|
436 |
-
$this->set_removed_autocoupon_codes( $removed_autocoupon_codes );
|
437 |
-
}
|
438 |
-
|
439 |
-
/**
|
440 |
-
* Remove 'wjecf_autocoupon_removed_coupons' from the session when cart is emptied
|
441 |
-
*
|
442 |
-
* @since 2.5.4
|
443 |
-
*/
|
444 |
-
function action_cart_emptied() {
|
445 |
-
$this->set_removed_autocoupon_codes( null );
|
446 |
-
}
|
447 |
-
|
448 |
-
/**
|
449 |
-
* Get the removed auto coupon-codes from the session
|
450 |
-
*
|
451 |
-
* @since 2.5.4
|
452 |
-
* @return array The queued coupon codes
|
453 |
-
*/
|
454 |
-
private function get_removed_autocoupon_codes( ) {
|
455 |
-
$coupon_codes = WC()->session->get( 'wjecf_autocoupon_removed_coupons' , array() );
|
456 |
-
return $coupon_codes;
|
457 |
-
}
|
458 |
-
|
459 |
-
/**
|
460 |
-
* Save the removed auto coupon-codes in the session
|
461 |
-
*
|
462 |
-
* @since 2.5.4
|
463 |
-
* @param array $coupon_codes
|
464 |
-
* @return void
|
465 |
-
*/
|
466 |
-
private function set_removed_autocoupon_codes( $coupon_codes ) {
|
467 |
-
WC()->session->set( 'wjecf_autocoupon_removed_coupons' , $coupon_codes );
|
468 |
-
}
|
469 |
-
|
470 |
-
/**
|
471 |
-
* Reads the option 'autocoupon_allow_remove'
|
472 |
-
*
|
473 |
-
* @since 2.5.4
|
474 |
-
* @return bool
|
475 |
-
*/
|
476 |
-
private function get_option_autocoupon_allow_remove() {
|
477 |
-
return WJECF()->is_pro() && WJECF()->get_option( 'autocoupon_allow_remove', false );
|
478 |
-
}
|
479 |
-
|
480 |
-
// ============ END wjecf_autocoupon_removed_coupons =======================
|
481 |
-
|
482 |
-
|
483 |
-
/**
|
484 |
-
* Apply matched autocoupons and remove unmatched autocoupons.
|
485 |
-
* @return void
|
486 |
-
*/
|
487 |
-
function update_matched_autocoupons() {
|
488 |
-
|
489 |
-
//2.3.3 Keep track of queued coupons and apply when they validate
|
490 |
-
$queuer = WJECF()->get_plugin('WJECF_Pro_Coupon_Queueing');
|
491 |
-
if ( $queuer !== false ) {
|
492 |
-
$queuer->apply_valid_queued_coupons();
|
493 |
-
}
|
494 |
-
|
495 |
-
//Get the coupons that should be in the cart
|
496 |
-
$valid_coupons = $this->get_valid_auto_coupons();
|
497 |
-
$valid_coupons = $this->individual_use_filter( $valid_coupons );
|
498 |
-
|
499 |
-
$valid_coupon_codes = array();
|
500 |
-
foreach ( $valid_coupons as $coupon ) {
|
501 |
-
$valid_coupon_codes[] = WJECF_Wrap( $coupon )->get_code();
|
502 |
-
}
|
503 |
-
|
504 |
-
$this->log( 'debug', sprintf( "Auto coupons that should be in cart: %s", implode( ', ', $valid_coupon_codes ) ) );
|
505 |
-
|
506 |
-
$calc_needed = $this->remove_unmatched_autocoupons( $valid_coupon_codes );
|
507 |
-
|
508 |
-
//Add valids
|
509 |
-
foreach( $valid_coupons as $coupon ) {
|
510 |
-
$coupon_code = WJECF_Wrap( $coupon )->get_code();
|
511 |
-
if ( ! WC()->cart->has_discount( $coupon_code ) ) {
|
512 |
-
$this->log( 'debug', sprintf( "Applying auto coupon %s", $coupon_code ) );
|
513 |
-
|
514 |
-
$apply_silently = WJECF_Wrap( $coupon )->get_meta( '_wjecf_apply_silently' ) == 'yes';
|
515 |
-
|
516 |
-
if ( $apply_silently ) {
|
517 |
-
$new_succss_msg = ''; // no message
|
518 |
-
} else {
|
519 |
-
$coupon_excerpt = WJECF_Wrap( $coupon )->get_description();
|
520 |
-
$new_succss_msg = sprintf(
|
521 |
-
__("Discount applied: %s", 'woocommerce-jos-autocoupon'),
|
522 |
-
__( empty( $coupon_excerpt ) ? $coupon_code : $coupon_excerpt, 'woocommerce-jos-autocoupon')
|
523 |
-
);
|
524 |
-
}
|
525 |
-
|
526 |
-
WJECF()->start_overwrite_success_message( $coupon, $new_succss_msg );
|
527 |
-
WC()->cart->add_discount( $coupon_code ); //Causes calculation and will remove other coupons if it's a individual coupon
|
528 |
-
WJECF()->stop_overwrite_success_message();
|
529 |
-
|
530 |
-
$calc_needed = false; //Already done by adding the discount
|
531 |
-
|
532 |
-
}
|
533 |
-
}
|
534 |
-
|
535 |
-
$this->log( 'debug', 'Coupons in cart: ' . implode( ', ', WC()->cart->applied_coupons ) . ($calc_needed ? ". RECALC" : "") );
|
536 |
-
|
537 |
-
if ( $calc_needed ) {
|
538 |
-
WC()->cart->calculate_totals();
|
539 |
-
}
|
540 |
-
|
541 |
-
}
|
542 |
-
|
543 |
-
private function get_valid_auto_coupons( ) {
|
544 |
-
$valid_coupons = array();
|
545 |
-
|
546 |
-
//Array will only have values if option autocoupon_allow_remove == true
|
547 |
-
$removed_autocoupon_codes = $this->get_option_autocoupon_allow_remove() ? $this->get_removed_autocoupon_codes() : array();
|
548 |
-
|
549 |
-
foreach ( $this->get_all_auto_coupons() as $coupon_code => $coupon ) {
|
550 |
-
if ( isset( $removed_autocoupon_codes[ $coupon_code ] ) ) continue;
|
551 |
-
if ( ! $this->coupon_can_be_applied( $coupon ) ) continue;
|
552 |
-
if ( ! $this->coupon_has_a_value( $coupon ) ) continue;
|
553 |
-
|
554 |
-
$valid_coupons[] = $coupon;
|
555 |
-
}
|
556 |
-
return $valid_coupons;
|
557 |
-
}
|
558 |
-
|
559 |
-
/**
|
560 |
-
* Test whether the coupon is valid (to be auto-applied)
|
561 |
-
* @return bool
|
562 |
-
*/
|
563 |
-
private function coupon_can_be_applied( $coupon ) {
|
564 |
-
$wrap_coupon = WJECF_Wrap( $coupon );
|
565 |
-
$can_be_applied = true;
|
566 |
-
|
567 |
-
//Test validity
|
568 |
-
if ( ! $coupon->is_valid() ) {
|
569 |
-
$can_be_applied = false;
|
570 |
-
}
|
571 |
-
else if ( $can_be_applied && is_array( $wrap_coupon->get_email_restrictions() ) && sizeof( $wrap_coupon->get_email_restrictions() ) > 0 ) {
|
572 |
-
//Test restricted emails
|
573 |
-
//See WooCommerce: class-wc-cart.php function check_customer_coupons
|
574 |
-
$user_emails = array_map( 'sanitize_email', array_map( 'strtolower', WJECF()->get_user_emails() ) );
|
575 |
-
$coupon_emails = array_map( 'sanitize_email', array_map( 'strtolower', $wrap_coupon->get_email_restrictions() ) );
|
576 |
-
|
577 |
-
if ( 0 == sizeof( array_intersect( $user_emails, $coupon_emails ) ) ) {
|
578 |
-
$can_be_applied = false;
|
579 |
-
}
|
580 |
-
|
581 |
-
$this->log( sprintf( 'Coupon emails: [ %s ] User emails: [ %s ] Match: %s',
|
582 |
-
join( ', ', $coupon_emails ),
|
583 |
-
join( ', ', $user_emails ),
|
584 |
-
$can_be_applied ? 'yes' : 'no'
|
585 |
-
) );
|
586 |
-
}
|
587 |
-
return apply_filters( 'wjecf_coupon_can_be_applied', $can_be_applied, $coupon );
|
588 |
-
|
589 |
-
}
|
590 |
-
|
591 |
-
/**
|
592 |
-
* Does the coupon have a value? (autocoupon should not be applied if it has no value)
|
593 |
-
* @param WC_Coupon $coupon The coupon data
|
594 |
-
* @return bool True if it has a value (discount, free shipping, whatever) otherwise false)
|
595 |
-
**/
|
596 |
-
function coupon_has_a_value( $coupon ) {
|
597 |
-
|
598 |
-
$has_a_value = false;
|
599 |
-
|
600 |
-
if ( $coupon->is_type('free_gift') ) { // 'WooCommerce Free Gift Coupons'-plugin
|
601 |
-
$has_a_value = true;
|
602 |
-
}
|
603 |
-
elseif ( WJECF_Wrap( $coupon )->get_free_shipping() ) {
|
604 |
-
$has_a_value = true;
|
605 |
-
}
|
606 |
-
else {
|
607 |
-
//Test whether discount > 0
|
608 |
-
//See WooCommerce: class-wc-cart.php function get_discounted_price
|
609 |
-
global $woocommerce;
|
610 |
-
foreach ( $woocommerce->cart->get_cart() as $cart_item ) {
|
611 |
-
if ( $coupon->is_valid_for_cart() || $coupon->is_valid_for_product( $cart_item['data'], $cart_item ) ) {
|
612 |
-
$has_a_value = WJECF_Wrap( $coupon )->get_amount() > 0;
|
613 |
-
break;
|
614 |
-
}
|
615 |
-
}
|
616 |
-
}
|
617 |
-
|
618 |
-
return apply_filters( 'wjecf_coupon_has_a_value', $has_a_value, $coupon );
|
619 |
-
}
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
/**
|
624 |
-
* Check wether the coupon is an "Auto coupon".
|
625 |
-
* @param WC_Coupon $coupon The coupon data
|
626 |
-
* @return bool true if it is an "Auto coupon"
|
627 |
-
*/
|
628 |
-
public function is_auto_coupon( $coupon ) {
|
629 |
-
return WJECF_Wrap( $coupon )->get_meta( '_wjecf_is_auto_coupon' ) == 'yes';
|
630 |
-
}
|
631 |
-
|
632 |
-
private function get_coupon_priority($coupon) {
|
633 |
-
if ( WJECF()->is_pro() ) {
|
634 |
-
$prio = WJECF_Wrap( $coupon )->get_meta( '_wjecf_coupon_priority' );
|
635 |
-
if ( ! empty( $prio ) ) {
|
636 |
-
return intval( $prio );
|
637 |
-
}
|
638 |
-
}
|
639 |
-
return 0;
|
640 |
-
}
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
/**
|
645 |
-
* Return an array of WC_Coupons with coupons that shouldn't cause individual use conflicts
|
646 |
-
*/
|
647 |
-
private function individual_use_filter( $valid_auto_coupons ) {
|
648 |
-
$filtered = array();
|
649 |
-
|
650 |
-
//Any individual use non-autocoupons in the cart?
|
651 |
-
foreach ( WC()->cart->get_applied_coupons() as $coupon_code ) {
|
652 |
-
$coupon = new WC_Coupon( $coupon_code );
|
653 |
-
if ( WJECF_Wrap( $coupon )->get_individual_use() && ! $this->is_auto_coupon( $coupon ) ) {
|
654 |
-
return $filtered; //Don't allow any auto coupon
|
655 |
-
}
|
656 |
-
}
|
657 |
-
foreach ( $valid_auto_coupons as $coupon ) {
|
658 |
-
if ( ! WJECF_Wrap( $coupon )->get_individual_use() || empty( $filtered ) ) {
|
659 |
-
$filtered[] = $coupon;
|
660 |
-
if ( WJECF_Wrap( $coupon )->get_individual_use() ) {
|
661 |
-
break;
|
662 |
-
}
|
663 |
-
}
|
664 |
-
}
|
665 |
-
return $filtered;
|
666 |
-
}
|
667 |
-
|
668 |
-
/**
|
669 |
-
* Get an array of all auto coupons [ $coupon_code => $coupon ]
|
670 |
-
* @return array All auto coupon codes
|
671 |
-
*/
|
672 |
-
public function get_all_auto_coupons() {
|
673 |
-
if ( ! is_array( $this->_autocoupons ) ) {
|
674 |
-
$this->_autocoupons = array();
|
675 |
-
|
676 |
-
$query_args = array(
|
677 |
-
'posts_per_page' => -1,
|
678 |
-
'post_type' => 'shop_coupon',
|
679 |
-
'post_status' => 'publish',
|
680 |
-
'orderby' => array( 'title' => 'ASC' ),
|
681 |
-
'meta_query' => array(
|
682 |
-
array(
|
683 |
-
'key' => '_wjecf_is_auto_coupon',
|
684 |
-
'compare' => '=',
|
685 |
-
'value' => 'yes',
|
686 |
-
),
|
687 |
-
)
|
688 |
-
);
|
689 |
-
|
690 |
-
$query = new WP_Query($query_args);
|
691 |
-
foreach ($query->posts as $post) {
|
692 |
-
$coupon = new WC_Coupon($post->post_title);
|
693 |
-
if ( $this->is_auto_coupon($coupon) ) {
|
694 |
-
$this->_autocoupons[ WJECF_Wrap( $coupon )->get_code() ] = $coupon;
|
695 |
-
}
|
696 |
-
}
|
697 |
-
|
698 |
-
//Sort by priority
|
699 |
-
@uasort( $this->_autocoupons , array( $this, 'sort_auto_coupons' ) ); //Ignore error PHP Bug #50688
|
700 |
-
|
701 |
-
$coupon_codes = array();
|
702 |
-
foreach( $this->_autocoupons as $coupon ) {
|
703 |
-
$coupon_codes[] = WJECF_Wrap( $coupon )->get_code();
|
704 |
-
}
|
705 |
-
|
706 |
-
$this->log( 'debug', "Autocoupons: " . implode(", ", $coupon_codes ) );
|
707 |
-
}
|
708 |
-
|
709 |
-
return $this->_autocoupons;
|
710 |
-
}
|
711 |
-
|
712 |
-
/**
|
713 |
-
* Compare function to sort coupons by priority
|
714 |
-
* @param type $a
|
715 |
-
* @param type $b
|
716 |
-
* @return type
|
717 |
-
*/
|
718 |
-
private function sort_auto_coupons( $coupon_a, $coupon_b ) {
|
719 |
-
$prio_a = $this->get_coupon_priority( $coupon_a );
|
720 |
-
$prio_b = $this->get_coupon_priority( $coupon_b );
|
721 |
-
//$this->log( 'debug', "A: $prio_a B: $prio_b " );
|
722 |
-
if ( $prio_a == $prio_b ) {
|
723 |
-
return WJECF_Wrap( $coupon_a )->get_code() < WJECF_Wrap( $coupon_b )->get_code() ? -1 : 1; //By title ASC
|
724 |
-
} else {
|
725 |
-
return $prio_a > $prio_b ? -1 : 1; //By prio DESC
|
726 |
-
}
|
727 |
-
}
|
728 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
defined('ABSPATH') or die();
|
4 |
+
|
5 |
+
class WJECF_AutoCoupon extends Abstract_WJECF_Plugin {
|
6 |
+
|
7 |
+
protected $options = null; // WJECF_Options object
|
8 |
+
protected $_autocoupons = null;
|
9 |
+
protected $_executed_coupon_by_url = false;
|
10 |
+
|
11 |
+
public function __construct() {
|
12 |
+
$this->set_plugin_data( array(
|
13 |
+
'description' => __( 'Allow coupons to be automatically applied to the cart when restrictions are met or by url.', 'woocommerce-jos-autocoupon' ),
|
14 |
+
'dependencies' => array(),
|
15 |
+
'can_be_disabled' => true
|
16 |
+
) );
|
17 |
+
}
|
18 |
+
|
19 |
+
public function init_hook() {
|
20 |
+
//Since 2.6.2 check for frontend request. Prevents 'Call to undefined function wc_add_notice()'.
|
21 |
+
if ( ! class_exists('WC_Coupon') || ! WJECF()->is_request( 'frontend' ) ) {
|
22 |
+
return;
|
23 |
+
}
|
24 |
+
|
25 |
+
//NOTE: WPML Causes an extra calculate_totals() !!!
|
26 |
+
|
27 |
+
//Frontend hooks - logic
|
28 |
+
if ( WJECF_WC()->check_woocommerce_version('2.3.0')) {
|
29 |
+
WJECF()->safe_add_action( 'woocommerce_after_calculate_totals', array( $this, 'update_matched_autocoupons' ) );
|
30 |
+
} else {
|
31 |
+
//WC Versions prior to 2.3.0 don't have after_calculate_totals hook, this is a fallback
|
32 |
+
WJECF()->safe_add_action( 'woocommerce_cart_updated', array( $this, 'update_matched_autocoupons' ) );
|
33 |
+
}
|
34 |
+
|
35 |
+
add_action( 'woocommerce_check_cart_items', array( $this, 'remove_unmatched_autocoupons' ) , 0, 0 ); //Remove coupon before WC does it and shows a message
|
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 ( ! WJECF()->is_request( 'ajax' ) ) {
|
45 |
+
//Get cart should not be called before the wp_loaded action nor the add_to_cart_action (class-wc-form-handler)
|
46 |
+
add_action( 'wp_loaded', array( &$this, 'coupon_by_url' ), 90 ); //Coupon through url
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Mark removed autocoupons to prevent them from being automatically applied again
|
51 |
+
* (PRO Only)
|
52 |
+
* @since 2.5.4
|
53 |
+
*/
|
54 |
+
add_action( 'woocommerce_applied_coupon', array( $this, 'action_applied_coupon' ), 10, 1 );
|
55 |
+
add_action( 'woocommerce_removed_coupon', array( $this, 'action_removed_coupon' ), 10, 1 );
|
56 |
+
add_action( 'woocommerce_cart_emptied', array( $this, 'action_cart_emptied' ), 10, 0 );
|
57 |
+
}
|
58 |
+
|
59 |
+
/* ADMIN HOOKS */
|
60 |
+
public function init_admin_hook() {
|
61 |
+
add_action( 'wjecf_woocommerce_coupon_options_extended_features', array( $this, 'admin_coupon_options_extended_features' ), 20, 2 );
|
62 |
+
|
63 |
+
//Inject columns
|
64 |
+
if ( WJECF()->is_pro() ) {
|
65 |
+
WJECF()->inject_coupon_column(
|
66 |
+
'_wjecf_auto_coupon',
|
67 |
+
__( 'Auto coupon', 'woocommerce-jos-autocoupon' ),
|
68 |
+
array( $this, 'admin_render_shop_coupon_columns' ), 'coupon_code'
|
69 |
+
);
|
70 |
+
WJECF()->inject_coupon_column(
|
71 |
+
'_wjecf_individual_use',
|
72 |
+
__( 'Individual use', 'woocommerce-jos-autocoupon' ),
|
73 |
+
array( $this, 'admin_render_shop_coupon_columns' ), 'coupon_code'
|
74 |
+
);
|
75 |
+
}
|
76 |
+
|
77 |
+
add_filter( 'views_edit-shop_coupon', array( $this, 'admin_views_edit_coupon' ) );
|
78 |
+
add_filter( 'request', array( $this, 'admin_request_query' ) );
|
79 |
+
|
80 |
+
add_action( 'wjecf_admin_before_settings', array( $this, 'wjecf_admin_before_settings' ), 20 );
|
81 |
+
add_filter( 'wjecf_admin_validate_settings', array( $this, 'wjecf_admin_validate_settings' ), 10, 2 );
|
82 |
+
}
|
83 |
+
|
84 |
+
public function wjecf_admin_before_settings() {
|
85 |
+
$page = WJECF_Admin_Settings::SETTINGS_PAGE;
|
86 |
+
|
87 |
+
if ( WJECF()->is_pro() ) {
|
88 |
+
add_settings_section(
|
89 |
+
WJECF_Admin_Settings::DOM_PREFIX . 'section_autocoupon',
|
90 |
+
__( 'Auto coupons', 'woocommerce-jos-autocoupon' ),
|
91 |
+
array( $this, 'render_section' ),
|
92 |
+
$page
|
93 |
+
);
|
94 |
+
|
95 |
+
add_settings_field(
|
96 |
+
WJECF_Admin_Settings::DOM_PREFIX . 'autocoupon_allow_remove',
|
97 |
+
__( 'Allow remove \'Auto Coupons\'', 'woocommerce-jos-autocoupon' ),
|
98 |
+
array( $this, 'render_setting_allow_remove_auto_coupon' ),
|
99 |
+
$page,
|
100 |
+
WJECF_Admin_Settings::DOM_PREFIX . 'section_autocoupon'
|
101 |
+
);
|
102 |
+
}
|
103 |
+
}
|
104 |
+
|
105 |
+
public function render_section( $section ) {
|
106 |
+
switch ( $section['id'] ) {
|
107 |
+
case WJECF_Admin_Settings::DOM_PREFIX . 'section_autocoupon':
|
108 |
+
//$body = ".....";
|
109 |
+
//printf( '<p>%s</p>', $body );
|
110 |
+
break;
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
public function render_setting_allow_remove_auto_coupon() {
|
115 |
+
$option_name = 'autocoupon_allow_remove';
|
116 |
+
$args = array(
|
117 |
+
'type' => 'checkbox',
|
118 |
+
'id' => WJECF_Admin_Settings::DOM_PREFIX . $option_name,
|
119 |
+
'name' => sprintf( "%s[%s]", WJECF_Admin_Settings::OPTION_NAME, $option_name ),
|
120 |
+
'value' => WJECF()->get_option( $option_name, false ) ? 'yes' : 'no'
|
121 |
+
);
|
122 |
+
|
123 |
+
WJECF_Admin_Html::render_input( $args );
|
124 |
+
WJECF_Admin_Html::render_tag(
|
125 |
+
'label',
|
126 |
+
array( "for" => esc_attr( $args['id'] ) ),
|
127 |
+
__( 'Enabled', 'woocommerce' )
|
128 |
+
);
|
129 |
+
WJECF_Admin_Html::render_tag(
|
130 |
+
'p',
|
131 |
+
array( 'class' => 'description'),
|
132 |
+
__( 'Check this box to allow the customer to remove \'Auto Coupons\' from the cart.', 'woocommerce-jos-autocoupon' )
|
133 |
+
);
|
134 |
+
|
135 |
+
}
|
136 |
+
|
137 |
+
public function wjecf_admin_validate_settings( $options, $input ) {
|
138 |
+
$options['autocoupon_allow_remove'] = isset( $input['autocoupon_allow_remove'] ) && $input['autocoupon_allow_remove'] === 'yes';
|
139 |
+
return $options;
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Output a coupon custom column value
|
144 |
+
*
|
145 |
+
* @param string $column
|
146 |
+
* @param WP_Post The coupon post object
|
147 |
+
*/
|
148 |
+
public function admin_render_shop_coupon_columns( $column, $post ) {
|
149 |
+
$wrap_coupon = WJECF_Wrap( intval( $post->ID ) );
|
150 |
+
|
151 |
+
switch ( $column ) {
|
152 |
+
case '_wjecf_auto_coupon' :
|
153 |
+
$is_auto_coupon = $wrap_coupon->get_meta( '_wjecf_is_auto_coupon', true ) == 'yes';
|
154 |
+
echo $is_auto_coupon ? __( 'Yes', 'woocommerce' ) : __( 'No', 'woocommerce' );
|
155 |
+
if ( $is_auto_coupon ) {
|
156 |
+
$prio = $wrap_coupon->get_meta( '_wjecf_coupon_priority', true );
|
157 |
+
if ( $prio ) echo " (" . intval( $prio ) . ")";
|
158 |
+
}
|
159 |
+
break;
|
160 |
+
case '_wjecf_individual_use' :
|
161 |
+
$individual = $wrap_coupon->get_individual_use();
|
162 |
+
echo $individual ? __( 'Yes', 'woocommerce' ) : __( 'No', 'woocommerce' );
|
163 |
+
break;
|
164 |
+
}
|
165 |
+
}
|
166 |
+
|
167 |
+
public function admin_views_edit_coupon( $views ) {
|
168 |
+
global $post_type, $wp_query;
|
169 |
+
|
170 |
+
$class = ( isset( $wp_query->query['meta_key'] ) && $wp_query->query['meta_key'] == '_wjecf_is_auto_coupon' ) ? 'current' : '';
|
171 |
+
$query_string = remove_query_arg(array( 'wjecf_is_auto_coupon' ));
|
172 |
+
$query_string = add_query_arg( 'wjecf_is_auto_coupon', '1', $query_string );
|
173 |
+
$views['wjecf_is_auto_coupon'] = '<a href="' . esc_url( $query_string ) . '" class="' . esc_attr( $class ) . '">' . __( 'Auto coupons', 'woocommerce-jos-autocoupon' ) . '</a>';
|
174 |
+
|
175 |
+
return $views;
|
176 |
+
}
|
177 |
+
|
178 |
+
/**
|
179 |
+
* Filters and sorting handler
|
180 |
+
*
|
181 |
+
* @param array $vars
|
182 |
+
* @return array
|
183 |
+
*/
|
184 |
+
public function admin_request_query( $vars ) {
|
185 |
+
global $typenow, $wp_query, $wp_post_statuses;
|
186 |
+
|
187 |
+
if ( 'shop_coupon' === $typenow ) {
|
188 |
+
if ( isset( $_GET['wjecf_is_auto_coupon'] ) ) {
|
189 |
+
$vars['meta_key'] = '_wjecf_is_auto_coupon';
|
190 |
+
$vars['meta_value'] = $_GET['wjecf_is_auto_coupon'] == '1' ? 'yes' : 'no';
|
191 |
+
}
|
192 |
+
}
|
193 |
+
|
194 |
+
return $vars;
|
195 |
+
}
|
196 |
+
|
197 |
+
public function admin_coupon_options_extended_features( $thepostid, $post ) {
|
198 |
+
|
199 |
+
//=============================
|
200 |
+
//Title
|
201 |
+
echo "<h3>" . esc_html( __( 'Auto coupon', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
|
202 |
+
|
203 |
+
|
204 |
+
//=============================
|
205 |
+
// Auto coupon checkbox
|
206 |
+
woocommerce_wp_checkbox( array(
|
207 |
+
'id' => '_wjecf_is_auto_coupon',
|
208 |
+
'label' => __( 'Auto coupon', 'woocommerce-jos-autocoupon' ),
|
209 |
+
'description' => __( "Automatically add the coupon to the cart if the restrictions are met. Please enter a description when you check this box, the description will be shown in the customer's cart if the coupon is applied.", 'woocommerce-jos-autocoupon' )
|
210 |
+
) );
|
211 |
+
|
212 |
+
echo '<div class="_wjecf_show_if_autocoupon">';
|
213 |
+
if ( WJECF()->is_pro() ) {
|
214 |
+
// Maximum quantity of matching products (product/category)
|
215 |
+
woocommerce_wp_text_input( array(
|
216 |
+
'id' => '_wjecf_coupon_priority',
|
217 |
+
'label' => __( 'Priority', 'woocommerce-jos-autocoupon' ),
|
218 |
+
'placeholder' => __( 'No priority', 'woocommerce' ),
|
219 |
+
'description' => __( 'When \'individual use\' is checked, auto coupons with a higher value will have priority over other auto coupons.', 'woocommerce-jos-autocoupon' ),
|
220 |
+
'data_type' => 'decimal',
|
221 |
+
'desc_tip' => true
|
222 |
+
) );
|
223 |
+
}
|
224 |
+
|
225 |
+
//=============================
|
226 |
+
// Apply without notice
|
227 |
+
woocommerce_wp_checkbox( array(
|
228 |
+
'id' => '_wjecf_apply_silently',
|
229 |
+
'label' => __( 'Apply silently', 'woocommerce-jos-autocoupon' ),
|
230 |
+
'description' => __( "Don't display a message when this coupon is automatically applied.", 'woocommerce-jos-autocoupon' ),
|
231 |
+
) );
|
232 |
+
echo '</div>';
|
233 |
+
|
234 |
+
?>
|
235 |
+
<script type="text/javascript">
|
236 |
+
//Hide/show when AUTO-COUPON value changes
|
237 |
+
function update_wjecf_apply_silently_field( animation ) {
|
238 |
+
if ( animation === undefined ) animation = 'slow';
|
239 |
+
|
240 |
+
if (jQuery("#_wjecf_is_auto_coupon").prop('checked')) {
|
241 |
+
jQuery("._wjecf_show_if_autocoupon").show( animation );
|
242 |
+
jQuery("._wjecf_hide_if_autocoupon").hide( animation );
|
243 |
+
} else {
|
244 |
+
jQuery("._wjecf_show_if_autocoupon").hide( animation );
|
245 |
+
jQuery("._wjecf_hide_if_autocoupon").show( animation );
|
246 |
+
}
|
247 |
+
}
|
248 |
+
|
249 |
+
jQuery( function( $ ) {
|
250 |
+
update_wjecf_apply_silently_field( 0 );
|
251 |
+
$("#_wjecf_is_auto_coupon").click( update_wjecf_apply_silently_field );
|
252 |
+
} );
|
253 |
+
</script>
|
254 |
+
<?php
|
255 |
+
|
256 |
+
}
|
257 |
+
|
258 |
+
public function admin_coupon_meta_fields( $coupon ) {
|
259 |
+
$fields = array(
|
260 |
+
'_wjecf_is_auto_coupon' => 'yesno',
|
261 |
+
'_wjecf_apply_silently' => 'yesno',
|
262 |
+
);
|
263 |
+
|
264 |
+
if ( WJECF()->is_pro() ) {
|
265 |
+
$fields['_wjecf_coupon_priority'] = 'int';
|
266 |
+
}
|
267 |
+
return $fields;
|
268 |
+
}
|
269 |
+
|
270 |
+
/* FRONTEND HOOKS */
|
271 |
+
|
272 |
+
/**
|
273 |
+
** Inhibit redirect to cart when apply_coupon supplied
|
274 |
+
*/
|
275 |
+
public function option_woocommerce_cart_redirect_after_add( $value ) {
|
276 |
+
if ( ! $this->_executed_coupon_by_url && isset( $_GET['apply_coupon'] ) ) {
|
277 |
+
$value = 'no';
|
278 |
+
}
|
279 |
+
return $value;
|
280 |
+
}
|
281 |
+
|
282 |
+
/**
|
283 |
+
* Add coupon through url
|
284 |
+
*/
|
285 |
+
public function coupon_by_url() {
|
286 |
+
$must_redirect = false;
|
287 |
+
|
288 |
+
//Apply coupon by url
|
289 |
+
if ( isset( $_GET['apply_coupon'] ) ) {
|
290 |
+
$must_redirect = true;
|
291 |
+
$this->_executed_coupon_by_url = true;
|
292 |
+
$split = explode( ",", wc_clean( $_GET['apply_coupon'] ) );
|
293 |
+
//2.2.2 Make sure a session cookie is set
|
294 |
+
if( ! WC()->session->has_session() )
|
295 |
+
{
|
296 |
+
WC()->session->set_customer_session_cookie( true );
|
297 |
+
}
|
298 |
+
|
299 |
+
$cart = WC()->cart;
|
300 |
+
foreach ( $split as $coupon_code ) {
|
301 |
+
$coupon = WJECF_WC()->get_coupon( $coupon_code );
|
302 |
+
if ( WJECF_WC()->check_woocommerce_version('2.3.0') && ! WJECF_Wrap( $coupon )->exists() ) {
|
303 |
+
wc_add_notice( $coupon->get_coupon_error( WC_Coupon::E_WC_COUPON_NOT_EXIST ), 'error' );
|
304 |
+
} else {
|
305 |
+
$valid = $coupon->is_valid();
|
306 |
+
if ( $valid ) {
|
307 |
+
$cart->add_discount( $coupon_code );
|
308 |
+
}
|
309 |
+
}
|
310 |
+
}
|
311 |
+
}
|
312 |
+
|
313 |
+
//Redirect to page without autocoupon query args
|
314 |
+
if ( $must_redirect ) {
|
315 |
+
$requested_url = is_ssl() ? 'https://' : 'http://';
|
316 |
+
$requested_url .= $_SERVER['HTTP_HOST'];
|
317 |
+
$requested_url .= $_SERVER['REQUEST_URI'];
|
318 |
+
|
319 |
+
wp_safe_redirect( remove_query_arg( array( 'apply_coupon', 'add-to-cart' ), ( $requested_url ) ) );
|
320 |
+
exit;
|
321 |
+
}
|
322 |
+
}
|
323 |
+
|
324 |
+
/**
|
325 |
+
* Overwrite the html created by wc_cart_totals_coupon_label() so a descriptive text will be shown for the discount.
|
326 |
+
* @param string $originaltext The default text created by wc_cart_totals_coupon_label()
|
327 |
+
* @param WC_Coupon $coupon The coupon data
|
328 |
+
* @return string The overwritten text
|
329 |
+
*/
|
330 |
+
function coupon_label( $originaltext, $coupon ) {
|
331 |
+
|
332 |
+
if ( $this->is_auto_coupon($coupon) ) {
|
333 |
+
return WJECF_Wrap( $coupon )->get_description();
|
334 |
+
} else {
|
335 |
+
return $originaltext;
|
336 |
+
}
|
337 |
+
}
|
338 |
+
|
339 |
+
/**
|
340 |
+
* Overwrite the html created by wc_cart_totals_coupon_html(). This function is required to remove the "Remove" link.
|
341 |
+
* @param string $originaltext The html created by wc_cart_totals_coupon_html()
|
342 |
+
* @param WC_Coupon $coupon The coupon data
|
343 |
+
* @return string The overwritten html
|
344 |
+
*/
|
345 |
+
function coupon_html( $originaltext, $coupon ) {
|
346 |
+
if ( $this->is_auto_coupon( $coupon ) && ! $this->get_option_autocoupon_allow_remove() ) {
|
347 |
+
$value = array();
|
348 |
+
|
349 |
+
if ( $amount = WC()->cart->get_coupon_discount_amount( WJECF_Wrap( $coupon )->get_code(), WC()->cart->display_cart_ex_tax ) ) {
|
350 |
+
$discount_html = '-' . wc_price( $amount );
|
351 |
+
} else {
|
352 |
+
$discount_html = '';
|
353 |
+
}
|
354 |
+
|
355 |
+
$value[] = apply_filters( 'woocommerce_coupon_discount_amount_html', $discount_html, $coupon );
|
356 |
+
|
357 |
+
if ( WJECF_Wrap( $coupon )->get_free_shipping() ) {
|
358 |
+
$value[] = __( 'Free shipping coupon', 'woocommerce' );
|
359 |
+
}
|
360 |
+
|
361 |
+
return implode( ', ', array_filter($value) ); //Remove empty array elements
|
362 |
+
} else {
|
363 |
+
return $originaltext;
|
364 |
+
}
|
365 |
+
}
|
366 |
+
|
367 |
+
function remove_unmatched_autocoupons( $valid_coupon_codes = null ) {
|
368 |
+
if ( $valid_coupon_codes === null ) {
|
369 |
+
//Get the coupons that should be in the cart
|
370 |
+
$valid_coupons = $this->get_valid_auto_coupons();
|
371 |
+
$valid_coupons = $this->individual_use_filter( $valid_coupons );
|
372 |
+
$valid_coupon_codes = array();
|
373 |
+
foreach ( $valid_coupons as $coupon ) {
|
374 |
+
$valid_coupon_codes[] = WJECF_Wrap( $coupon )->get_code();
|
375 |
+
}
|
376 |
+
}
|
377 |
+
|
378 |
+
//Remove invalids
|
379 |
+
$calc_needed = false;
|
380 |
+
foreach ( $this->get_all_auto_coupons() as $coupon ) {
|
381 |
+
$coupon_code = WJECF_Wrap( $coupon )->get_code();
|
382 |
+
if ( WC()->cart->has_discount( $coupon_code ) && ! in_array( $coupon_code, $valid_coupon_codes ) ) {
|
383 |
+
$this->log( 'debug', sprintf( "Removing %s", $coupon_code ) );
|
384 |
+
$this->ignore_removal[$coupon_code] = $coupon_code;
|
385 |
+
WC()->cart->remove_coupon( $coupon_code );
|
386 |
+
unset( $this->ignore_removal[$coupon_code] );
|
387 |
+
$calc_needed = true;
|
388 |
+
}
|
389 |
+
}
|
390 |
+
return $calc_needed;
|
391 |
+
}
|
392 |
+
|
393 |
+
|
394 |
+
// ============ BEGIN wjecf_autocoupon_removed_coupons =======================
|
395 |
+
|
396 |
+
// When a custom clicks the [remove]-button of an auto coupon, the coupon will not be applied automatically anymore...
|
397 |
+
// After that the coupon can only be applied manually by entering the coupon code.
|
398 |
+
|
399 |
+
//Will ignore the remove_coupon action for the given keys
|
400 |
+
private $ignore_removal = array( /* coupon_code => coupon_code */ );
|
401 |
+
|
402 |
+
/**
|
403 |
+
* Remove the coupon from session 'wjecf_autocoupon_removed_coupons'
|
404 |
+
* @since 2.5.4
|
405 |
+
*/
|
406 |
+
function action_applied_coupon( $coupon_code ) {
|
407 |
+
if ( ! $this->is_auto_coupon( $coupon_code ) || ! $this->get_option_autocoupon_allow_remove() ) {
|
408 |
+
return;
|
409 |
+
}
|
410 |
+
|
411 |
+
$removed_autocoupon_codes = $this->get_removed_autocoupon_codes();
|
412 |
+
if ( ! isset( $removed_autocoupon_codes[$coupon_code] ) ) {
|
413 |
+
return;
|
414 |
+
}
|
415 |
+
|
416 |
+
unset( $removed_autocoupon_codes[$coupon_code] ) ;
|
417 |
+
$this->set_removed_autocoupon_codes( $removed_autocoupon_codes );
|
418 |
+
}
|
419 |
+
|
420 |
+
/**
|
421 |
+
* Add the coupon to session 'wjecf_autocoupon_removed_coupons'
|
422 |
+
*
|
423 |
+
* @since 2.5.4
|
424 |
+
*/
|
425 |
+
function action_removed_coupon( $coupon_code ) {
|
426 |
+
if ( ! $this->is_auto_coupon( $coupon_code ) || ! $this->get_option_autocoupon_allow_remove() ) {
|
427 |
+
return;
|
428 |
+
}
|
429 |
+
//Ignore, because the auto-coupon was removed automatically (not manually by the customer)
|
430 |
+
if ( isset( $this->ignore_removal[$coupon_code] ) ) {
|
431 |
+
return;
|
432 |
+
}
|
433 |
+
|
434 |
+
$removed_autocoupon_codes = $this->get_removed_autocoupon_codes();
|
435 |
+
$removed_autocoupon_codes[$coupon_code] = $coupon_code;
|
436 |
+
$this->set_removed_autocoupon_codes( $removed_autocoupon_codes );
|
437 |
+
}
|
438 |
+
|
439 |
+
/**
|
440 |
+
* Remove 'wjecf_autocoupon_removed_coupons' from the session when cart is emptied
|
441 |
+
*
|
442 |
+
* @since 2.5.4
|
443 |
+
*/
|
444 |
+
function action_cart_emptied() {
|
445 |
+
$this->set_removed_autocoupon_codes( null );
|
446 |
+
}
|
447 |
+
|
448 |
+
/**
|
449 |
+
* Get the removed auto coupon-codes from the session
|
450 |
+
*
|
451 |
+
* @since 2.5.4
|
452 |
+
* @return array The queued coupon codes
|
453 |
+
*/
|
454 |
+
private function get_removed_autocoupon_codes( ) {
|
455 |
+
$coupon_codes = WC()->session->get( 'wjecf_autocoupon_removed_coupons' , array() );
|
456 |
+
return $coupon_codes;
|
457 |
+
}
|
458 |
+
|
459 |
+
/**
|
460 |
+
* Save the removed auto coupon-codes in the session
|
461 |
+
*
|
462 |
+
* @since 2.5.4
|
463 |
+
* @param array $coupon_codes
|
464 |
+
* @return void
|
465 |
+
*/
|
466 |
+
private function set_removed_autocoupon_codes( $coupon_codes ) {
|
467 |
+
WC()->session->set( 'wjecf_autocoupon_removed_coupons' , $coupon_codes );
|
468 |
+
}
|
469 |
+
|
470 |
+
/**
|
471 |
+
* Reads the option 'autocoupon_allow_remove'
|
472 |
+
*
|
473 |
+
* @since 2.5.4
|
474 |
+
* @return bool
|
475 |
+
*/
|
476 |
+
private function get_option_autocoupon_allow_remove() {
|
477 |
+
return WJECF()->is_pro() && WJECF()->get_option( 'autocoupon_allow_remove', false );
|
478 |
+
}
|
479 |
+
|
480 |
+
// ============ END wjecf_autocoupon_removed_coupons =======================
|
481 |
+
|
482 |
+
|
483 |
+
/**
|
484 |
+
* Apply matched autocoupons and remove unmatched autocoupons.
|
485 |
+
* @return void
|
486 |
+
*/
|
487 |
+
function update_matched_autocoupons() {
|
488 |
+
|
489 |
+
//2.3.3 Keep track of queued coupons and apply when they validate
|
490 |
+
$queuer = WJECF()->get_plugin('WJECF_Pro_Coupon_Queueing');
|
491 |
+
if ( $queuer !== false ) {
|
492 |
+
$queuer->apply_valid_queued_coupons();
|
493 |
+
}
|
494 |
+
|
495 |
+
//Get the coupons that should be in the cart
|
496 |
+
$valid_coupons = $this->get_valid_auto_coupons();
|
497 |
+
$valid_coupons = $this->individual_use_filter( $valid_coupons );
|
498 |
+
|
499 |
+
$valid_coupon_codes = array();
|
500 |
+
foreach ( $valid_coupons as $coupon ) {
|
501 |
+
$valid_coupon_codes[] = WJECF_Wrap( $coupon )->get_code();
|
502 |
+
}
|
503 |
+
|
504 |
+
$this->log( 'debug', sprintf( "Auto coupons that should be in cart: %s", implode( ', ', $valid_coupon_codes ) ) );
|
505 |
+
|
506 |
+
$calc_needed = $this->remove_unmatched_autocoupons( $valid_coupon_codes );
|
507 |
+
|
508 |
+
//Add valids
|
509 |
+
foreach( $valid_coupons as $coupon ) {
|
510 |
+
$coupon_code = WJECF_Wrap( $coupon )->get_code();
|
511 |
+
if ( ! WC()->cart->has_discount( $coupon_code ) ) {
|
512 |
+
$this->log( 'debug', sprintf( "Applying auto coupon %s", $coupon_code ) );
|
513 |
+
|
514 |
+
$apply_silently = WJECF_Wrap( $coupon )->get_meta( '_wjecf_apply_silently' ) == 'yes';
|
515 |
+
|
516 |
+
if ( $apply_silently ) {
|
517 |
+
$new_succss_msg = ''; // no message
|
518 |
+
} else {
|
519 |
+
$coupon_excerpt = WJECF_Wrap( $coupon )->get_description();
|
520 |
+
$new_succss_msg = sprintf(
|
521 |
+
__("Discount applied: %s", 'woocommerce-jos-autocoupon'),
|
522 |
+
__( empty( $coupon_excerpt ) ? $coupon_code : $coupon_excerpt, 'woocommerce-jos-autocoupon')
|
523 |
+
);
|
524 |
+
}
|
525 |
+
|
526 |
+
WJECF()->start_overwrite_success_message( $coupon, $new_succss_msg );
|
527 |
+
WC()->cart->add_discount( $coupon_code ); //Causes calculation and will remove other coupons if it's a individual coupon
|
528 |
+
WJECF()->stop_overwrite_success_message();
|
529 |
+
|
530 |
+
$calc_needed = false; //Already done by adding the discount
|
531 |
+
|
532 |
+
}
|
533 |
+
}
|
534 |
+
|
535 |
+
$this->log( 'debug', 'Coupons in cart: ' . implode( ', ', WC()->cart->applied_coupons ) . ($calc_needed ? ". RECALC" : "") );
|
536 |
+
|
537 |
+
if ( $calc_needed ) {
|
538 |
+
WC()->cart->calculate_totals();
|
539 |
+
}
|
540 |
+
|
541 |
+
}
|
542 |
+
|
543 |
+
private function get_valid_auto_coupons( ) {
|
544 |
+
$valid_coupons = array();
|
545 |
+
|
546 |
+
//Array will only have values if option autocoupon_allow_remove == true
|
547 |
+
$removed_autocoupon_codes = $this->get_option_autocoupon_allow_remove() ? $this->get_removed_autocoupon_codes() : array();
|
548 |
+
|
549 |
+
foreach ( $this->get_all_auto_coupons() as $coupon_code => $coupon ) {
|
550 |
+
if ( isset( $removed_autocoupon_codes[ $coupon_code ] ) ) continue;
|
551 |
+
if ( ! $this->coupon_can_be_applied( $coupon ) ) continue;
|
552 |
+
if ( ! $this->coupon_has_a_value( $coupon ) ) continue;
|
553 |
+
|
554 |
+
$valid_coupons[] = $coupon;
|
555 |
+
}
|
556 |
+
return $valid_coupons;
|
557 |
+
}
|
558 |
+
|
559 |
+
/**
|
560 |
+
* Test whether the coupon is valid (to be auto-applied)
|
561 |
+
* @return bool
|
562 |
+
*/
|
563 |
+
private function coupon_can_be_applied( $coupon ) {
|
564 |
+
$wrap_coupon = WJECF_Wrap( $coupon );
|
565 |
+
$can_be_applied = true;
|
566 |
+
|
567 |
+
//Test validity
|
568 |
+
if ( ! $coupon->is_valid() ) {
|
569 |
+
$can_be_applied = false;
|
570 |
+
}
|
571 |
+
else if ( $can_be_applied && is_array( $wrap_coupon->get_email_restrictions() ) && sizeof( $wrap_coupon->get_email_restrictions() ) > 0 ) {
|
572 |
+
//Test restricted emails
|
573 |
+
//See WooCommerce: class-wc-cart.php function check_customer_coupons
|
574 |
+
$user_emails = array_map( 'sanitize_email', array_map( 'strtolower', WJECF()->get_user_emails() ) );
|
575 |
+
$coupon_emails = array_map( 'sanitize_email', array_map( 'strtolower', $wrap_coupon->get_email_restrictions() ) );
|
576 |
+
|
577 |
+
if ( 0 == sizeof( array_intersect( $user_emails, $coupon_emails ) ) ) {
|
578 |
+
$can_be_applied = false;
|
579 |
+
}
|
580 |
+
|
581 |
+
$this->log( sprintf( 'Coupon emails: [ %s ] User emails: [ %s ] Match: %s',
|
582 |
+
join( ', ', $coupon_emails ),
|
583 |
+
join( ', ', $user_emails ),
|
584 |
+
$can_be_applied ? 'yes' : 'no'
|
585 |
+
) );
|
586 |
+
}
|
587 |
+
return apply_filters( 'wjecf_coupon_can_be_applied', $can_be_applied, $coupon );
|
588 |
+
|
589 |
+
}
|
590 |
+
|
591 |
+
/**
|
592 |
+
* Does the coupon have a value? (autocoupon should not be applied if it has no value)
|
593 |
+
* @param WC_Coupon $coupon The coupon data
|
594 |
+
* @return bool True if it has a value (discount, free shipping, whatever) otherwise false)
|
595 |
+
**/
|
596 |
+
function coupon_has_a_value( $coupon ) {
|
597 |
+
|
598 |
+
$has_a_value = false;
|
599 |
+
|
600 |
+
if ( $coupon->is_type('free_gift') ) { // 'WooCommerce Free Gift Coupons'-plugin
|
601 |
+
$has_a_value = true;
|
602 |
+
}
|
603 |
+
elseif ( WJECF_Wrap( $coupon )->get_free_shipping() ) {
|
604 |
+
$has_a_value = true;
|
605 |
+
}
|
606 |
+
else {
|
607 |
+
//Test whether discount > 0
|
608 |
+
//See WooCommerce: class-wc-cart.php function get_discounted_price
|
609 |
+
global $woocommerce;
|
610 |
+
foreach ( $woocommerce->cart->get_cart() as $cart_item ) {
|
611 |
+
if ( $coupon->is_valid_for_cart() || $coupon->is_valid_for_product( $cart_item['data'], $cart_item ) ) {
|
612 |
+
$has_a_value = WJECF_Wrap( $coupon )->get_amount() > 0;
|
613 |
+
break;
|
614 |
+
}
|
615 |
+
}
|
616 |
+
}
|
617 |
+
|
618 |
+
return apply_filters( 'wjecf_coupon_has_a_value', $has_a_value, $coupon );
|
619 |
+
}
|
620 |
+
|
621 |
+
|
622 |
+
|
623 |
+
/**
|
624 |
+
* Check wether the coupon is an "Auto coupon".
|
625 |
+
* @param WC_Coupon $coupon The coupon data
|
626 |
+
* @return bool true if it is an "Auto coupon"
|
627 |
+
*/
|
628 |
+
public function is_auto_coupon( $coupon ) {
|
629 |
+
return WJECF_Wrap( $coupon )->get_meta( '_wjecf_is_auto_coupon' ) == 'yes';
|
630 |
+
}
|
631 |
+
|
632 |
+
private function get_coupon_priority($coupon) {
|
633 |
+
if ( WJECF()->is_pro() ) {
|
634 |
+
$prio = WJECF_Wrap( $coupon )->get_meta( '_wjecf_coupon_priority' );
|
635 |
+
if ( ! empty( $prio ) ) {
|
636 |
+
return intval( $prio );
|
637 |
+
}
|
638 |
+
}
|
639 |
+
return 0;
|
640 |
+
}
|
641 |
+
|
642 |
+
|
643 |
+
|
644 |
+
/**
|
645 |
+
* Return an array of WC_Coupons with coupons that shouldn't cause individual use conflicts
|
646 |
+
*/
|
647 |
+
private function individual_use_filter( $valid_auto_coupons ) {
|
648 |
+
$filtered = array();
|
649 |
+
|
650 |
+
//Any individual use non-autocoupons in the cart?
|
651 |
+
foreach ( WC()->cart->get_applied_coupons() as $coupon_code ) {
|
652 |
+
$coupon = new WC_Coupon( $coupon_code );
|
653 |
+
if ( WJECF_Wrap( $coupon )->get_individual_use() && ! $this->is_auto_coupon( $coupon ) ) {
|
654 |
+
return $filtered; //Don't allow any auto coupon
|
655 |
+
}
|
656 |
+
}
|
657 |
+
foreach ( $valid_auto_coupons as $coupon ) {
|
658 |
+
if ( ! WJECF_Wrap( $coupon )->get_individual_use() || empty( $filtered ) ) {
|
659 |
+
$filtered[] = $coupon;
|
660 |
+
if ( WJECF_Wrap( $coupon )->get_individual_use() ) {
|
661 |
+
break;
|
662 |
+
}
|
663 |
+
}
|
664 |
+
}
|
665 |
+
return $filtered;
|
666 |
+
}
|
667 |
+
|
668 |
+
/**
|
669 |
+
* Get an array of all auto coupons [ $coupon_code => $coupon ]
|
670 |
+
* @return array All auto coupon codes
|
671 |
+
*/
|
672 |
+
public function get_all_auto_coupons() {
|
673 |
+
if ( ! is_array( $this->_autocoupons ) ) {
|
674 |
+
$this->_autocoupons = array();
|
675 |
+
|
676 |
+
$query_args = array(
|
677 |
+
'posts_per_page' => -1,
|
678 |
+
'post_type' => 'shop_coupon',
|
679 |
+
'post_status' => 'publish',
|
680 |
+
'orderby' => array( 'title' => 'ASC' ),
|
681 |
+
'meta_query' => array(
|
682 |
+
array(
|
683 |
+
'key' => '_wjecf_is_auto_coupon',
|
684 |
+
'compare' => '=',
|
685 |
+
'value' => 'yes',
|
686 |
+
),
|
687 |
+
)
|
688 |
+
);
|
689 |
+
|
690 |
+
$query = new WP_Query($query_args);
|
691 |
+
foreach ($query->posts as $post) {
|
692 |
+
$coupon = new WC_Coupon($post->post_title);
|
693 |
+
if ( $this->is_auto_coupon($coupon) ) {
|
694 |
+
$this->_autocoupons[ WJECF_Wrap( $coupon )->get_code() ] = $coupon;
|
695 |
+
}
|
696 |
+
}
|
697 |
+
|
698 |
+
//Sort by priority
|
699 |
+
@uasort( $this->_autocoupons , array( $this, 'sort_auto_coupons' ) ); //Ignore error PHP Bug #50688
|
700 |
+
|
701 |
+
$coupon_codes = array();
|
702 |
+
foreach( $this->_autocoupons as $coupon ) {
|
703 |
+
$coupon_codes[] = WJECF_Wrap( $coupon )->get_code();
|
704 |
+
}
|
705 |
+
|
706 |
+
$this->log( 'debug', "Autocoupons: " . implode(", ", $coupon_codes ) );
|
707 |
+
}
|
708 |
+
|
709 |
+
return $this->_autocoupons;
|
710 |
+
}
|
711 |
+
|
712 |
+
/**
|
713 |
+
* Compare function to sort coupons by priority
|
714 |
+
* @param type $a
|
715 |
+
* @param type $b
|
716 |
+
* @return type
|
717 |
+
*/
|
718 |
+
private function sort_auto_coupons( $coupon_a, $coupon_b ) {
|
719 |
+
$prio_a = $this->get_coupon_priority( $coupon_a );
|
720 |
+
$prio_b = $this->get_coupon_priority( $coupon_b );
|
721 |
+
//$this->log( 'debug', "A: $prio_a B: $prio_b " );
|
722 |
+
if ( $prio_a == $prio_b ) {
|
723 |
+
return WJECF_Wrap( $coupon_a )->get_code() < WJECF_Wrap( $coupon_b )->get_code() ? -1 : 1; //By title ASC
|
724 |
+
} else {
|
725 |
+
return $prio_a > $prio_b ? -1 : 1; //By prio DESC
|
726 |
+
}
|
727 |
+
}
|
728 |
+
}
|
includes/WJECF_Bootstrap.php
CHANGED
@@ -1,130 +1,130 @@
|
|
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 |
-
$this->require_once_php( 'WJECF_Wrap' );
|
24 |
-
|
25 |
-
$this->add_plugin( 'WJECF_Debug' );
|
26 |
-
$this->require_once_php( 'admin/WJECF_Admin_Html' );
|
27 |
-
$this->add_plugin('admin/WJECF_Admin');
|
28 |
-
$this->try_add_plugin('admin/WJECF_Admin_Data_Update');
|
29 |
-
|
30 |
-
$this->try_add_plugin('admin/WJECF_Admin_Settings');
|
31 |
-
$this->try_add_plugin('WJECF_AutoCoupon');
|
32 |
-
$this->try_add_plugin('WJECF_WPML');
|
33 |
-
|
34 |
-
if ( $pro ) {
|
35 |
-
$this->try_include_php( 'pro/WJECF_Pro_API' );
|
36 |
-
$this->try_add_plugin('pro/admin/WJECF_Pro_Admin_Auto_Update');
|
37 |
-
|
38 |
-
$this->try_add_plugin('pro/WJECF_Pro_Free_Products/WJECF_Pro_Free_Products');
|
39 |
-
$this->try_add_plugin('pro/WJECF_Pro_Coupon_Queueing');
|
40 |
-
$this->try_add_plugin('pro/WJECF_Pro_Product_Filter');
|
41 |
-
$this->try_add_plugin('pro/WJECF_Pro_Limit_Discount_Quantities');
|
42 |
-
}
|
43 |
-
|
44 |
-
WJECF()->start();
|
45 |
-
|
46 |
-
//WP-cli for debugging
|
47 |
-
if ( defined( 'WP_CLI' ) && WP_CLI ) {
|
48 |
-
if ( $this->try_include_php( 'WJECF_Debug_CLI' ) ) {
|
49 |
-
WJECF_Debug_CLI::add_command();
|
50 |
-
}
|
51 |
-
}
|
52 |
-
|
53 |
-
}
|
54 |
-
|
55 |
-
/**
|
56 |
-
* Singleton Instance
|
57 |
-
*
|
58 |
-
* @static
|
59 |
-
* @return Singleton Instance
|
60 |
-
*/
|
61 |
-
public static function instance() {
|
62 |
-
if ( is_null( self::$_instance ) ) {
|
63 |
-
self::$_instance = new self();
|
64 |
-
}
|
65 |
-
return self::$_instance;
|
66 |
-
}
|
67 |
-
protected static $_instance = null;
|
68 |
-
|
69 |
-
|
70 |
-
/**
|
71 |
-
* require_once( $path + '.php' )
|
72 |
-
* @param string $path Path to the php file (excluding extension) relative to the current path
|
73 |
-
* @return bool True if succesful
|
74 |
-
*/
|
75 |
-
protected function require_once_php( $path ) {
|
76 |
-
$fullpath = $this->get_path( $path ) . '.php';
|
77 |
-
require_once( $fullpath );
|
78 |
-
}
|
79 |
-
|
80 |
-
/**
|
81 |
-
* tries to include_once( $path + '.php' )
|
82 |
-
* @param string $path Path to the php file (excluding extension) relative to the current path
|
83 |
-
* @return bool True if succesful
|
84 |
-
*/
|
85 |
-
protected function try_include_php( $path ) {
|
86 |
-
$fullpath = $this->get_path( $path ) . '.php';
|
87 |
-
|
88 |
-
if ( ! file_exists( $fullpath ) ) {
|
89 |
-
return false;
|
90 |
-
}
|
91 |
-
|
92 |
-
include_once( $fullpath );
|
93 |
-
return true;
|
94 |
-
}
|
95 |
-
|
96 |
-
/**
|
97 |
-
* Loads the class file and adds the plugin to WJECF(). Throws exception on failure.
|
98 |
-
* @param string $path Path to the php file (excluding extension) relative to the current path
|
99 |
-
* @return void
|
100 |
-
*/
|
101 |
-
protected function add_plugin( $path ) {
|
102 |
-
$class_name = basename( $path );
|
103 |
-
|
104 |
-
$this->require_once_php( $path );
|
105 |
-
|
106 |
-
if ( ! WJECF()->add_plugin( $class_name ) ) {
|
107 |
-
throw new Exception( sprintf( 'Unable to add plugin %s', $class_name ) );
|
108 |
-
}
|
109 |
-
}
|
110 |
-
|
111 |
-
/**
|
112 |
-
* Tries loading the class file and adding the plugin to WJECF().
|
113 |
-
* @param string $path Path to the php file (excluding extension) relative to the current path
|
114 |
-
* @return bool True if succesful
|
115 |
-
*/
|
116 |
-
protected function try_add_plugin( $path ) {
|
117 |
-
$class_name = basename( $path );
|
118 |
-
return $this->try_include_php( $path ) && WJECF()->add_plugin( $class_name );
|
119 |
-
}
|
120 |
-
|
121 |
-
/**
|
122 |
-
* Gets the path relative to the includes/ directory
|
123 |
-
* @param string $path
|
124 |
-
* @return string
|
125 |
-
*/
|
126 |
-
private function get_path( $path ) {
|
127 |
-
return plugin_dir_path( __FILE__ ) . $path;
|
128 |
-
}
|
129 |
-
|
130 |
}
|
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 |
+
$this->require_once_php( 'WJECF_Wrap' );
|
24 |
+
|
25 |
+
$this->add_plugin( 'WJECF_Debug' );
|
26 |
+
$this->require_once_php( 'admin/WJECF_Admin_Html' );
|
27 |
+
$this->add_plugin('admin/WJECF_Admin');
|
28 |
+
$this->try_add_plugin('admin/WJECF_Admin_Data_Update');
|
29 |
+
|
30 |
+
$this->try_add_plugin('admin/WJECF_Admin_Settings');
|
31 |
+
$this->try_add_plugin('WJECF_AutoCoupon');
|
32 |
+
$this->try_add_plugin('WJECF_WPML');
|
33 |
+
|
34 |
+
if ( $pro ) {
|
35 |
+
$this->try_include_php( 'pro/WJECF_Pro_API' );
|
36 |
+
$this->try_add_plugin('pro/admin/WJECF_Pro_Admin_Auto_Update');
|
37 |
+
|
38 |
+
$this->try_add_plugin('pro/WJECF_Pro_Free_Products/WJECF_Pro_Free_Products');
|
39 |
+
$this->try_add_plugin('pro/WJECF_Pro_Coupon_Queueing');
|
40 |
+
$this->try_add_plugin('pro/WJECF_Pro_Product_Filter');
|
41 |
+
$this->try_add_plugin('pro/WJECF_Pro_Limit_Discount_Quantities');
|
42 |
+
}
|
43 |
+
|
44 |
+
WJECF()->start();
|
45 |
+
|
46 |
+
//WP-cli for debugging
|
47 |
+
if ( defined( 'WP_CLI' ) && WP_CLI ) {
|
48 |
+
if ( $this->try_include_php( 'WJECF_Debug_CLI' ) ) {
|
49 |
+
WJECF_Debug_CLI::add_command();
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Singleton Instance
|
57 |
+
*
|
58 |
+
* @static
|
59 |
+
* @return Singleton Instance
|
60 |
+
*/
|
61 |
+
public static function instance() {
|
62 |
+
if ( is_null( self::$_instance ) ) {
|
63 |
+
self::$_instance = new self();
|
64 |
+
}
|
65 |
+
return self::$_instance;
|
66 |
+
}
|
67 |
+
protected static $_instance = null;
|
68 |
+
|
69 |
+
|
70 |
+
/**
|
71 |
+
* require_once( $path + '.php' )
|
72 |
+
* @param string $path Path to the php file (excluding extension) relative to the current path
|
73 |
+
* @return bool True if succesful
|
74 |
+
*/
|
75 |
+
protected function require_once_php( $path ) {
|
76 |
+
$fullpath = $this->get_path( $path ) . '.php';
|
77 |
+
require_once( $fullpath );
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* tries to include_once( $path + '.php' )
|
82 |
+
* @param string $path Path to the php file (excluding extension) relative to the current path
|
83 |
+
* @return bool True if succesful
|
84 |
+
*/
|
85 |
+
protected function try_include_php( $path ) {
|
86 |
+
$fullpath = $this->get_path( $path ) . '.php';
|
87 |
+
|
88 |
+
if ( ! file_exists( $fullpath ) ) {
|
89 |
+
return false;
|
90 |
+
}
|
91 |
+
|
92 |
+
include_once( $fullpath );
|
93 |
+
return true;
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Loads the class file and adds the plugin to WJECF(). Throws exception on failure.
|
98 |
+
* @param string $path Path to the php file (excluding extension) relative to the current path
|
99 |
+
* @return void
|
100 |
+
*/
|
101 |
+
protected function add_plugin( $path ) {
|
102 |
+
$class_name = basename( $path );
|
103 |
+
|
104 |
+
$this->require_once_php( $path );
|
105 |
+
|
106 |
+
if ( ! WJECF()->add_plugin( $class_name ) ) {
|
107 |
+
throw new Exception( sprintf( 'Unable to add plugin %s', $class_name ) );
|
108 |
+
}
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Tries loading the class file and adding the plugin to WJECF().
|
113 |
+
* @param string $path Path to the php file (excluding extension) relative to the current path
|
114 |
+
* @return bool True if succesful
|
115 |
+
*/
|
116 |
+
protected function try_add_plugin( $path ) {
|
117 |
+
$class_name = basename( $path );
|
118 |
+
return $this->try_include_php( $path ) && WJECF()->add_plugin( $class_name );
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Gets the path relative to the includes/ directory
|
123 |
+
* @param string $path
|
124 |
+
* @return string
|
125 |
+
*/
|
126 |
+
private function get_path( $path ) {
|
127 |
+
return plugin_dir_path( __FILE__ ) . $path;
|
128 |
+
}
|
129 |
+
|
130 |
}
|
includes/WJECF_Controller.php
CHANGED
@@ -1,970 +1,1001 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
defined('ABSPATH') or die();
|
4 |
-
|
5 |
-
/**
|
6 |
-
* The main controller for WooCommerce Extended Coupon Features
|
7 |
-
*/
|
8 |
-
class WJECF_Controller {
|
9 |
-
|
10 |
-
// Coupon message codes
|
11 |
-
//NOTE: I use prefix 79 for this plugin; there's no guarantee that other plugins don't use the same values!
|
12 |
-
const E_WC_COUPON_MIN_MATCHING_SUBTOTAL_NOT_MET = 79100;
|
13 |
-
const E_WC_COUPON_MAX_MATCHING_SUBTOTAL_NOT_MET = 79101;
|
14 |
-
const E_WC_COUPON_MIN_MATCHING_QUANTITY_NOT_MET = 79102;
|
15 |
-
const E_WC_COUPON_MAX_MATCHING_QUANTITY_NOT_MET = 79103;
|
16 |
-
const E_WC_COUPON_SHIPPING_METHOD_NOT_MET = 79104;
|
17 |
-
const E_WC_COUPON_PAYMENT_METHOD_NOT_MET = 79105;
|
18 |
-
const E_WC_COUPON_NOT_FOR_THIS_USER = 79106;
|
19 |
-
const E_WC_COUPON_FIRST_PURCHASE_ONLY = 79107;
|
20 |
-
|
21 |
-
private $options = null;
|
22 |
-
private $_user_emails = null;
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Singleton Instance
|
26 |
-
*
|
27 |
-
* @static
|
28 |
-
* @return Singleton Instance
|
29 |
-
*/
|
30 |
-
public static function instance() {
|
31 |
-
if ( is_null( self::$_instance ) ) {
|
32 |
-
self::$_instance = new self();
|
33 |
-
}
|
34 |
-
return self::$_instance;
|
35 |
-
}
|
36 |
-
protected static $_instance = null;
|
37 |
-
|
38 |
-
|
39 |
-
public function __construct() {
|
40 |
-
$this->options = new WJECF_Options(
|
41 |
-
'wjecf_options',
|
42 |
-
array(
|
43 |
-
'db_version' => 0, // integer
|
44 |
-
'debug_mode' => false, // true or false
|
45 |
-
'disabled_plugins' => array(), // e.g. [ 'WJECF_AutoCoupon' ]
|
46 |
-
'autocoupon_allow_remove' => false
|
47 |
-
)
|
48 |
-
);
|
49 |
-
}
|
50 |
-
|
51 |
-
public function start() {
|
52 |
-
add_action('init', array( $this, 'init_hook' ));
|
53 |
-
}
|
54 |
-
|
55 |
-
public function init_hook() {
|
56 |
-
if ( ! class_exists('WC_Coupon') ) {
|
57 |
-
add_action( 'admin_notices', array( $this, 'admin_notice_woocommerce_not_found' ) );
|
58 |
-
return;
|
59 |
-
}
|
60 |
-
|
61 |
-
$this->controller_init();
|
62 |
-
|
63 |
-
/**
|
64 |
-
* Fires before the WJECF plugins are initialised.
|
65 |
-
*
|
66 |
-
* Perfect hook for themes or plugins to load custom WJECF plugins.
|
67 |
-
*
|
68 |
-
* @since 2.3.7
|
69 |
-
**/
|
70 |
-
do_action( 'wjecf_init_plugins');
|
71 |
-
|
72 |
-
//Start the plugins
|
73 |
-
foreach ( WJECF()->get_plugins() as $name => $plugin ) {
|
74 |
-
if ( $plugin->plugin_is_enabled() ) {
|
75 |
-
|
76 |
-
foreach( $plugin->get_plugin_dependencies() as $dependency_name ) {
|
77 |
-
$dependency = $this->get_plugin( $dependency_name );
|
78 |
-
if ( ! $dependency || ! $dependency->plugin_is_enabled() ) {
|
79 |
-
$this->log( 'error', 'Unable to initialize ' . $name . ' because it requires ' . $dependency_name );
|
80 |
-
continue;
|
81 |
-
}
|
82 |
-
}
|
83 |
-
|
84 |
-
$plugin->init_hook();
|
85 |
-
if ( is_admin() ) {
|
86 |
-
$plugin->init_admin_hook();
|
87 |
-
}
|
88 |
-
}
|
89 |
-
}
|
90 |
-
}
|
91 |
-
|
92 |
-
public function controller_init() {
|
93 |
-
|
94 |
-
$this->log( 'debug', "INIT " . ( is_ajax() ? "AJAX" : is_admin() ? "ADMIN" : "FRONTEND" ) . " " . $_SERVER['REQUEST_URI'] );
|
95 |
-
|
96 |
-
//Frontend hooks
|
97 |
-
|
98 |
-
//assert_coupon_is_valid (which raises exception on invalid coupon) can only be used on WC 2.3.0 and up
|
99 |
-
if ( WJECF_WC()->check_woocommerce_version('2.3.0') ) {
|
100 |
-
add_filter('woocommerce_coupon_is_valid', array( $this, 'assert_coupon_is_valid' ), 10, 3 ); //Since WC3.2 WC_Discounts is passed as a 3rd argument
|
101 |
-
} else {
|
102 |
-
add_filter('woocommerce_coupon_is_valid', array( $this, 'coupon_is_valid' ), 10, 2 );
|
103 |
-
}
|
104 |
-
|
105 |
-
//Last check for coupons with restricted_emails (moved from WJECF_AutoCoupon since 2.5.6)
|
106 |
-
add_action( 'woocommerce_checkout_update_order_review', array( $this, 'fetch_billing_email' ), 10 ); // AJAX One page checkout
|
107 |
-
add_action( 'woocommerce_after_checkout_validation', array( $this, 'fetch_billing_email' ), 10 ); // Checkout posted
|
108 |
-
|
109 |
-
add_filter('woocommerce_coupon_error', array( $this, 'woocommerce_coupon_error' ), 10, 3 );
|
110 |
-
}
|
111 |
-
|
112 |
-
protected $plugins = array();
|
113 |
-
|
114 |
-
/**
|
115 |
-
* Load a WJECF Plugin (class name)
|
116 |
-
* @param string $class_name The class name of the plugin
|
117 |
-
* @return bool True if succeeded, otherwise false
|
118 |
-
*/
|
119 |
-
public function add_plugin( $class_name ) {
|
120 |
-
if ( isset( $this->plugins[ $class_name ] ) ) {
|
121 |
-
return false; //Already loaded
|
122 |
-
}
|
123 |
-
|
124 |
-
if ( ! class_exists( $class_name ) ) {
|
125 |
-
$this->log( 'warning', 'Unknown plugin: ' . $class_name );
|
126 |
-
return false; //Not found
|
127 |
-
}
|
128 |
-
|
129 |
-
$plugin = new $class_name();
|
130 |
-
foreach( $plugin->get_plugin_dependencies() as $dependency ) {
|
131 |
-
if ( ! class_exists( $dependency ) ) {
|
132 |
-
$this->log( 'warning', 'Unknown dependency: ' . $dependency . ' for plugin ' . $class_name );
|
133 |
-
return false;
|
134 |
-
}
|
135 |
-
|
136 |
-
if ( isset( $this->plugins[ $class_name ] ) ) {
|
137 |
-
continue; //dependency is al geladen
|
138 |
-
}
|
139 |
-
|
140 |
-
$this->add_plugin( $dependency );
|
141 |
-
}
|
142 |
-
|
143 |
-
//Assert dependencies
|
144 |
-
try {
|
145 |
-
$plugin->assert_dependencies();
|
146 |
-
} catch (Exception $ex) {
|
147 |
-
$msg = sprintf('Failed loading %s. %s', $class_name, $ex->getMessage() );
|
148 |
-
|
149 |
-
$this->log( 'error', $msg );
|
150 |
-
|
151 |
-
if ( $wjecf_admin = WJECF()->get_plugin('WJECF_Admin') ) {
|
152 |
-
$wjecf_admin->enqueue_notice( $msg, 'error' );
|
153 |
-
}
|
154 |
-
return false;
|
155 |
-
}
|
156 |
-
|
157 |
-
|
158 |
-
$this->plugins[ $class_name ] = $plugin;
|
159 |
-
$this->log( 'debug', 'Loaded plugin: ' . $class_name );
|
160 |
-
|
161 |
-
return true;
|
162 |
-
}
|
163 |
-
|
164 |
-
|
165 |
-
/**
|
166 |
-
* Description
|
167 |
-
* @param type $plugin
|
168 |
-
* @return bool true if succesful
|
169 |
-
*/
|
170 |
-
private function load_dependencies( $plugin ) {
|
171 |
-
|
172 |
-
return true;
|
173 |
-
}
|
174 |
-
|
175 |
-
public function get_plugins() {
|
176 |
-
return $this->plugins;
|
177 |
-
}
|
178 |
-
|
179 |
-
/**
|
180 |
-
* Retrieves the WJECF Plugin
|
181 |
-
* @param string $class_name
|
182 |
-
* @return object|bool The plugin if found, otherwise returns false
|
183 |
-
*/
|
184 |
-
public function get_plugin( $class_name ) {
|
185 |
-
if ( isset( $this->plugins[ $class_name ] ) ) {
|
186 |
-
return $this->plugins[ $class_name ];
|
187 |
-
} else {
|
188 |
-
return false;
|
189 |
-
}
|
190 |
-
}
|
191 |
-
|
192 |
-
/* OPTIONS */
|
193 |
-
|
194 |
-
public function get_options() {
|
195 |
-
return $this->options->get();
|
196 |
-
}
|
197 |
-
|
198 |
-
public function get_option( $key, $default = null ) {
|
199 |
-
return $this->options->get( $key, $default );
|
200 |
-
}
|
201 |
-
|
202 |
-
public function set_option( $key, $value ) {
|
203 |
-
$this->options->set( $key, $value );
|
204 |
-
}
|
205 |
-
|
206 |
-
public function save_options() {
|
207 |
-
if ( ! is_admin() ) {
|
208 |
-
$this->log( 'error', 'WJECF Options must only be saved from admin.' );
|
209 |
-
return;
|
210 |
-
}
|
211 |
-
$this->options->save();
|
212 |
-
}
|
213 |
-
|
214 |
-
public function sanitizer() {
|
215 |
-
return WJECF_Sanitizer::instance();
|
216 |
-
}
|
217 |
-
|
218 |
-
/**
|
219 |
-
* Same as WordPress add_action(), but prevents the callback to be recursively called
|
220 |
-
*
|
221 |
-
* @param string $tag
|
222 |
-
* @param callable $function_to_add
|
223 |
-
* @param int $priority
|
224 |
-
* @param int $accepted_args
|
225 |
-
*/
|
226 |
-
public function safe_add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
|
227 |
-
$_RECURSION_LIMIT = 5;
|
228 |
-
WJECF_Action_Or_Filter::action( $tag, $function_to_add, $priority, $accepted_args, $_RECURSION_LIMIT );
|
229 |
-
}
|
230 |
-
|
231 |
-
/* FRONTEND HOOKS */
|
232 |
-
|
233 |
-
/**
|
234 |
-
* Notifies that WooCommerce has not been detected.
|
235 |
-
* @return void
|
236 |
-
*/
|
237 |
-
public function admin_notice_woocommerce_not_found() {
|
238 |
-
$msg = __( 'WooCommerce Extended Coupon Features is disabled because WooCommerce could not be detected.', 'woocommerce-jos-autocoupon' );
|
239 |
-
echo '<div class="error"><p>' . $msg . '</p></div>';
|
240 |
-
}
|
241 |
-
|
242 |
-
/**
|
243 |
-
* Overwrite coupon error message, if $err_code is an error code of this plugin
|
244 |
-
* @param string $err Original error message
|
245 |
-
* @param int $err_code Error code
|
246 |
-
* @param WC_Coupon $coupon The coupon
|
247 |
-
* @return string Overwritten error message
|
248 |
-
*/
|
249 |
-
public function woocommerce_coupon_error( $err, $err_code, $coupon ) {
|
250 |
-
switch ( $err_code ) {
|
251 |
-
case self::E_WC_COUPON_MIN_MATCHING_SUBTOTAL_NOT_MET:
|
252 |
-
$min_price = wc_price( WJECF_Wrap( $coupon )->get_meta( '_wjecf_min_matching_product_subtotal' ) );
|
253 |
-
$err = sprintf( __( 'The minimum subtotal of the matching products for this coupon is %s.', 'woocommerce-jos-autocoupon' ), $min_price );
|
254 |
-
break;
|
255 |
-
case self::E_WC_COUPON_MAX_MATCHING_SUBTOTAL_NOT_MET:
|
256 |
-
$max_price = wc_price( WJECF_Wrap( $coupon )->get_meta( '_wjecf_max_matching_product_subtotal' ) );
|
257 |
-
$err = sprintf( __( 'The maximum subtotal of the matching products for this coupon is %s.', 'woocommerce-jos-autocoupon' ), $max_price );
|
258 |
-
break;
|
259 |
-
case self::E_WC_COUPON_MIN_MATCHING_QUANTITY_NOT_MET:
|
260 |
-
$min_matching_product_qty = intval( WJECF_Wrap( $coupon )->get_meta( '_wjecf_min_matching_product_qty' ) );
|
261 |
-
$err = sprintf( __( 'The minimum quantity of matching products for this coupon is %s.', 'woocommerce-jos-autocoupon' ), $min_matching_product_qty );
|
262 |
-
break;
|
263 |
-
case self::E_WC_COUPON_MAX_MATCHING_QUANTITY_NOT_MET:
|
264 |
-
$max_matching_product_qty = intval( WJECF_Wrap( $coupon )->get_meta( '_wjecf_min_matching_product_qty' ) );
|
265 |
-
$err = sprintf( __( 'The maximum quantity of matching products for this coupon is %s.', 'woocommerce-jos-autocoupon' ), $max_matching_product_qty );
|
266 |
-
break;
|
267 |
-
case self::E_WC_COUPON_SHIPPING_METHOD_NOT_MET:
|
268 |
-
$err = __( 'The coupon is not valid for the currently selected shipping method.', 'woocommerce-jos-autocoupon' );
|
269 |
-
break;
|
270 |
-
case self::E_WC_COUPON_PAYMENT_METHOD_NOT_MET:
|
271 |
-
$err = __( 'The coupon is not valid for the currently selected payment method.', 'woocommerce-jos-autocoupon' );
|
272 |
-
break;
|
273 |
-
case self::E_WC_COUPON_NOT_FOR_THIS_USER:
|
274 |
-
$err = sprintf( __( 'Sorry, it seems the coupon "%s" is not yours.', 'woocommerce-jos-autocoupon' ), WJECF_Wrap( $coupon )->get_code() );
|
275 |
-
break;
|
276 |
-
case self::E_WC_COUPON_FIRST_PURCHASE_ONLY:
|
277 |
-
$err = sprintf( __( 'Sorry, coupon "%s" is only valid on your first purchase.', 'woocommerce-jos-autocoupon' ), WJECF_Wrap( $coupon )->get_code() );
|
278 |
-
break;
|
279 |
-
default:
|
280 |
-
//Do nothing
|
281 |
-
break;
|
282 |
-
}
|
283 |
-
return $err;
|
284 |
-
}
|
285 |
-
|
286 |
-
/**
|
287 |
-
* Extra validation rules for coupons.
|
288 |
-
* @param bool $valid
|
289 |
-
* @param WC_Coupon $coupon
|
290 |
-
* @param WC_Discounts $discounts
|
291 |
-
* @return bool True if valid; False if not valid.
|
292 |
-
*/
|
293 |
-
public function coupon_is_valid( $valid, $coupon, $wc_discounts = null ) {
|
294 |
-
try {
|
295 |
-
return $this->assert_coupon_is_valid( $valid, $coupon, $wc_discounts );
|
296 |
-
} catch ( Exception $e ) {
|
297 |
-
return false;
|
298 |
-
}
|
299 |
-
}
|
300 |
-
|
301 |
-
/**
|
302 |
-
* Extra validation rules for coupons. Throw an exception when not valid.
|
303 |
-
* @param bool $valid
|
304 |
-
* @param WC_Coupon $coupon
|
305 |
-
* @param WC_Discounts $discounts
|
306 |
-
* @return bool True if valid; False if already invalid on function call. In any other case an Exception will be thrown.
|
307 |
-
*/
|
308 |
-
public function assert_coupon_is_valid( $valid, $coupon, $wc_discounts = null ) {
|
309 |
-
|
310 |
-
//Not valid? Then it will never validate, so get out of here
|
311 |
-
if ( ! $valid ) {
|
312 |
-
return false;
|
313 |
-
}
|
314 |
-
|
315 |
-
$wrap_coupon = WJECF_Wrap( $coupon );
|
316 |
-
$items = WJECF_WC()->get_discount_items( $wc_discounts );
|
317 |
-
|
318 |
-
//$this->log( 'debug', 'Asserting validity of coupon: ' . $wrap_coupon->get_code() );
|
319 |
-
|
320 |
-
//============================
|
321 |
-
//Test if ALL products are in the cart (if AND-operator selected instead of the default OR)
|
322 |
-
$products_and = $wrap_coupon->get_meta( '_wjecf_products_and' ) == 'yes';
|
323 |
-
if ( $products_and && sizeof( $wrap_coupon->get_product_ids() ) > 1 ) { // We use > 1, because if size == 1, 'AND' makes no difference
|
324 |
-
//Get array of all cart product and variation ids
|
325 |
-
$item_ids = array();
|
326 |
-
|
327 |
-
foreach( $items as $item_key => $item ) {
|
328 |
-
if ( $item->product === false ) continue;
|
329 |
-
$wrap_product = WJECF_Wrap( $item->product );
|
330 |
-
|
331 |
-
$item_ids[] = $wrap_product->get_id();
|
332 |
-
if ( $item->product->is_type( 'variation' ) ) $item_ids[] = $wrap_product->get_variable_product_id();
|
333 |
-
}
|
334 |
-
//Filter used by WJECF_WPML hook
|
335 |
-
$item_ids = apply_filters( 'wjecf_get_product_ids', array_unique( $item_ids ) );
|
336 |
-
|
337 |
-
//check if every single product is in the cart
|
338 |
-
foreach( apply_filters( 'wjecf_get_product_ids', $wrap_coupon->get_product_ids() ) as $product_id ) {
|
339 |
-
if ( ! in_array( $product_id, $item_ids ) ) {
|
340 |
-
throw new Exception( WC_Coupon::E_WC_COUPON_NOT_APPLICABLE );
|
341 |
-
}
|
342 |
-
}
|
343 |
-
}
|
344 |
-
|
345 |
-
//============================
|
346 |
-
//Test if products form ALL categories are in the cart (if AND-operator selected instead of the default OR)
|
347 |
-
$categories_and = $wrap_coupon->get_meta( '_wjecf_categories_and' ) == 'yes';
|
348 |
-
if ( $categories_and && sizeof( $wrap_coupon->get_product_categories() ) > 1 ) { // We use > 1, because if size == 1, 'AND' makes no difference
|
349 |
-
//Get array of all cart product and variation ids
|
350 |
-
$product_cats = array();
|
351 |
-
|
352 |
-
foreach( $items as $item_key => $item ) {
|
353 |
-
if ( $item->product === false ) continue;
|
354 |
-
|
355 |
-
$product_id = WJECF_Wrap( $item->product )->get_id();
|
356 |
-
if ('product_variation' == get_post_type( $product_id )) $product_id = WJECF_Wrap( $item->product )->get_variable_product_id();
|
357 |
-
$product_cats = array_merge( $product_cats, wp_get_post_terms( $product_id, 'product_cat', array( "fields" => "ids" ) ) );
|
358 |
-
}
|
359 |
-
//Filter used by WJECF_WPML hook
|
360 |
-
$product_cats = apply_filters( 'wjecf_get_product_cat_ids', $product_cats );
|
361 |
-
//check if every single category is in the cart
|
362 |
-
foreach( apply_filters( 'wjecf_get_product_cat_ids', $wrap_coupon->get_product_categories() ) as $cat_id ) {
|
363 |
-
if ( ! in_array( $cat_id, $product_cats ) ) {
|
364 |
-
$this->log( 'debug', $cat_id . " is not in " . implode( ',', $product_cats ));
|
365 |
-
throw new Exception( WC_Coupon::E_WC_COUPON_NOT_APPLICABLE );
|
366 |
-
}
|
367 |
-
}
|
368 |
-
}
|
369 |
-
|
370 |
-
//============================
|
371 |
-
//Test min/max quantity of matching products
|
372 |
-
//
|
373 |
-
//For all items in the cart:
|
374 |
-
// If coupon contains both a product AND category inclusion filter: the item is counted if it matches either one of them
|
375 |
-
// If coupon contains either a product OR category exclusion filter: the item will NOT be counted if it matches either one of them
|
376 |
-
// If sale items are excluded by the coupon: the item will NOT be counted if it is a sale item
|
377 |
-
// If no filter exist, all items will be counted
|
378 |
-
|
379 |
-
$
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
$
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
if ( $
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
$
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
if ( $
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
$
|
416 |
-
|
417 |
-
|
418 |
-
$chosen_shipping = $chosen_shipping
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
$
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
$
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
$
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
$
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
$
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
*
|
621 |
-
* @
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
$
|
656 |
-
$
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
// ===========================================================================
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
* @
|
722 |
-
*
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
$this
|
735 |
-
|
736 |
-
}
|
737 |
-
|
738 |
-
private $
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
*
|
755 |
-
*
|
756 |
-
*
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
768 |
-
|
769 |
-
|
770 |
-
|
771 |
-
|
772 |
-
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
|
804 |
-
|
805 |
-
|
806 |
-
|
807 |
-
|
808 |
-
|
809 |
-
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
|
818 |
-
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
-
|
823 |
-
|
824 |
-
|
825 |
-
|
826 |
-
|
827 |
-
|
828 |
-
|
829 |
-
|
830 |
-
|
831 |
-
|
832 |
-
|
833 |
-
|
834 |
-
|
835 |
-
|
836 |
-
|
837 |
-
|
838 |
-
|
839 |
-
|
840 |
-
|
841 |
-
|
842 |
-
|
843 |
-
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
-
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
|
856 |
-
|
857 |
-
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
-
|
862 |
-
|
863 |
-
|
864 |
-
|
865 |
-
|
866 |
-
|
867 |
-
|
868 |
-
|
869 |
-
|
870 |
-
|
871 |
-
|
872 |
-
|
873 |
-
|
874 |
-
|
875 |
-
|
876 |
-
|
877 |
-
|
878 |
-
public function
|
879 |
-
|
880 |
-
|
881 |
-
|
882 |
-
|
883 |
-
//
|
884 |
-
//
|
885 |
-
|
886 |
-
|
887 |
-
/**
|
888 |
-
*
|
889 |
-
*
|
890 |
-
|
891 |
-
|
892 |
-
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
public function
|
897 |
-
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
|
903 |
-
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
}
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
*
|
922 |
-
*
|
923 |
-
* @param
|
924 |
-
* @param
|
925 |
-
* @param int $
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
$this->
|
933 |
-
|
934 |
-
|
935 |
-
}
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
945 |
-
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
|
955 |
-
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
-
|
962 |
-
|
963 |
-
|
964 |
-
|
965 |
-
|
966 |
-
|
967 |
-
|
968 |
-
|
969 |
-
|
970 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
defined('ABSPATH') or die();
|
4 |
+
|
5 |
+
/**
|
6 |
+
* The main controller for WooCommerce Extended Coupon Features
|
7 |
+
*/
|
8 |
+
class WJECF_Controller {
|
9 |
+
|
10 |
+
// Coupon message codes
|
11 |
+
//NOTE: I use prefix 79 for this plugin; there's no guarantee that other plugins don't use the same values!
|
12 |
+
const E_WC_COUPON_MIN_MATCHING_SUBTOTAL_NOT_MET = 79100;
|
13 |
+
const E_WC_COUPON_MAX_MATCHING_SUBTOTAL_NOT_MET = 79101;
|
14 |
+
const E_WC_COUPON_MIN_MATCHING_QUANTITY_NOT_MET = 79102;
|
15 |
+
const E_WC_COUPON_MAX_MATCHING_QUANTITY_NOT_MET = 79103;
|
16 |
+
const E_WC_COUPON_SHIPPING_METHOD_NOT_MET = 79104;
|
17 |
+
const E_WC_COUPON_PAYMENT_METHOD_NOT_MET = 79105;
|
18 |
+
const E_WC_COUPON_NOT_FOR_THIS_USER = 79106;
|
19 |
+
const E_WC_COUPON_FIRST_PURCHASE_ONLY = 79107;
|
20 |
+
|
21 |
+
private $options = null;
|
22 |
+
private $_user_emails = null;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Singleton Instance
|
26 |
+
*
|
27 |
+
* @static
|
28 |
+
* @return Singleton Instance
|
29 |
+
*/
|
30 |
+
public static function instance() {
|
31 |
+
if ( is_null( self::$_instance ) ) {
|
32 |
+
self::$_instance = new self();
|
33 |
+
}
|
34 |
+
return self::$_instance;
|
35 |
+
}
|
36 |
+
protected static $_instance = null;
|
37 |
+
|
38 |
+
|
39 |
+
public function __construct() {
|
40 |
+
$this->options = new WJECF_Options(
|
41 |
+
'wjecf_options',
|
42 |
+
array(
|
43 |
+
'db_version' => 0, // integer
|
44 |
+
'debug_mode' => false, // true or false
|
45 |
+
'disabled_plugins' => array(), // e.g. [ 'WJECF_AutoCoupon' ]
|
46 |
+
'autocoupon_allow_remove' => false
|
47 |
+
)
|
48 |
+
);
|
49 |
+
}
|
50 |
+
|
51 |
+
public function start() {
|
52 |
+
add_action('init', array( $this, 'init_hook' ));
|
53 |
+
}
|
54 |
+
|
55 |
+
public function init_hook() {
|
56 |
+
if ( ! class_exists('WC_Coupon') ) {
|
57 |
+
add_action( 'admin_notices', array( $this, 'admin_notice_woocommerce_not_found' ) );
|
58 |
+
return;
|
59 |
+
}
|
60 |
+
|
61 |
+
$this->controller_init();
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Fires before the WJECF plugins are initialised.
|
65 |
+
*
|
66 |
+
* Perfect hook for themes or plugins to load custom WJECF plugins.
|
67 |
+
*
|
68 |
+
* @since 2.3.7
|
69 |
+
**/
|
70 |
+
do_action( 'wjecf_init_plugins');
|
71 |
+
|
72 |
+
//Start the plugins
|
73 |
+
foreach ( WJECF()->get_plugins() as $name => $plugin ) {
|
74 |
+
if ( $plugin->plugin_is_enabled() ) {
|
75 |
+
|
76 |
+
foreach( $plugin->get_plugin_dependencies() as $dependency_name ) {
|
77 |
+
$dependency = $this->get_plugin( $dependency_name );
|
78 |
+
if ( ! $dependency || ! $dependency->plugin_is_enabled() ) {
|
79 |
+
$this->log( 'error', 'Unable to initialize ' . $name . ' because it requires ' . $dependency_name );
|
80 |
+
continue;
|
81 |
+
}
|
82 |
+
}
|
83 |
+
|
84 |
+
$plugin->init_hook();
|
85 |
+
if ( is_admin() ) {
|
86 |
+
$plugin->init_admin_hook();
|
87 |
+
}
|
88 |
+
}
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
public function controller_init() {
|
93 |
+
|
94 |
+
$this->log( 'debug', "INIT " . ( is_ajax() ? "AJAX" : is_admin() ? "ADMIN" : "FRONTEND" ) . " " . $_SERVER['REQUEST_URI'] );
|
95 |
+
|
96 |
+
//Frontend hooks
|
97 |
+
|
98 |
+
//assert_coupon_is_valid (which raises exception on invalid coupon) can only be used on WC 2.3.0 and up
|
99 |
+
if ( WJECF_WC()->check_woocommerce_version('2.3.0') ) {
|
100 |
+
add_filter('woocommerce_coupon_is_valid', array( $this, 'assert_coupon_is_valid' ), 10, 3 ); //Since WC3.2 WC_Discounts is passed as a 3rd argument
|
101 |
+
} else {
|
102 |
+
add_filter('woocommerce_coupon_is_valid', array( $this, 'coupon_is_valid' ), 10, 2 );
|
103 |
+
}
|
104 |
+
|
105 |
+
//Last check for coupons with restricted_emails (moved from WJECF_AutoCoupon since 2.5.6)
|
106 |
+
add_action( 'woocommerce_checkout_update_order_review', array( $this, 'fetch_billing_email' ), 10 ); // AJAX One page checkout
|
107 |
+
add_action( 'woocommerce_after_checkout_validation', array( $this, 'fetch_billing_email' ), 10 ); // Checkout posted
|
108 |
+
|
109 |
+
add_filter('woocommerce_coupon_error', array( $this, 'woocommerce_coupon_error' ), 10, 3 );
|
110 |
+
}
|
111 |
+
|
112 |
+
protected $plugins = array();
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Load a WJECF Plugin (class name)
|
116 |
+
* @param string $class_name The class name of the plugin
|
117 |
+
* @return bool True if succeeded, otherwise false
|
118 |
+
*/
|
119 |
+
public function add_plugin( $class_name ) {
|
120 |
+
if ( isset( $this->plugins[ $class_name ] ) ) {
|
121 |
+
return false; //Already loaded
|
122 |
+
}
|
123 |
+
|
124 |
+
if ( ! class_exists( $class_name ) ) {
|
125 |
+
$this->log( 'warning', 'Unknown plugin: ' . $class_name );
|
126 |
+
return false; //Not found
|
127 |
+
}
|
128 |
+
|
129 |
+
$plugin = new $class_name();
|
130 |
+
foreach( $plugin->get_plugin_dependencies() as $dependency ) {
|
131 |
+
if ( ! class_exists( $dependency ) ) {
|
132 |
+
$this->log( 'warning', 'Unknown dependency: ' . $dependency . ' for plugin ' . $class_name );
|
133 |
+
return false;
|
134 |
+
}
|
135 |
+
|
136 |
+
if ( isset( $this->plugins[ $class_name ] ) ) {
|
137 |
+
continue; //dependency is al geladen
|
138 |
+
}
|
139 |
+
|
140 |
+
$this->add_plugin( $dependency );
|
141 |
+
}
|
142 |
+
|
143 |
+
//Assert dependencies
|
144 |
+
try {
|
145 |
+
$plugin->assert_dependencies();
|
146 |
+
} catch (Exception $ex) {
|
147 |
+
$msg = sprintf('Failed loading %s. %s', $class_name, $ex->getMessage() );
|
148 |
+
|
149 |
+
$this->log( 'error', $msg );
|
150 |
+
|
151 |
+
if ( $wjecf_admin = WJECF()->get_plugin('WJECF_Admin') ) {
|
152 |
+
$wjecf_admin->enqueue_notice( $msg, 'error' );
|
153 |
+
}
|
154 |
+
return false;
|
155 |
+
}
|
156 |
+
|
157 |
+
|
158 |
+
$this->plugins[ $class_name ] = $plugin;
|
159 |
+
$this->log( 'debug', 'Loaded plugin: ' . $class_name );
|
160 |
+
|
161 |
+
return true;
|
162 |
+
}
|
163 |
+
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Description
|
167 |
+
* @param type $plugin
|
168 |
+
* @return bool true if succesful
|
169 |
+
*/
|
170 |
+
private function load_dependencies( $plugin ) {
|
171 |
+
|
172 |
+
return true;
|
173 |
+
}
|
174 |
+
|
175 |
+
public function get_plugins() {
|
176 |
+
return $this->plugins;
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Retrieves the WJECF Plugin
|
181 |
+
* @param string $class_name
|
182 |
+
* @return object|bool The plugin if found, otherwise returns false
|
183 |
+
*/
|
184 |
+
public function get_plugin( $class_name ) {
|
185 |
+
if ( isset( $this->plugins[ $class_name ] ) ) {
|
186 |
+
return $this->plugins[ $class_name ];
|
187 |
+
} else {
|
188 |
+
return false;
|
189 |
+
}
|
190 |
+
}
|
191 |
+
|
192 |
+
/* OPTIONS */
|
193 |
+
|
194 |
+
public function get_options() {
|
195 |
+
return $this->options->get();
|
196 |
+
}
|
197 |
+
|
198 |
+
public function get_option( $key, $default = null ) {
|
199 |
+
return $this->options->get( $key, $default );
|
200 |
+
}
|
201 |
+
|
202 |
+
public function set_option( $key, $value ) {
|
203 |
+
$this->options->set( $key, $value );
|
204 |
+
}
|
205 |
+
|
206 |
+
public function save_options() {
|
207 |
+
if ( ! is_admin() ) {
|
208 |
+
$this->log( 'error', 'WJECF Options must only be saved from admin.' );
|
209 |
+
return;
|
210 |
+
}
|
211 |
+
$this->options->save();
|
212 |
+
}
|
213 |
+
|
214 |
+
public function sanitizer() {
|
215 |
+
return WJECF_Sanitizer::instance();
|
216 |
+
}
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Same as WordPress add_action(), but prevents the callback to be recursively called
|
220 |
+
*
|
221 |
+
* @param string $tag
|
222 |
+
* @param callable $function_to_add
|
223 |
+
* @param int $priority
|
224 |
+
* @param int $accepted_args
|
225 |
+
*/
|
226 |
+
public function safe_add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
|
227 |
+
$_RECURSION_LIMIT = 5;
|
228 |
+
WJECF_Action_Or_Filter::action( $tag, $function_to_add, $priority, $accepted_args, $_RECURSION_LIMIT );
|
229 |
+
}
|
230 |
+
|
231 |
+
/* FRONTEND HOOKS */
|
232 |
+
|
233 |
+
/**
|
234 |
+
* Notifies that WooCommerce has not been detected.
|
235 |
+
* @return void
|
236 |
+
*/
|
237 |
+
public function admin_notice_woocommerce_not_found() {
|
238 |
+
$msg = __( 'WooCommerce Extended Coupon Features is disabled because WooCommerce could not be detected.', 'woocommerce-jos-autocoupon' );
|
239 |
+
echo '<div class="error"><p>' . $msg . '</p></div>';
|
240 |
+
}
|
241 |
+
|
242 |
+
/**
|
243 |
+
* Overwrite coupon error message, if $err_code is an error code of this plugin
|
244 |
+
* @param string $err Original error message
|
245 |
+
* @param int $err_code Error code
|
246 |
+
* @param WC_Coupon $coupon The coupon
|
247 |
+
* @return string Overwritten error message
|
248 |
+
*/
|
249 |
+
public function woocommerce_coupon_error( $err, $err_code, $coupon ) {
|
250 |
+
switch ( $err_code ) {
|
251 |
+
case self::E_WC_COUPON_MIN_MATCHING_SUBTOTAL_NOT_MET:
|
252 |
+
$min_price = wc_price( WJECF_Wrap( $coupon )->get_meta( '_wjecf_min_matching_product_subtotal' ) );
|
253 |
+
$err = sprintf( __( 'The minimum subtotal of the matching products for this coupon is %s.', 'woocommerce-jos-autocoupon' ), $min_price );
|
254 |
+
break;
|
255 |
+
case self::E_WC_COUPON_MAX_MATCHING_SUBTOTAL_NOT_MET:
|
256 |
+
$max_price = wc_price( WJECF_Wrap( $coupon )->get_meta( '_wjecf_max_matching_product_subtotal' ) );
|
257 |
+
$err = sprintf( __( 'The maximum subtotal of the matching products for this coupon is %s.', 'woocommerce-jos-autocoupon' ), $max_price );
|
258 |
+
break;
|
259 |
+
case self::E_WC_COUPON_MIN_MATCHING_QUANTITY_NOT_MET:
|
260 |
+
$min_matching_product_qty = intval( WJECF_Wrap( $coupon )->get_meta( '_wjecf_min_matching_product_qty' ) );
|
261 |
+
$err = sprintf( __( 'The minimum quantity of matching products for this coupon is %s.', 'woocommerce-jos-autocoupon' ), $min_matching_product_qty );
|
262 |
+
break;
|
263 |
+
case self::E_WC_COUPON_MAX_MATCHING_QUANTITY_NOT_MET:
|
264 |
+
$max_matching_product_qty = intval( WJECF_Wrap( $coupon )->get_meta( '_wjecf_min_matching_product_qty' ) );
|
265 |
+
$err = sprintf( __( 'The maximum quantity of matching products for this coupon is %s.', 'woocommerce-jos-autocoupon' ), $max_matching_product_qty );
|
266 |
+
break;
|
267 |
+
case self::E_WC_COUPON_SHIPPING_METHOD_NOT_MET:
|
268 |
+
$err = __( 'The coupon is not valid for the currently selected shipping method.', 'woocommerce-jos-autocoupon' );
|
269 |
+
break;
|
270 |
+
case self::E_WC_COUPON_PAYMENT_METHOD_NOT_MET:
|
271 |
+
$err = __( 'The coupon is not valid for the currently selected payment method.', 'woocommerce-jos-autocoupon' );
|
272 |
+
break;
|
273 |
+
case self::E_WC_COUPON_NOT_FOR_THIS_USER:
|
274 |
+
$err = sprintf( __( 'Sorry, it seems the coupon "%s" is not yours.', 'woocommerce-jos-autocoupon' ), WJECF_Wrap( $coupon )->get_code() );
|
275 |
+
break;
|
276 |
+
case self::E_WC_COUPON_FIRST_PURCHASE_ONLY:
|
277 |
+
$err = sprintf( __( 'Sorry, coupon "%s" is only valid on your first purchase.', 'woocommerce-jos-autocoupon' ), WJECF_Wrap( $coupon )->get_code() );
|
278 |
+
break;
|
279 |
+
default:
|
280 |
+
//Do nothing
|
281 |
+
break;
|
282 |
+
}
|
283 |
+
return $err;
|
284 |
+
}
|
285 |
+
|
286 |
+
/**
|
287 |
+
* Extra validation rules for coupons.
|
288 |
+
* @param bool $valid
|
289 |
+
* @param WC_Coupon $coupon
|
290 |
+
* @param WC_Discounts $discounts
|
291 |
+
* @return bool True if valid; False if not valid.
|
292 |
+
*/
|
293 |
+
public function coupon_is_valid( $valid, $coupon, $wc_discounts = null ) {
|
294 |
+
try {
|
295 |
+
return $this->assert_coupon_is_valid( $valid, $coupon, $wc_discounts );
|
296 |
+
} catch ( Exception $e ) {
|
297 |
+
return false;
|
298 |
+
}
|
299 |
+
}
|
300 |
+
|
301 |
+
/**
|
302 |
+
* Extra validation rules for coupons. Throw an exception when not valid.
|
303 |
+
* @param bool $valid
|
304 |
+
* @param WC_Coupon $coupon
|
305 |
+
* @param WC_Discounts $discounts
|
306 |
+
* @return bool True if valid; False if already invalid on function call. In any other case an Exception will be thrown.
|
307 |
+
*/
|
308 |
+
public function assert_coupon_is_valid( $valid, $coupon, $wc_discounts = null ) {
|
309 |
+
|
310 |
+
//Not valid? Then it will never validate, so get out of here
|
311 |
+
if ( ! $valid ) {
|
312 |
+
return false;
|
313 |
+
}
|
314 |
+
|
315 |
+
$wrap_coupon = WJECF_Wrap( $coupon );
|
316 |
+
$items = WJECF_WC()->get_discount_items( $wc_discounts );
|
317 |
+
|
318 |
+
//$this->log( 'debug', 'Asserting validity of coupon: ' . $wrap_coupon->get_code() );
|
319 |
+
|
320 |
+
//============================
|
321 |
+
//Test if ALL products are in the cart (if AND-operator selected instead of the default OR)
|
322 |
+
$products_and = $wrap_coupon->get_meta( '_wjecf_products_and' ) == 'yes';
|
323 |
+
if ( $products_and && sizeof( $wrap_coupon->get_product_ids() ) > 1 ) { // We use > 1, because if size == 1, 'AND' makes no difference
|
324 |
+
//Get array of all cart product and variation ids
|
325 |
+
$item_ids = array();
|
326 |
+
|
327 |
+
foreach( $items as $item_key => $item ) {
|
328 |
+
if ( $item->product === false ) continue;
|
329 |
+
$wrap_product = WJECF_Wrap( $item->product );
|
330 |
+
|
331 |
+
$item_ids[] = $wrap_product->get_id();
|
332 |
+
if ( $item->product->is_type( 'variation' ) ) $item_ids[] = $wrap_product->get_variable_product_id();
|
333 |
+
}
|
334 |
+
//Filter used by WJECF_WPML hook
|
335 |
+
$item_ids = apply_filters( 'wjecf_get_product_ids', array_unique( $item_ids ) );
|
336 |
+
|
337 |
+
//check if every single product is in the cart
|
338 |
+
foreach( apply_filters( 'wjecf_get_product_ids', $wrap_coupon->get_product_ids() ) as $product_id ) {
|
339 |
+
if ( ! in_array( $product_id, $item_ids ) ) {
|
340 |
+
throw new Exception( WC_Coupon::E_WC_COUPON_NOT_APPLICABLE );
|
341 |
+
}
|
342 |
+
}
|
343 |
+
}
|
344 |
+
|
345 |
+
//============================
|
346 |
+
//Test if products form ALL categories are in the cart (if AND-operator selected instead of the default OR)
|
347 |
+
$categories_and = $wrap_coupon->get_meta( '_wjecf_categories_and' ) == 'yes';
|
348 |
+
if ( $categories_and && sizeof( $wrap_coupon->get_product_categories() ) > 1 ) { // We use > 1, because if size == 1, 'AND' makes no difference
|
349 |
+
//Get array of all cart product and variation ids
|
350 |
+
$product_cats = array();
|
351 |
+
|
352 |
+
foreach( $items as $item_key => $item ) {
|
353 |
+
if ( $item->product === false ) continue;
|
354 |
+
|
355 |
+
$product_id = WJECF_Wrap( $item->product )->get_id();
|
356 |
+
if ('product_variation' == get_post_type( $product_id )) $product_id = WJECF_Wrap( $item->product )->get_variable_product_id();
|
357 |
+
$product_cats = array_merge( $product_cats, wp_get_post_terms( $product_id, 'product_cat', array( "fields" => "ids" ) ) );
|
358 |
+
}
|
359 |
+
//Filter used by WJECF_WPML hook
|
360 |
+
$product_cats = apply_filters( 'wjecf_get_product_cat_ids', $product_cats );
|
361 |
+
//check if every single category is in the cart
|
362 |
+
foreach( apply_filters( 'wjecf_get_product_cat_ids', $wrap_coupon->get_product_categories() ) as $cat_id ) {
|
363 |
+
if ( ! in_array( $cat_id, $product_cats ) ) {
|
364 |
+
$this->log( 'debug', $cat_id . " is not in " . implode( ',', $product_cats ));
|
365 |
+
throw new Exception( WC_Coupon::E_WC_COUPON_NOT_APPLICABLE );
|
366 |
+
}
|
367 |
+
}
|
368 |
+
}
|
369 |
+
|
370 |
+
//============================
|
371 |
+
//Test min/max quantity of matching products
|
372 |
+
//
|
373 |
+
//For all items in the cart:
|
374 |
+
// If coupon contains both a product AND category inclusion filter: the item is counted if it matches either one of them
|
375 |
+
// If coupon contains either a product OR category exclusion filter: the item will NOT be counted if it matches either one of them
|
376 |
+
// If sale items are excluded by the coupon: the item will NOT be counted if it is a sale item
|
377 |
+
// If no filter exist, all items will be counted
|
378 |
+
|
379 |
+
unset( $this->coupon_multiplier_values[ $wrap_coupon->get_code() ] );
|
380 |
+
$multiplier = null; //null = not initialized
|
381 |
+
|
382 |
+
//Validate quantity
|
383 |
+
$min_matching_product_qty = intval( $wrap_coupon->get_meta( '_wjecf_min_matching_product_qty' ) );
|
384 |
+
$max_matching_product_qty = intval( $wrap_coupon->get_meta( '_wjecf_max_matching_product_qty' ) );
|
385 |
+
if ( $min_matching_product_qty > 0 || $max_matching_product_qty > 0 ) {
|
386 |
+
//Count the products
|
387 |
+
$qty = $this->get_quantity_of_matching_products( $coupon, $wc_discounts );
|
388 |
+
//$this->log( 'debug', 'Quantity of matching products: ' . $qty );
|
389 |
+
if ( $min_matching_product_qty > 0 && $qty < $min_matching_product_qty ) throw new Exception( self::E_WC_COUPON_MIN_MATCHING_QUANTITY_NOT_MET );
|
390 |
+
if ( $max_matching_product_qty > 0 && $qty > $max_matching_product_qty ) throw new Exception( self::E_WC_COUPON_MAX_MATCHING_QUANTITY_NOT_MET );
|
391 |
+
|
392 |
+
if ( $min_matching_product_qty > 0 ) {
|
393 |
+
$multiplier = self::min_value( floor( $qty / $min_matching_product_qty ), $multiplier );
|
394 |
+
}
|
395 |
+
}
|
396 |
+
|
397 |
+
//Validate subtotal (2.2.2)
|
398 |
+
$min_matching_product_subtotal = floatval( $wrap_coupon->get_meta( '_wjecf_min_matching_product_subtotal' ) );
|
399 |
+
$max_matching_product_subtotal = floatval( $wrap_coupon->get_meta( '_wjecf_max_matching_product_subtotal' ) );
|
400 |
+
if ( $min_matching_product_subtotal > 0 || $max_matching_product_subtotal > 0 ) {
|
401 |
+
$subtotal = $this->get_subtotal_of_matching_products( $coupon, $wc_discounts );
|
402 |
+
//$this->log( 'debug', 'Subtotal of matching products: ' . $subtotal );
|
403 |
+
if ( $min_matching_product_subtotal > 0 && $subtotal < $min_matching_product_subtotal ) throw new Exception( self::E_WC_COUPON_MIN_MATCHING_SUBTOTAL_NOT_MET );
|
404 |
+
if ( $max_matching_product_subtotal > 0 && $subtotal > $max_matching_product_subtotal ) throw new Exception( self::E_WC_COUPON_MAX_MATCHING_SUBTOTAL_NOT_MET );
|
405 |
+
|
406 |
+
if ( $min_matching_product_subtotal > 0 ) {
|
407 |
+
$multiplier = self::min_value( floor( $subtotal / $min_matching_product_subtotal ), $multiplier );
|
408 |
+
}
|
409 |
+
}
|
410 |
+
|
411 |
+
//============================
|
412 |
+
//Test restricted shipping methods
|
413 |
+
$shipping_method_ids = $this->get_coupon_shipping_method_ids( $coupon );
|
414 |
+
if ( sizeof( $shipping_method_ids ) > 0 ) {
|
415 |
+
$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
|
416 |
+
$chosen_shipping = empty( $chosen_shipping_methods ) ? '' : $chosen_shipping_methods[0];
|
417 |
+
//$this->log('debug', 'Current shipping method: ' . ( $chosen_shipping === '' ? 'none' : $chosen_shipping ));
|
418 |
+
$chosen_shipping = explode( ':', $chosen_shipping); //UPS and USPS stores extra data, seperated by colon
|
419 |
+
$chosen_shipping = $chosen_shipping[0];
|
420 |
+
|
421 |
+
if ( ! in_array( $chosen_shipping, $shipping_method_ids ) ) {
|
422 |
+
throw new Exception( self::E_WC_COUPON_SHIPPING_METHOD_NOT_MET );
|
423 |
+
}
|
424 |
+
}
|
425 |
+
|
426 |
+
//============================
|
427 |
+
//Test restricted payment methods
|
428 |
+
$payment_method_ids = $this->get_coupon_payment_method_ids( $coupon );
|
429 |
+
if ( sizeof( $payment_method_ids ) > 0 ) {
|
430 |
+
$chosen_payment_method = isset( WC()->session->chosen_payment_method ) ? WC()->session->chosen_payment_method : array();
|
431 |
+
|
432 |
+
if ( ! in_array( $chosen_payment_method, $payment_method_ids ) ) {
|
433 |
+
throw new Exception( self::E_WC_COUPON_PAYMENT_METHOD_NOT_MET );
|
434 |
+
}
|
435 |
+
}
|
436 |
+
|
437 |
+
//Since 2.6.3: only verify customer if on frontend
|
438 |
+
if ( $this->is_request( 'frontend' ) ) {
|
439 |
+
//============================
|
440 |
+
//Test restricted user ids and roles
|
441 |
+
//NOTE: If both customer id and role restrictions are provided, the coupon matches if either the id or the role matches
|
442 |
+
$coupon_customer_ids = $this->get_coupon_customer_ids( $coupon );
|
443 |
+
$coupon_customer_roles = $this->get_coupon_customer_roles( $coupon );
|
444 |
+
if ( sizeof( $coupon_customer_ids ) > 0 || sizeof( $coupon_customer_roles ) > 0 ) {
|
445 |
+
$user = wp_get_current_user();
|
446 |
+
|
447 |
+
//If both fail we invalidate. Otherwise it's ok
|
448 |
+
if ( ! in_array( $user->ID, $coupon_customer_ids ) && ! array_intersect( $user->roles, $coupon_customer_roles ) ) {
|
449 |
+
throw new Exception( self::E_WC_COUPON_NOT_FOR_THIS_USER );
|
450 |
+
}
|
451 |
+
}
|
452 |
+
|
453 |
+
//============================
|
454 |
+
//Test excluded user roles
|
455 |
+
$coupon_excluded_customer_roles = $this->get_coupon_excluded_customer_roles( $coupon );
|
456 |
+
if ( sizeof( $coupon_excluded_customer_roles ) > 0 ) {
|
457 |
+
$user = wp_get_current_user();
|
458 |
+
|
459 |
+
//Excluded customer roles
|
460 |
+
if ( array_intersect( $user->roles, $coupon_excluded_customer_roles ) ) {
|
461 |
+
throw new Exception( self::E_WC_COUPON_NOT_FOR_THIS_USER );
|
462 |
+
}
|
463 |
+
}
|
464 |
+
}
|
465 |
+
|
466 |
+
//We use our own filter (instead of woocommerce_coupon_is_valid) for easier compatibility management
|
467 |
+
//e.g. WC prior to 2.3.0 can't handle Exceptions; while 2.3.0 and above require exceptions
|
468 |
+
do_action( 'wjecf_assert_coupon_is_valid', $coupon, $wc_discounts );
|
469 |
+
|
470 |
+
if ( (float) $wrap_coupon->get_minimum_amount() ) {
|
471 |
+
$multiplier = self::min_value( floor( $this->get_subtotal( $wc_discounts ) / $wrap_coupon->get_minimum_amount() ), $multiplier );
|
472 |
+
}
|
473 |
+
|
474 |
+
/**
|
475 |
+
* Filters the (product-)multiplier value of the coupon.
|
476 |
+
*
|
477 |
+
* @since 2.6.3
|
478 |
+
*
|
479 |
+
* @param float|null $multiplier Current multiplier value (or null if no multiplier yet known)
|
480 |
+
* @param WC_Coupon $coupon The coupon
|
481 |
+
* @param WC_Discounts $wc_discounts Discounts class containing the cart items (NOTE: Will be a WJECF_WC_Discounts for WC < 3.2.0)
|
482 |
+
*/
|
483 |
+
$multiplier = apply_filters( 'wjecf_coupon_multiplier_value', $multiplier, $coupon, $wc_discounts );
|
484 |
+
$this->coupon_multiplier_values[ $wrap_coupon->get_code() ] = isset( $multiplier ) ? $multiplier : 1;
|
485 |
+
|
486 |
+
//$this->log( 'debug', 'Coupon ' . $wrap_coupon->get_code() . ' is valid. Multiplyer value: ' . $multiplier );
|
487 |
+
|
488 |
+
return true; // VALID!
|
489 |
+
}
|
490 |
+
|
491 |
+
/**
|
492 |
+
* Return the lowest multiplier value
|
493 |
+
* @param float $value
|
494 |
+
* @param float|null $current_multiplier_value Null means the value is not yet known
|
495 |
+
* @return float
|
496 |
+
*/
|
497 |
+
private static function min_value( $value, $current_multiplier_value = null ) {
|
498 |
+
return ( $current_multiplier_value === null || $value < $current_multiplier_value ) ? $value : $current_multiplier_value;
|
499 |
+
}
|
500 |
+
|
501 |
+
/**
|
502 |
+
* The amount of times the minimum spend / quantity / subtotal values are reached
|
503 |
+
* @return int 1 or more if coupon is valid, otherwise 0
|
504 |
+
*/
|
505 |
+
public function get_coupon_multiplier_value( $coupon ) {
|
506 |
+
$coupon = WJECF_WC()->get_coupon( $coupon );
|
507 |
+
|
508 |
+
//If coupon validation was not executed, the value is unknown
|
509 |
+
if ( ! isset( $this->coupon_multiplier_values[ WJECF_Wrap( $coupon )->get_code() ] ) ) {
|
510 |
+
if ( ! $this->coupon_is_valid( true, $coupon ) ) {
|
511 |
+
return 0;
|
512 |
+
}
|
513 |
+
//Calling coupon_is_valid enforces $this->coupon_multiplier_values to be set; if the coupon is valid.
|
514 |
+
}
|
515 |
+
|
516 |
+
return $this->coupon_multiplier_values[ WJECF_Wrap( $coupon )->get_code() ];
|
517 |
+
}
|
518 |
+
|
519 |
+
//Temporary storage
|
520 |
+
private $coupon_multiplier_values = array();
|
521 |
+
|
522 |
+
|
523 |
+
/**
|
524 |
+
* (API FUNCTION)
|
525 |
+
* The total amount of the products in the cart that match the coupon restrictions
|
526 |
+
* since 2.2.2-b3
|
527 |
+
*/
|
528 |
+
public function get_quantity_of_matching_products( $coupon, $wc_discounts = null ) {
|
529 |
+
$coupon = WJECF_WC()->get_coupon( $coupon );
|
530 |
+
$items = WJECF_WC()->get_discount_items( $wc_discounts );
|
531 |
+
|
532 |
+
$qty = 0;
|
533 |
+
foreach( $items as $item_key => $item ) {
|
534 |
+
if ( $item->product === false ) continue;
|
535 |
+
|
536 |
+
if ($this->coupon_is_valid_for_product( $coupon, $item->product, $item->object ) ) {
|
537 |
+
$qty += $item->quantity;
|
538 |
+
}
|
539 |
+
}
|
540 |
+
return $qty;
|
541 |
+
}
|
542 |
+
|
543 |
+
/**
|
544 |
+
* (API FUNCTION)
|
545 |
+
* The total value of the products in the cart that match the coupon restrictions
|
546 |
+
* since 2.2.2-b3
|
547 |
+
*/
|
548 |
+
public function get_subtotal_of_matching_products( $coupon, $wc_discounts = null ) {
|
549 |
+
$coupon = WJECF_WC()->get_coupon( $coupon );
|
550 |
+
$items = WJECF_WC()->get_discount_items( $wc_discounts );
|
551 |
+
|
552 |
+
$subtotal_precise = 0;
|
553 |
+
foreach( $items as $item_key => $item ) {
|
554 |
+
if ( $item->product === false ) continue;
|
555 |
+
|
556 |
+
if ($this->coupon_is_valid_for_product( $coupon, $item->product, $item->object ) ) {
|
557 |
+
$subtotal_precise += $item->price;
|
558 |
+
}
|
559 |
+
}
|
560 |
+
|
561 |
+
$subtotal = WJECF_WC()->wc_remove_number_precision( $subtotal_precise );
|
562 |
+
return $subtotal;
|
563 |
+
}
|
564 |
+
|
565 |
+
/**
|
566 |
+
* The total value of the products in the cart
|
567 |
+
* since 2.2.2-b3
|
568 |
+
*/
|
569 |
+
public function get_subtotal( $wc_discounts = null ) {
|
570 |
+
$items = WJECF_WC()->get_discount_items( $wc_discounts );
|
571 |
+
|
572 |
+
$subtotal_precise = 0;
|
573 |
+
foreach( $items as $item_key => $item ) {
|
574 |
+
if ( $item->product === false ) continue;
|
575 |
+
$subtotal_precise += $item->price;
|
576 |
+
}
|
577 |
+
|
578 |
+
$subtotal = WJECF_WC()->wc_remove_number_precision( $subtotal_precise );
|
579 |
+
return $subtotal;
|
580 |
+
}
|
581 |
+
|
582 |
+
/**
|
583 |
+
* (API FUNCTION)
|
584 |
+
* Test if coupon is valid for the product
|
585 |
+
* (this function is used to count the quantity of matching products)
|
586 |
+
*/
|
587 |
+
public function coupon_is_valid_for_product( $coupon, $product, $values = array() ) {
|
588 |
+
//Do not count the free products
|
589 |
+
if ( isset( $values['_wjecf_free_product_coupon'] ) ) {
|
590 |
+
return false;
|
591 |
+
}
|
592 |
+
|
593 |
+
//Get the original coupon, without values overwritten by WJECF
|
594 |
+
$duplicate_coupon = $this->get_original_coupon( $coupon );
|
595 |
+
|
596 |
+
//$coupon->is_valid_for_product() only works for fixed_product or percent_product discounts
|
597 |
+
if ( ! $duplicate_coupon->is_type( WJECF_WC()->wc_get_product_coupon_types() ) ) {
|
598 |
+
WJECF_Wrap( $duplicate_coupon )->set_discount_type( 'fixed_product' );
|
599 |
+
}
|
600 |
+
|
601 |
+
$valid = $duplicate_coupon->is_valid_for_product( $product, $values );
|
602 |
+
//$this->log( sprintf("%s valid for %s? %s", WJECF_Wrap( $coupon )->get_code(), WJECF_Wrap( $product )->get_name(), $valid ? 'yes':'no' ) );
|
603 |
+
return $valid;
|
604 |
+
}
|
605 |
+
|
606 |
+
|
607 |
+
// =====================
|
608 |
+
|
609 |
+
/**
|
610 |
+
* Get array of the selected shipping methods ids.
|
611 |
+
* @param WC_Coupon|string $coupon The coupon code or a WC_Coupon object
|
612 |
+
* @return array Id's of the shipping methods or an empty array.
|
613 |
+
*/
|
614 |
+
public function get_coupon_shipping_method_ids( $coupon ) {
|
615 |
+
$v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_shipping_methods' );
|
616 |
+
return is_array( $v ) ? $v : array();
|
617 |
+
}
|
618 |
+
|
619 |
+
/**
|
620 |
+
* Get array of the selected payment method ids.
|
621 |
+
* @param WC_Coupon|string $coupon The coupon code or a WC_Coupon object
|
622 |
+
* @return array Id's of the payment methods or an empty array.
|
623 |
+
*/
|
624 |
+
public function get_coupon_payment_method_ids( $coupon ) {
|
625 |
+
$v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_payment_methods' );
|
626 |
+
return is_array( $v ) ? $v : array();
|
627 |
+
}
|
628 |
+
|
629 |
+
/**
|
630 |
+
* Get array of the selected customer ids.
|
631 |
+
* @param WC_Coupon|string $coupon The coupon code or a WC_Coupon object
|
632 |
+
* @return array Id's of the customers (users) or an empty array.
|
633 |
+
*/
|
634 |
+
public function get_coupon_customer_ids( $coupon ) {
|
635 |
+
$v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_customer_ids' );
|
636 |
+
return WJECF()->sanitizer()->sanitize( $v, 'int[]' );
|
637 |
+
}
|
638 |
+
|
639 |
+
/**
|
640 |
+
* Get array of the selected customer role ids.
|
641 |
+
* @param WC_Coupon|string $coupon The coupon code or a WC_Coupon object
|
642 |
+
* @return array Id's (string) of the customer roles or an empty array.
|
643 |
+
*/
|
644 |
+
public function get_coupon_customer_roles( $coupon ) {
|
645 |
+
$v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_customer_roles' );
|
646 |
+
return is_array( $v ) ? $v : array();
|
647 |
+
}
|
648 |
+
|
649 |
+
/**
|
650 |
+
* Get array of the excluded customer role ids.
|
651 |
+
* @param WC_Coupon|string $coupon The coupon code or a WC_Coupon object
|
652 |
+
* @return array Id's (string) of the excluded customer roles or an empty array.
|
653 |
+
*/
|
654 |
+
public function get_coupon_excluded_customer_roles( $coupon ) {
|
655 |
+
$v = WJECF_Wrap( $coupon )->get_meta( '_wjecf_excluded_customer_roles' );
|
656 |
+
return is_array( $v ) ? $v : array();
|
657 |
+
}
|
658 |
+
|
659 |
+
|
660 |
+
// ===========================================================================
|
661 |
+
// User identification
|
662 |
+
// ===========================================================================
|
663 |
+
|
664 |
+
/**
|
665 |
+
* Get a list of the users' known email addresses
|
666 |
+
*
|
667 |
+
* NOTE: Also called in AutoCoupon
|
668 |
+
*
|
669 |
+
* @since 2.5.6 (Moved from WJECF_AutoCoupon)
|
670 |
+
*/
|
671 |
+
public function get_user_emails() {
|
672 |
+
if ( ! is_array($this->_user_emails) ) {
|
673 |
+
$this->_user_emails = array();
|
674 |
+
//Email of the logged in user
|
675 |
+
if ( is_user_logged_in() ) {
|
676 |
+
$current_user = wp_get_current_user();
|
677 |
+
$this->_user_emails[] = $current_user->user_email;
|
678 |
+
}
|
679 |
+
}
|
680 |
+
$user_emails = $this->_user_emails;
|
681 |
+
|
682 |
+
$billing_email = $this->get_session('billing_email', '');
|
683 |
+
if ( is_email( $billing_email ) ) $user_emails[] = $billing_email;
|
684 |
+
|
685 |
+
$user_emails = array_map( 'strtolower', $user_emails );
|
686 |
+
$user_emails = array_map( 'sanitize_email', $user_emails );
|
687 |
+
$user_emails = array_filter( $user_emails, 'is_email' );
|
688 |
+
return array_unique( $user_emails );
|
689 |
+
}
|
690 |
+
|
691 |
+
/**
|
692 |
+
* Called on action: woocommerce_checkout_update_order_review
|
693 |
+
*
|
694 |
+
* Collects billing email address from the checkout-form
|
695 |
+
*/
|
696 |
+
public function fetch_billing_email( $post_data ) {
|
697 |
+
//post_data can be an array, or a query=string&like=this
|
698 |
+
if ( ! is_array( $post_data ) ) {
|
699 |
+
parse_str( $post_data, $posted );
|
700 |
+
} else {
|
701 |
+
$posted = $post_data;
|
702 |
+
}
|
703 |
+
|
704 |
+
if ( isset( $posted['billing_email'] ) ) {
|
705 |
+
//$this->log('debug', 'billing:' . $posted['billing_email']);
|
706 |
+
WJECF()->set_session( 'billing_email', $posted['billing_email'] );
|
707 |
+
}
|
708 |
+
}
|
709 |
+
|
710 |
+
public function is_pro() {
|
711 |
+
return $this instanceof WJECF_Pro_Controller;
|
712 |
+
}
|
713 |
+
|
714 |
+
// ===========================================================================
|
715 |
+
// START - OVERWRITE INFO MESSAGES
|
716 |
+
// ===========================================================================
|
717 |
+
|
718 |
+
/**
|
719 |
+
* 2.3.4
|
720 |
+
* If a 'Coupon applied' message is displayed by WooCommerce, replace it by another message (or no message)
|
721 |
+
* @param WC_Coupon $coupon The coupon to replace the message for
|
722 |
+
* @param string $new_message The new message. Set to empty string if no message must be displayed
|
723 |
+
*/
|
724 |
+
public function start_overwrite_success_message( $coupon, $new_message = '' ) {
|
725 |
+
$this->overwrite_coupon_message[ WJECF_Wrap( $coupon )->get_code() ] = array( $coupon->get_coupon_message( WC_Coupon::WC_COUPON_SUCCESS ) => $new_message );
|
726 |
+
add_filter( 'woocommerce_coupon_message', array( $this, 'filter_woocommerce_coupon_message' ), 10, 3 );
|
727 |
+
}
|
728 |
+
|
729 |
+
/**
|
730 |
+
* 2.3.4
|
731 |
+
* Stop overwriting messages
|
732 |
+
*/
|
733 |
+
public function stop_overwrite_success_message() {
|
734 |
+
remove_filter( 'woocommerce_coupon_message', array( $this, 'filter_woocommerce_coupon_message' ), 10 );
|
735 |
+
$this->overwrite_coupon_message = array();
|
736 |
+
}
|
737 |
+
|
738 |
+
private $overwrite_coupon_message = array(); /* [ 'coupon_code' => [ old_message' => 'new_message' ] ] */
|
739 |
+
|
740 |
+
function filter_woocommerce_coupon_message( $msg, $msg_code, $coupon ) {
|
741 |
+
if ( isset( $this->overwrite_coupon_message[ WJECF_Wrap( $coupon )->get_code() ][ $msg ] ) ) {
|
742 |
+
$msg = $this->overwrite_coupon_message[ WJECF_Wrap( $coupon )->get_code() ][ $msg ];
|
743 |
+
}
|
744 |
+
return $msg;
|
745 |
+
}
|
746 |
+
|
747 |
+
// ===========================================================================
|
748 |
+
// END - OVERWRITE INFO MESSAGES
|
749 |
+
// ===========================================================================
|
750 |
+
|
751 |
+
/**
|
752 |
+
* @since 2.4.4
|
753 |
+
*
|
754 |
+
* Get a coupon, but inhibit the woocommerce_coupon_loaded to overwrite values.
|
755 |
+
* @param WC_Coupon|string $coupon The coupon code or a WC_Coupon object
|
756 |
+
* @return WC_Coupon The coupon object
|
757 |
+
*/
|
758 |
+
public function get_original_coupon( $coupon ) {
|
759 |
+
//Prevent returning the same instance
|
760 |
+
if ( $coupon instanceof WC_Coupon ) {
|
761 |
+
$coupon = WJECF_Wrap( $coupon )->get_code();
|
762 |
+
}
|
763 |
+
$this->inhibit_overwrite++;
|
764 |
+
$coupon = WJECF_WC()->get_coupon( $coupon );
|
765 |
+
$this->inhibit_overwrite--;
|
766 |
+
return $coupon;
|
767 |
+
}
|
768 |
+
|
769 |
+
private $inhibit_overwrite = 0;
|
770 |
+
|
771 |
+
/**
|
772 |
+
* @since 2.4.4
|
773 |
+
*
|
774 |
+
* May coupon values be overwritten by this plugin upon load?
|
775 |
+
* @return bool
|
776 |
+
*/
|
777 |
+
public function allow_overwrite_coupon_values() {
|
778 |
+
return ( $this->inhibit_overwrite == 0 ) && $this->is_request( 'frontend' );
|
779 |
+
}
|
780 |
+
|
781 |
+
//============
|
782 |
+
|
783 |
+
private $_session_data = null;
|
784 |
+
/**
|
785 |
+
* Read something from the session.
|
786 |
+
*
|
787 |
+
* If key is omitted; all the session data will be returned as an array
|
788 |
+
*
|
789 |
+
* @param string $key The key for identification
|
790 |
+
* @param any $default The default value (Default: false)
|
791 |
+
*
|
792 |
+
* @return The saved value if found, otherwise the default value
|
793 |
+
*/
|
794 |
+
public function get_session( $key = null, $default = false ) {
|
795 |
+
if ( $this->_session_data == null ) {
|
796 |
+
if ( WC()->session == null ) {
|
797 |
+
$this->log( 'error', 'Trying to access WC()->session while it was not yet initialized.' );
|
798 |
+
return null;
|
799 |
+
}
|
800 |
+
$this->_session_data = WC()->session->get( '_wjecf_session_data', array() );
|
801 |
+
}
|
802 |
+
|
803 |
+
if ( ! isset( $key ) ) return $this->_session_data;
|
804 |
+
if ( ! isset( $this->_session_data[ $key ] ) ) return $default;
|
805 |
+
return $this->_session_data[ $key ];
|
806 |
+
}
|
807 |
+
|
808 |
+
/**
|
809 |
+
* Save something in the session
|
810 |
+
*
|
811 |
+
* @param string $key The key for identification
|
812 |
+
* @param anything $value The value to store. Use 'null' to remove the value
|
813 |
+
*/
|
814 |
+
public function set_session( $key, $value ) {
|
815 |
+
if ( $this->_session_data == null) {
|
816 |
+
if ( WC()->session == null ) {
|
817 |
+
$this->log( 'error', 'Trying to access WC()->session while it was not yet initialized.' );
|
818 |
+
return null;
|
819 |
+
}
|
820 |
+
$this->_session_data = WC()->session->get( '_wjecf_session_data', array() );
|
821 |
+
}
|
822 |
+
if ( is_null( $value ) ) {
|
823 |
+
unset( $this->_session_data[ $key ] );
|
824 |
+
} else {
|
825 |
+
$this->_session_data[ $key ] = $value;
|
826 |
+
}
|
827 |
+
|
828 |
+
WC()->session->set( '_wjecf_session_data', $this->_session_data );
|
829 |
+
}
|
830 |
+
|
831 |
+
/**
|
832 |
+
* (Copied from class-woocommerce.php) What type of request is this?
|
833 |
+
*
|
834 |
+
* @since 2.6.2
|
835 |
+
* @param string $type admin, ajax, cron or frontend.
|
836 |
+
* @return bool
|
837 |
+
*/
|
838 |
+
public function is_request( $type ) {
|
839 |
+
switch ( $type ) {
|
840 |
+
case 'admin':
|
841 |
+
return is_admin();
|
842 |
+
case 'ajax':
|
843 |
+
return defined( 'DOING_AJAX' );
|
844 |
+
case 'cron':
|
845 |
+
return defined( 'DOING_CRON' );
|
846 |
+
case 'frontend':
|
847 |
+
return ( ! is_admin() || defined( 'DOING_AJAX' ) ) && ! defined( 'DOING_CRON' );
|
848 |
+
}
|
849 |
+
}
|
850 |
+
|
851 |
+
/**
|
852 |
+
* Get overwritable template filename
|
853 |
+
*
|
854 |
+
* Template can be overwritten in wp-content/themes/YOUR_THEME/woocommerce-auto-added-coupons/
|
855 |
+
* @param string $template_name
|
856 |
+
* @return string Template filename
|
857 |
+
*/
|
858 |
+
public function get_template_filename( $template_name ) {
|
859 |
+
$template_path = 'woocommerce-auto-added-coupons';
|
860 |
+
|
861 |
+
//Get template overwritten file
|
862 |
+
$template = locate_template( trailingslashit( $template_path ) . $template_name );
|
863 |
+
|
864 |
+
// Get default template
|
865 |
+
if ( ! $template ) {
|
866 |
+
$plugin_template_path = plugin_dir_path( dirname(__FILE__) ) . 'templates/';
|
867 |
+
$template = $plugin_template_path . $template_name;
|
868 |
+
}
|
869 |
+
|
870 |
+
return $template;
|
871 |
+
}
|
872 |
+
|
873 |
+
/**
|
874 |
+
* Include a template file, either from this plugins directory or overwritten in the themes directory
|
875 |
+
* @param type $template_name
|
876 |
+
* @return type
|
877 |
+
*/
|
878 |
+
public function include_template( $template_name, $variables = array() ) {
|
879 |
+
extract( $variables );
|
880 |
+
include( $this->get_template_filename( $template_name ) );
|
881 |
+
}
|
882 |
+
|
883 |
+
// ========================
|
884 |
+
// INFO ABOUT WJECF PLUGIN
|
885 |
+
// ========================
|
886 |
+
|
887 |
+
/**
|
888 |
+
* Filename of this plugin including the containing directory.
|
889 |
+
* @return string
|
890 |
+
*/
|
891 |
+
public function plugin_file() {
|
892 |
+
$filename = $this->is_pro() ? "woocommerce-jos-autocoupon-pro.php" : "woocommerce-jos-autocoupon.php" ;
|
893 |
+
return trailingslashit( basename( dirname( dirname( __FILE__ ) ) ) ) . $filename;
|
894 |
+
}
|
895 |
+
|
896 |
+
public function plugin_basename() {
|
897 |
+
return plugin_basename( $this->plugin_file() );
|
898 |
+
}
|
899 |
+
|
900 |
+
|
901 |
+
/**
|
902 |
+
* url to the base directory of this plugin (wp-content/woocommerce-jos-autocoupon/) with trailing slash
|
903 |
+
* @return string
|
904 |
+
*/
|
905 |
+
public function plugin_url( $suffix = '' ) {
|
906 |
+
return plugins_url( '/', dirname( __FILE__ ) ) . $suffix;
|
907 |
+
}
|
908 |
+
|
909 |
+
public function plugin_version() {
|
910 |
+
return WJECF_VERSION;
|
911 |
+
}
|
912 |
+
|
913 |
+
// ========================
|
914 |
+
// LOGGING
|
915 |
+
// ========================
|
916 |
+
|
917 |
+
|
918 |
+
/**
|
919 |
+
* Log a message for debugging.
|
920 |
+
*
|
921 |
+
* If debug_mode is false; messages with level 'debug' will be ignored.
|
922 |
+
*
|
923 |
+
* @param string $level The level of the message. e.g. 'debug' or 'warning'
|
924 |
+
* @param string $string The message to log
|
925 |
+
* @param int $skip_backtrace Defaults to 0, amount of items to skip in backtrace to fetch class and method name
|
926 |
+
*/
|
927 |
+
public function log( $level, $message = null, $skip_backtrace = 0) {
|
928 |
+
if ( ! $this->debugger ) {
|
929 |
+
$this->debugger = $this->get_plugin( 'WJECF_Debug' );
|
930 |
+
}
|
931 |
+
|
932 |
+
if ( $this->debugger ) {
|
933 |
+
$this->debugger->log( $level, $message, $skip_backtrace + 1 );
|
934 |
+
}
|
935 |
+
}
|
936 |
+
private $debugger = null;
|
937 |
+
|
938 |
+
}
|
939 |
+
|
940 |
+
/**
|
941 |
+
* Class that prevents an action or filter to be recursively called
|
942 |
+
*/
|
943 |
+
class WJECF_Action_Or_Filter {
|
944 |
+
|
945 |
+
private $tag;
|
946 |
+
private $function_to_add;
|
947 |
+
private $priority;
|
948 |
+
private $accepted_args;
|
949 |
+
private $limit_calls;
|
950 |
+
|
951 |
+
/**
|
952 |
+
*
|
953 |
+
* @param string $tag name of the action or filter
|
954 |
+
* @param callable $function_to_add
|
955 |
+
* @param int $priority
|
956 |
+
* @param int $accepted_args
|
957 |
+
* @param int $limit_calls When > 0 the calls will be limited to this amount (prevents recursive calls)
|
958 |
+
*/
|
959 |
+
private function __construct( $tag, $function_to_add, $priority, $accepted_args, $limit_calls = 0 ) {
|
960 |
+
$this->tag = $tag;
|
961 |
+
$this->function_to_add = $function_to_add;
|
962 |
+
$this->priority = $priority;
|
963 |
+
$this->accepted_args = $accepted_args;
|
964 |
+
|
965 |
+
$this->limit_calls = $limit_calls;
|
966 |
+
}
|
967 |
+
|
968 |
+
private $inhibit = false;
|
969 |
+
private $counter = 0;
|
970 |
+
|
971 |
+
//Must be public for WC
|
972 |
+
public function execute() {
|
973 |
+
if ($this->inhibit) return;
|
974 |
+
|
975 |
+
$this->counter++;
|
976 |
+
|
977 |
+
$this->inhibit = true;
|
978 |
+
$func_args = func_get_args(); // $func_args variable required for PHP5.2
|
979 |
+
$retval = call_user_func_array( $this->function_to_add, $func_args );
|
980 |
+
$this->inhibit = false;
|
981 |
+
|
982 |
+
if ($this->limit_calls > 0 && $this->counter >= $this->limit_calls) {
|
983 |
+
remove_action( $this->tag, array( $this, 'execute' ), $this->priority ); //unhook the action
|
984 |
+
}
|
985 |
+
|
986 |
+
return $retval;
|
987 |
+
}
|
988 |
+
|
989 |
+
/**
|
990 |
+
* Same as WordPress add_action(), but prevents the callback to be recursively called
|
991 |
+
*
|
992 |
+
* @param string $tag
|
993 |
+
* @param callable $function_to_add
|
994 |
+
* @param int $priority
|
995 |
+
* @param int $accepted_args
|
996 |
+
*/
|
997 |
+
public static function action( $tag, $function_to_add, $priority = 10, $accepted_args = 1, $limit_calls ) {
|
998 |
+
$me = new WJECF_Action_Or_Filter( $tag, $function_to_add, $priority, $accepted_args, $limit_calls );
|
999 |
+
add_action( $tag, array( $me, 'execute' ), $priority, $accepted_args );
|
1000 |
+
}
|
1001 |
+
}
|
includes/WJECF_Debug.php
CHANGED
@@ -1,200 +1,200 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
defined('ABSPATH') or die();
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Debugging functions for wjecf
|
7 |
-
*
|
8 |
-
* @since 2.6.0
|
9 |
-
*/
|
10 |
-
class WJECF_Debug extends Abstract_WJECF_Plugin {
|
11 |
-
|
12 |
-
private $enable_logging = false;
|
13 |
-
|
14 |
-
public function __construct() {
|
15 |
-
$this->set_plugin_data( array(
|
16 |
-
'description' => __( 'Debugging methods for WooCommerce Extended Coupon Features.', 'woocommerce-jos-autocoupon' ),
|
17 |
-
'dependencies' => array(),
|
18 |
-
'can_be_disabled' => false,
|
19 |
-
'hidden' => false
|
20 |
-
) );
|
21 |
-
}
|
22 |
-
|
23 |
-
public function init_hook() {
|
24 |
-
$this->enable_logging = true;
|
25 |
-
|
26 |
-
add_action( 'wp_loaded', array( $this, 'handle_querystring' ), 90 );
|
27 |
-
add_action( 'wp_footer', array( $this, 'render_log' ) ); //Log
|
28 |
-
}
|
29 |
-
|
30 |
-
public function init_admin_hook() {
|
31 |
-
if ( current_user_can( 'manage_options' ) && $this->debug_mode() )
|
32 |
-
{
|
33 |
-
if ( $wjecf_admin = WJECF()->get_plugin('WJECF_Admin') ) {
|
34 |
-
$msg = __( 'Debug mode is enabled. Please disable it when you\'re done debugging.', 'woocommerce-jos-autocoupon' );
|
35 |
-
$wjecf_admin_settings = WJECF()->get_plugin('WJECF_Admin_Settings');
|
36 |
-
if ($wjecf_admin_settings) {
|
37 |
-
$msg .= ' <a href="' . $wjecf_admin_settings ->get_settings_page_url() . '">' . __( 'Go to settings page', 'woocommerce-jos-autocoupon' ) . '</a>';
|
38 |
-
}
|
39 |
-
$wjecf_admin->enqueue_notice( $msg, 'notice-warning' );
|
40 |
-
}
|
41 |
-
add_action( 'wjecf_coupon_metabox_misc', array( $this, 'wjecf_coupon_metabox_misc' ), 20, 2 );
|
42 |
-
}
|
43 |
-
}
|
44 |
-
|
45 |
-
// ========================
|
46 |
-
// ACTION HOOKS
|
47 |
-
// ========================
|
48 |
-
|
49 |
-
public function wjecf_coupon_metabox_misc( $thepostid, $post ) {
|
50 |
-
echo "<h3>" . esc_html( __( 'Debug', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
|
51 |
-
|
52 |
-
$coupon_code = WJECF_Wrap( WJECF_WC()->get_coupon( $post ) )->get_code();
|
53 |
-
$url = add_query_arg( array( 'wjecf_dump' => $coupon_code ), get_site_url() );
|
54 |
-
$text = __( 'Coupon data as json', 'woocommerce-jos-autocoupon');
|
55 |
-
echo '<p>';
|
56 |
-
printf( '<a href="%s" target="_blank">%s</a>', $url, $text );
|
57 |
-
echo '</p>';
|
58 |
-
}
|
59 |
-
|
60 |
-
/**
|
61 |
-
* Output the log as html
|
62 |
-
*/
|
63 |
-
public function render_log() {
|
64 |
-
if ( ! $this->debug_mode() && ! current_user_can( 'manage_options' ) ) return;
|
65 |
-
if ( ! WJECF()->get_session('wjecf_log') ) return;
|
66 |
-
|
67 |
-
$this->log( 'debug', "Session: " . print_r( WJECF()->get_session(), true ) );
|
68 |
-
$this->log( 'debug', 'Current coupons in cart: ' . implode( ", ", WC()->cart->applied_coupons ) );
|
69 |
-
|
70 |
-
if ( $this->log_output ) {
|
71 |
-
WJECF()->include_template( 'debug/log.php', array( 'log' => $this->log_output ) );
|
72 |
-
}
|
73 |
-
}
|
74 |
-
|
75 |
-
/**
|
76 |
-
* Query argument 'wjecf_debug' toggles rendering of the debug-log for any user (only allowed when debug mode is enabled)
|
77 |
-
* @return type
|
78 |
-
*/
|
79 |
-
public function handle_querystring() {
|
80 |
-
$this->handle_querystring_wjecf_log();
|
81 |
-
$this->handle_querystring_wjecf_dump_coupon();
|
82 |
-
}
|
83 |
-
|
84 |
-
public function handle_querystring_wjecf_log() {
|
85 |
-
// wjecf_log=1 / 0 Enable log on the frontend for guest users
|
86 |
-
if ( isset( $_GET['wjecf_log'] ) ) {
|
87 |
-
WJECF()->set_session( 'wjecf_log', $_GET['wjecf_log'] ? true : null );
|
88 |
-
}
|
89 |
-
}
|
90 |
-
|
91 |
-
public function handle_querystring_wjecf_dump_coupon() {
|
92 |
-
// wjecf_dump_coupon=coupon_code Dump the coupon data on the frontend
|
93 |
-
if ( ! current_user_can( 'manage_options' ) && ! $this->debug_mode() ) return;
|
94 |
-
|
95 |
-
if ( isset( $_GET['wjecf_dump'] ) ) {
|
96 |
-
$coupon_code = $_GET['wjecf_dump'];
|
97 |
-
$coupon = new WC_Coupon( $coupon_code );
|
98 |
-
$wrap_coupon = WJECF_Wrap( $coupon );
|
99 |
-
$coupon_id = $wrap_coupon->get_id();
|
100 |
-
|
101 |
-
$array = array( 'result' => 'error' );
|
102 |
-
if ( $coupon_id ) {
|
103 |
-
$meta = array();
|
104 |
-
foreach( array_keys( get_post_meta( $coupon_id ) ) as $key ) {
|
105 |
-
$meta[$key] = $wrap_coupon->get_meta( $key );
|
106 |
-
}
|
107 |
-
ksort( $meta );
|
108 |
-
$array['coupons'] = array(
|
109 |
-
'coupon_id' => $coupon_id,
|
110 |
-
'coupon_code' => $coupon->get_code(),
|
111 |
-
'meta' => $meta,
|
112 |
-
);
|
113 |
-
$array['result'] = 'ok';
|
114 |
-
} else {
|
115 |
-
}
|
116 |
-
header( 'Content-Type: application/json' );
|
117 |
-
echo json_encode( $array );
|
118 |
-
die();
|
119 |
-
}
|
120 |
-
}
|
121 |
-
|
122 |
-
/**
|
123 |
-
* Is debug mode enabled?
|
124 |
-
*
|
125 |
-
* @since 2.6.0
|
126 |
-
* @return bool
|
127 |
-
*/
|
128 |
-
public function debug_mode() {
|
129 |
-
return WJECF()->get_option('debug_mode');
|
130 |
-
}
|
131 |
-
|
132 |
-
|
133 |
-
// ========================
|
134 |
-
// LOGGING
|
135 |
-
// ========================
|
136 |
-
|
137 |
-
private $debug_mode = false;
|
138 |
-
private $log_output = array();
|
139 |
-
|
140 |
-
/**
|
141 |
-
* Log a message for debugging.
|
142 |
-
*
|
143 |
-
* If debug_mode is false; messages with level 'debug' will be ignored.
|
144 |
-
*
|
145 |
-
* @param string $level The level of the message. e.g. 'debug' or 'warning'
|
146 |
-
* @param string $string The message to log
|
147 |
-
* @param int $skip_backtrace Defaults to 0, amount of items to skip in backtrace to fetch class and method name
|
148 |
-
*/
|
149 |
-
public function log( $level, $message = null, $skip_backtrace = 0 ) {
|
150 |
-
if ( ! $this->enable_logging ) return;
|
151 |
-
|
152 |
-
if ( ! $this->debug_mode() && $level === 'debug' ) return;
|
153 |
-
|
154 |
-
//Backwards compatibility; $level was introduced in 2.4.4
|
155 |
-
if ( $message == null ) {
|
156 |
-
$message = $level;
|
157 |
-
$level = 'debug';
|
158 |
-
} else if ( is_int( $message ) && ! $this->is_valid_log_level( $level ) ) {
|
159 |
-
$skip_backtrace = $message;
|
160 |
-
$message = $level;
|
161 |
-
$level = 'debug';
|
162 |
-
}
|
163 |
-
|
164 |
-
if ( ! $this->debug_mode() && $level === 'debug' ) return;
|
165 |
-
|
166 |
-
$nth = 1 + $skip_backtrace;
|
167 |
-
$bt = debug_backtrace();
|
168 |
-
$class = $bt[$nth]['class'];
|
169 |
-
$function = $bt[$nth]['function'];
|
170 |
-
|
171 |
-
$row = array(
|
172 |
-
'level' => $level,
|
173 |
-
'time' => time(),
|
174 |
-
'class' => $class,
|
175 |
-
'function' => $function,
|
176 |
-
'filter' => current_filter(),
|
177 |
-
'message' => $message,
|
178 |
-
);
|
179 |
-
|
180 |
-
$nice_str = $row['filter'] . ' ' . $row['class'] . '::' . $row['function'] . ' ' . $row['message'];
|
181 |
-
|
182 |
-
//Since WC2.7
|
183 |
-
if ( function_exists( 'wc_get_logger' ) ) {
|
184 |
-
$logger = wc_get_logger();
|
185 |
-
$context = array( 'source' => 'WooCommerce Extended Coupon Features' );
|
186 |
-
$logger->log( $level, $nice_str, $context );
|
187 |
-
if ( $level !== 'debug' ) error_log( 'WooCommerce Extended Coupon Features ' . $level . ': ' . $row['message'] );
|
188 |
-
} else {
|
189 |
-
//Legacy
|
190 |
-
error_log( $level . ': ' . $nice_str );
|
191 |
-
}
|
192 |
-
|
193 |
-
$this->log_output[] = $row;
|
194 |
-
}
|
195 |
-
|
196 |
-
private function is_valid_log_level( $level ) {
|
197 |
-
return in_array( $level, array( 'debug', 'informational', 'notice', 'warning', 'error', 'critical', 'alert', 'emergency' ) );
|
198 |
-
}
|
199 |
-
|
200 |
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
defined('ABSPATH') or die();
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Debugging functions for wjecf
|
7 |
+
*
|
8 |
+
* @since 2.6.0
|
9 |
+
*/
|
10 |
+
class WJECF_Debug extends Abstract_WJECF_Plugin {
|
11 |
+
|
12 |
+
private $enable_logging = false;
|
13 |
+
|
14 |
+
public function __construct() {
|
15 |
+
$this->set_plugin_data( array(
|
16 |
+
'description' => __( 'Debugging methods for WooCommerce Extended Coupon Features.', 'woocommerce-jos-autocoupon' ),
|
17 |
+
'dependencies' => array(),
|
18 |
+
'can_be_disabled' => false,
|
19 |
+
'hidden' => false
|
20 |
+
) );
|
21 |
+
}
|
22 |
+
|
23 |
+
public function init_hook() {
|
24 |
+
$this->enable_logging = true;
|
25 |
+
|
26 |
+
add_action( 'wp_loaded', array( $this, 'handle_querystring' ), 90 );
|
27 |
+
add_action( 'wp_footer', array( $this, 'render_log' ) ); //Log
|
28 |
+
}
|
29 |
+
|
30 |
+
public function init_admin_hook() {
|
31 |
+
if ( current_user_can( 'manage_options' ) && $this->debug_mode() )
|
32 |
+
{
|
33 |
+
if ( $wjecf_admin = WJECF()->get_plugin('WJECF_Admin') ) {
|
34 |
+
$msg = __( 'Debug mode is enabled. Please disable it when you\'re done debugging.', 'woocommerce-jos-autocoupon' );
|
35 |
+
$wjecf_admin_settings = WJECF()->get_plugin('WJECF_Admin_Settings');
|
36 |
+
if ($wjecf_admin_settings) {
|
37 |
+
$msg .= ' <a href="' . $wjecf_admin_settings ->get_settings_page_url() . '">' . __( 'Go to settings page', 'woocommerce-jos-autocoupon' ) . '</a>';
|
38 |
+
}
|
39 |
+
$wjecf_admin->enqueue_notice( $msg, 'notice-warning' );
|
40 |
+
}
|
41 |
+
add_action( 'wjecf_coupon_metabox_misc', array( $this, 'wjecf_coupon_metabox_misc' ), 20, 2 );
|
42 |
+
}
|
43 |
+
}
|
44 |
+
|
45 |
+
// ========================
|
46 |
+
// ACTION HOOKS
|
47 |
+
// ========================
|
48 |
+
|
49 |
+
public function wjecf_coupon_metabox_misc( $thepostid, $post ) {
|
50 |
+
echo "<h3>" . esc_html( __( 'Debug', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
|
51 |
+
|
52 |
+
$coupon_code = WJECF_Wrap( WJECF_WC()->get_coupon( $post ) )->get_code();
|
53 |
+
$url = add_query_arg( array( 'wjecf_dump' => $coupon_code ), get_site_url() );
|
54 |
+
$text = __( 'Coupon data as json', 'woocommerce-jos-autocoupon');
|
55 |
+
echo '<p>';
|
56 |
+
printf( '<a href="%s" target="_blank">%s</a>', $url, $text );
|
57 |
+
echo '</p>';
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Output the log as html
|
62 |
+
*/
|
63 |
+
public function render_log() {
|
64 |
+
if ( ! $this->debug_mode() && ! current_user_can( 'manage_options' ) ) return;
|
65 |
+
if ( ! WJECF()->get_session('wjecf_log') ) return;
|
66 |
+
|
67 |
+
$this->log( 'debug', "Session: " . print_r( WJECF()->get_session(), true ) );
|
68 |
+
$this->log( 'debug', 'Current coupons in cart: ' . implode( ", ", WC()->cart->applied_coupons ) );
|
69 |
+
|
70 |
+
if ( $this->log_output ) {
|
71 |
+
WJECF()->include_template( 'debug/log.php', array( 'log' => $this->log_output ) );
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Query argument 'wjecf_debug' toggles rendering of the debug-log for any user (only allowed when debug mode is enabled)
|
77 |
+
* @return type
|
78 |
+
*/
|
79 |
+
public function handle_querystring() {
|
80 |
+
$this->handle_querystring_wjecf_log();
|
81 |
+
$this->handle_querystring_wjecf_dump_coupon();
|
82 |
+
}
|
83 |
+
|
84 |
+
public function handle_querystring_wjecf_log() {
|
85 |
+
// wjecf_log=1 / 0 Enable log on the frontend for guest users
|
86 |
+
if ( isset( $_GET['wjecf_log'] ) ) {
|
87 |
+
WJECF()->set_session( 'wjecf_log', $_GET['wjecf_log'] ? true : null );
|
88 |
+
}
|
89 |
+
}
|
90 |
+
|
91 |
+
public function handle_querystring_wjecf_dump_coupon() {
|
92 |
+
// wjecf_dump_coupon=coupon_code Dump the coupon data on the frontend
|
93 |
+
if ( ! current_user_can( 'manage_options' ) && ! $this->debug_mode() ) return;
|
94 |
+
|
95 |
+
if ( isset( $_GET['wjecf_dump'] ) ) {
|
96 |
+
$coupon_code = $_GET['wjecf_dump'];
|
97 |
+
$coupon = new WC_Coupon( $coupon_code );
|
98 |
+
$wrap_coupon = WJECF_Wrap( $coupon );
|
99 |
+
$coupon_id = $wrap_coupon->get_id();
|
100 |
+
|
101 |
+
$array = array( 'result' => 'error' );
|
102 |
+
if ( $coupon_id ) {
|
103 |
+
$meta = array();
|
104 |
+
foreach( array_keys( get_post_meta( $coupon_id ) ) as $key ) {
|
105 |
+
$meta[$key] = $wrap_coupon->get_meta( $key );
|
106 |
+
}
|
107 |
+
ksort( $meta );
|
108 |
+
$array['coupons'] = array(
|
109 |
+
'coupon_id' => $coupon_id,
|
110 |
+
'coupon_code' => $coupon->get_code(),
|
111 |
+
'meta' => $meta,
|
112 |
+
);
|
113 |
+
$array['result'] = 'ok';
|
114 |
+
} else {
|
115 |
+
}
|
116 |
+
header( 'Content-Type: application/json' );
|
117 |
+
echo json_encode( $array );
|
118 |
+
die();
|
119 |
+
}
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Is debug mode enabled?
|
124 |
+
*
|
125 |
+
* @since 2.6.0
|
126 |
+
* @return bool
|
127 |
+
*/
|
128 |
+
public function debug_mode() {
|
129 |
+
return WJECF()->get_option('debug_mode');
|
130 |
+
}
|
131 |
+
|
132 |
+
|
133 |
+
// ========================
|
134 |
+
// LOGGING
|
135 |
+
// ========================
|
136 |
+
|
137 |
+
private $debug_mode = false;
|
138 |
+
private $log_output = array();
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Log a message for debugging.
|
142 |
+
*
|
143 |
+
* If debug_mode is false; messages with level 'debug' will be ignored.
|
144 |
+
*
|
145 |
+
* @param string $level The level of the message. e.g. 'debug' or 'warning'
|
146 |
+
* @param string $string The message to log
|
147 |
+
* @param int $skip_backtrace Defaults to 0, amount of items to skip in backtrace to fetch class and method name
|
148 |
+
*/
|
149 |
+
public function log( $level, $message = null, $skip_backtrace = 0 ) {
|
150 |
+
if ( ! $this->enable_logging ) return;
|
151 |
+
|
152 |
+
if ( ! $this->debug_mode() && $level === 'debug' ) return;
|
153 |
+
|
154 |
+
//Backwards compatibility; $level was introduced in 2.4.4
|
155 |
+
if ( $message == null ) {
|
156 |
+
$message = $level;
|
157 |
+
$level = 'debug';
|
158 |
+
} else if ( is_int( $message ) && ! $this->is_valid_log_level( $level ) ) {
|
159 |
+
$skip_backtrace = $message;
|
160 |
+
$message = $level;
|
161 |
+
$level = 'debug';
|
162 |
+
}
|
163 |
+
|
164 |
+
if ( ! $this->debug_mode() && $level === 'debug' ) return;
|
165 |
+
|
166 |
+
$nth = 1 + $skip_backtrace;
|
167 |
+
$bt = debug_backtrace();
|
168 |
+
$class = $bt[$nth]['class'];
|
169 |
+
$function = $bt[$nth]['function'];
|
170 |
+
|
171 |
+
$row = array(
|
172 |
+
'level' => $level,
|
173 |
+
'time' => time(),
|
174 |
+
'class' => $class,
|
175 |
+
'function' => $function,
|
176 |
+
'filter' => current_filter(),
|
177 |
+
'message' => $message,
|
178 |
+
);
|
179 |
+
|
180 |
+
$nice_str = $row['filter'] . ' ' . $row['class'] . '::' . $row['function'] . ' ' . $row['message'];
|
181 |
+
|
182 |
+
//Since WC2.7
|
183 |
+
if ( function_exists( 'wc_get_logger' ) ) {
|
184 |
+
$logger = wc_get_logger();
|
185 |
+
$context = array( 'source' => 'WooCommerce Extended Coupon Features' );
|
186 |
+
$logger->log( $level, $nice_str, $context );
|
187 |
+
if ( $level !== 'debug' ) error_log( 'WooCommerce Extended Coupon Features ' . $level . ': ' . $row['message'] );
|
188 |
+
} else {
|
189 |
+
//Legacy
|
190 |
+
error_log( $level . ': ' . $nice_str );
|
191 |
+
}
|
192 |
+
|
193 |
+
$this->log_output[] = $row;
|
194 |
+
}
|
195 |
+
|
196 |
+
private function is_valid_log_level( $level ) {
|
197 |
+
return in_array( $level, array( 'debug', 'informational', 'notice', 'warning', 'error', 'critical', 'alert', 'emergency' ) );
|
198 |
+
}
|
199 |
+
|
200 |
}
|
includes/WJECF_Debug_CLI.php
CHANGED
@@ -1,267 +1,267 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
defined('ABSPATH') or die();
|
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 |
-
/**
|
21 |
-
* Test API functions for one or more coupons
|
22 |
-
*
|
23 |
-
* ## OPTIONS
|
24 |
-
*
|
25 |
-
* [couponcode, ...]
|
26 |
-
* : The coupon codes for which to run the tests. If omitted the test will be executed for all auto coupons.
|
27 |
-
*
|
28 |
-
* @param array $args CLI arguments
|
29 |
-
*/
|
30 |
-
public function test_api( $args ) {
|
31 |
-
require_once( 'pro/wjecf-pro-api-example.php' );
|
32 |
-
|
33 |
-
if ( count( $args ) > 0 ) {
|
34 |
-
$all = $args;
|
35 |
-
} else {
|
36 |
-
$all = WJECF_API()->get_all_auto_coupons();
|
37 |
-
}
|
38 |
-
|
39 |
-
foreach( $all as $coupon ) {
|
40 |
-
$values = WJECF_API_Test_Coupon( $coupon );
|
41 |
-
foreach( $values as $key => $value ) {
|
42 |
-
WP_CLI::log( sprintf( "%s: %s", $key, print_r( $value, true ) ) );
|
43 |
-
}
|
44 |
-
}
|
45 |
-
}
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Check whether the customer has ordered before.
|
49 |
-
*
|
50 |
-
* ## OPTIONS
|
51 |
-
*
|
52 |
-
* <customer>
|
53 |
-
* : The email-address or userid of the customer
|
54 |
-
*
|
55 |
-
* @param array $args CLI arguments
|
56 |
-
*/
|
57 |
-
public function test_first_order( $args )
|
58 |
-
{
|
59 |
-
if ( count( $args ) <= 0 ) {
|
60 |
-
WP_CLI::error( sprintf("Please provide an email-address" ) );
|
61 |
-
return;
|
62 |
-
}
|
63 |
-
$customer = $args[0];
|
64 |
-
$is_first = ! WJECF()->has_customer_ordered_before( $customer );
|
65 |
-
WP_CLI::log( sprintf("First order for %s: %s", $customer, $is_first ? 'yes' : 'no' ) );
|
66 |
-
}
|
67 |
-
|
68 |
-
/**
|
69 |
-
* Test the sanitizers
|
70 |
-
*/
|
71 |
-
public function test_sanitizer() {
|
72 |
-
$array_tests = array(
|
73 |
-
array(),
|
74 |
-
array(0),
|
75 |
-
array(1,0,2.0,"3")
|
76 |
-
);
|
77 |
-
foreach( $array_tests as $array ) {
|
78 |
-
$comma = join( ',', $array );
|
79 |
-
$ints_array = array_map( 'intval', $array);
|
80 |
-
$ints_comma = join( ',', $ints_array );
|
81 |
-
|
82 |
-
$this->single_test_sanitizer( $comma, 'int[]', $ints_array );
|
83 |
-
$this->single_test_sanitizer( $array, 'int[]', $ints_array );
|
84 |
-
|
85 |
-
$this->single_test_sanitizer( $comma, 'int,', $ints_comma );
|
86 |
-
$this->single_test_sanitizer( $array, 'int,', $ints_comma );
|
87 |
-
}
|
88 |
-
|
89 |
-
$this->single_test_sanitizer( null, 'int[]', array() );
|
90 |
-
|
91 |
-
$this->single_test_sanitizer( null, 'int,', '' );
|
92 |
-
$this->single_test_sanitizer( '', 'int,', '' );
|
93 |
-
|
94 |
-
$this->single_test_sanitizer( null, 'int', null );
|
95 |
-
$this->single_test_sanitizer( '', 'int', null );
|
96 |
-
$this->single_test_sanitizer( '1.234', 'int', 1 );
|
97 |
-
|
98 |
-
$this->single_test_sanitizer( '1.234', 'decimal', '1.234' );
|
99 |
-
$this->single_test_sanitizer( null, 'decimal', null );
|
100 |
-
}
|
101 |
-
|
102 |
-
private function single_test_sanitizer( $value, $rule, $expected ) {
|
103 |
-
//$msg = sprintf( "Sanitized %s: %s to %s", $rule, print_r( $value, true ), print_r( $expected, true ) );
|
104 |
-
$msg = sprintf(
|
105 |
-
"Sanitized %s: %s to %s",
|
106 |
-
$rule, $value === null ? 'null' : $value,
|
107 |
-
$expected === null ? 'null' : $expected
|
108 |
-
);
|
109 |
-
$this->assert( WJECF()->sanitizer()->sanitize( $value, $rule ) === $expected, $msg);
|
110 |
-
|
111 |
-
}
|
112 |
-
/**
|
113 |
-
* Tests if the wrappers return the same values for WooCommerce 3.0 and older WC versions
|
114 |
-
*/
|
115 |
-
public function test_wrappers() {
|
116 |
-
|
117 |
-
$args = array(
|
118 |
-
'posts_per_page' => -1,
|
119 |
-
'orderby' => 'title',
|
120 |
-
'order' => 'asc',
|
121 |
-
'post_type' => 'shop_coupon',
|
122 |
-
'post_status' => 'publish',
|
123 |
-
);
|
124 |
-
$posts = get_posts( $args );
|
125 |
-
foreach ( $posts as $post ) {
|
126 |
-
$coupon = WJECF_WC()->get_coupon( $post->ID );
|
127 |
-
$this->execute_test_for_coupon( $coupon );
|
128 |
-
}
|
129 |
-
|
130 |
-
$args = array(
|
131 |
-
'posts_per_page' => -1,
|
132 |
-
'orderby' => 'title',
|
133 |
-
'order' => 'asc',
|
134 |
-
'post_type' => array( 'product', 'product_variation' ),
|
135 |
-
'post_status' => 'publish',
|
136 |
-
);
|
137 |
-
$posts = get_posts( $args );
|
138 |
-
foreach ( $posts as $post ) {
|
139 |
-
$product = wc_get_product( $post->ID );
|
140 |
-
$this->execute_test_for_product( $product );
|
141 |
-
}
|
142 |
-
|
143 |
-
$msg = sprintf("%d tests executed. Fails: %d Passes: %d", $this->tests, $this->fails, $this->passes );
|
144 |
-
if ( $this->fails != 0 )
|
145 |
-
WP_CLI::error( $msg );
|
146 |
-
else
|
147 |
-
WP_CLI::success( $msg );
|
148 |
-
|
149 |
-
}
|
150 |
-
|
151 |
-
protected function execute_test_for_coupon( $coupon ) {
|
152 |
-
//WP_CLI::log( sprintf("Coupon fields: %s", print_r( $coupon->coupon_custom_fields ) ) );
|
153 |
-
//WP_CLI::log( sprintf("Coupon fields: %s", print_r( $coupon->get_meta_data() ) ) );
|
154 |
-
|
155 |
-
$meta_keys = array_keys( $coupon->coupon_custom_fields );
|
156 |
-
$meta_keys[] = '__non_existing__';
|
157 |
-
|
158 |
-
//WP_CLI::log( sprintf("Coupon fields: %s", print_r( $coupon->coupon_custom_fields ) ) );
|
159 |
-
//WP_CLI::log( sprintf("Coupon fields: %s", print_r( $coupon->get_meta_data() ) ) );
|
160 |
-
|
161 |
-
$wrap_leg = WJECF_WC()->wrap( $coupon, false ); $wrap_leg->use_wc27 = false;
|
162 |
-
$wrap_new = WJECF_WC()->wrap( $coupon, false ); $wrap_new->use_wc27 = true;
|
163 |
-
|
164 |
-
$results = array();
|
165 |
-
$results['new'] = $wrap_new->get_id();
|
166 |
-
$results['legacy'] = $wrap_leg->get_id();
|
167 |
-
$results['old'] = $coupon->id;
|
168 |
-
$this->assert_same( $results, sprintf('Same coupon id %s', current( $results ) ) );
|
169 |
-
|
170 |
-
foreach( $meta_keys as $meta_key ) {
|
171 |
-
for($i=1; $i>=0; $i--) {
|
172 |
-
$single = $i>0;
|
173 |
-
|
174 |
-
$results = array();
|
175 |
-
$results['new'] = $wrap_new->get_meta( $meta_key, $single );
|
176 |
-
$results['legacy'] = $wrap_leg->get_meta( $meta_key, $single );
|
177 |
-
$results['old'] = get_post_meta( $coupon->id, $meta_key, $single );
|
178 |
-
$this->assert_same( $results, sprintf('%s: Same value %s', $meta_key, $single ? 'single' : 'multi' ) );
|
179 |
-
|
180 |
-
}
|
181 |
-
}
|
182 |
-
}
|
183 |
-
|
184 |
-
protected function execute_test_for_product( $product ) {
|
185 |
-
$wrap_leg = WJECF_WC()->wrap( $product, false ); $wrap_leg->use_wc27 = false;
|
186 |
-
$wrap_new = WJECF_WC()->wrap( $product, false ); $wrap_new->use_wc27 = true;
|
187 |
-
|
188 |
-
if ($product instanceof WC_Product_Variation) {
|
189 |
-
$results = array();
|
190 |
-
$results['new'] = $wrap_new->get_product_or_variation_id();
|
191 |
-
$results['legacy'] = $wrap_leg->get_product_or_variation_id();
|
192 |
-
$results['old'] = $product->variation_id;
|
193 |
-
$this->assert_same( $results, sprintf('Same variation id %s', current( $results ) ) );
|
194 |
-
|
195 |
-
$results = array();
|
196 |
-
$results['new'] = $wrap_new->get_variable_product_id();
|
197 |
-
$results['legacy'] = $wrap_leg->get_variable_product_id();
|
198 |
-
$results['old'] = $wrap_leg->get_variable_product_id();
|
199 |
-
$this->assert_same( $results, sprintf('Same variable product (parent) id %s', current( $results ) ) );
|
200 |
-
} else {
|
201 |
-
$results = array();
|
202 |
-
$results['new'] = $wrap_new->get_id();
|
203 |
-
$results['legacy'] = $wrap_leg->get_id();
|
204 |
-
$results['old'] = $product->id;
|
205 |
-
$this->assert_same( $results, sprintf('Same product id %s', current( $results ) ) );
|
206 |
-
}
|
207 |
-
|
208 |
-
$meta_keys = array( 'total_sales', '_price', '__non_existing__');
|
209 |
-
foreach( $meta_keys as $meta_key ) {
|
210 |
-
for($i=1; $i>=0; $i--) {
|
211 |
-
$single = $i>0;
|
212 |
-
|
213 |
-
$results = array();
|
214 |
-
$results['new'] = $wrap_new->get_field( $meta_key, $single );
|
215 |
-
$results['legacy'] = $wrap_leg->get_field( $meta_key, $single );
|
216 |
-
$results['old'] = get_post_meta( $wrap_new->get_product_or_variation_id(), $meta_key, $single );
|
217 |
-
$this->assert_same( $results, sprintf('%s: Same value %s. %s', $meta_key, $single ? 'single' : 'multi', $this->dd( current( $results ) ) ) );
|
218 |
-
|
219 |
-
}
|
220 |
-
}
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
}
|
226 |
-
|
227 |
-
protected $tests = 0;
|
228 |
-
protected $fails = 0;
|
229 |
-
protected $passess = 0;
|
230 |
-
|
231 |
-
protected function assert( $true, $test_description ) {
|
232 |
-
if ( $true !== true ) {
|
233 |
-
WP_CLI::error( $test_description );
|
234 |
-
die();
|
235 |
-
}
|
236 |
-
WP_CLI::success( $test_description );
|
237 |
-
}
|
238 |
-
|
239 |
-
protected function assert_same( $results, $test_description ) {
|
240 |
-
$success = true;
|
241 |
-
foreach( $results as $result ) {
|
242 |
-
if ( isset( $prev_result ) && $result !== $prev_result ) {
|
243 |
-
$success = false;
|
244 |
-
break;
|
245 |
-
}
|
246 |
-
$prev_result = $result;
|
247 |
-
}
|
248 |
-
|
249 |
-
$this->tests++;
|
250 |
-
|
251 |
-
if ( $success ) {
|
252 |
-
$this->passes++;
|
253 |
-
WP_CLI::success( $test_description );
|
254 |
-
} else {
|
255 |
-
$this->fails++;
|
256 |
-
foreach( $results as $key => $result ) {
|
257 |
-
WP_CLI::log( sprintf("%s : %s", $key, $this->dd( $result ) ) );
|
258 |
-
}
|
259 |
-
WP_CLI::error( $test_description );
|
260 |
-
}
|
261 |
-
}
|
262 |
-
|
263 |
-
protected function dd( $variable ) {
|
264 |
-
return print_r( $variable, true );
|
265 |
-
}
|
266 |
-
|
267 |
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
defined('ABSPATH') or die();
|
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 |
+
/**
|
21 |
+
* Test API functions for one or more coupons
|
22 |
+
*
|
23 |
+
* ## OPTIONS
|
24 |
+
*
|
25 |
+
* [couponcode, ...]
|
26 |
+
* : The coupon codes for which to run the tests. If omitted the test will be executed for all auto coupons.
|
27 |
+
*
|
28 |
+
* @param array $args CLI arguments
|
29 |
+
*/
|
30 |
+
public function test_api( $args ) {
|
31 |
+
require_once( 'pro/wjecf-pro-api-example.php' );
|
32 |
+
|
33 |
+
if ( count( $args ) > 0 ) {
|
34 |
+
$all = $args;
|
35 |
+
} else {
|
36 |
+
$all = WJECF_API()->get_all_auto_coupons();
|
37 |
+
}
|
38 |
+
|
39 |
+
foreach( $all as $coupon ) {
|
40 |
+
$values = WJECF_API_Test_Coupon( $coupon );
|
41 |
+
foreach( $values as $key => $value ) {
|
42 |
+
WP_CLI::log( sprintf( "%s: %s", $key, print_r( $value, true ) ) );
|
43 |
+
}
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Check whether the customer has ordered before.
|
49 |
+
*
|
50 |
+
* ## OPTIONS
|
51 |
+
*
|
52 |
+
* <customer>
|
53 |
+
* : The email-address or userid of the customer
|
54 |
+
*
|
55 |
+
* @param array $args CLI arguments
|
56 |
+
*/
|
57 |
+
public function test_first_order( $args )
|
58 |
+
{
|
59 |
+
if ( count( $args ) <= 0 ) {
|
60 |
+
WP_CLI::error( sprintf("Please provide an email-address" ) );
|
61 |
+
return;
|
62 |
+
}
|
63 |
+
$customer = $args[0];
|
64 |
+
$is_first = ! WJECF()->has_customer_ordered_before( $customer );
|
65 |
+
WP_CLI::log( sprintf("First order for %s: %s", $customer, $is_first ? 'yes' : 'no' ) );
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Test the sanitizers
|
70 |
+
*/
|
71 |
+
public function test_sanitizer() {
|
72 |
+
$array_tests = array(
|
73 |
+
array(),
|
74 |
+
array(0),
|
75 |
+
array(1,0,2.0,"3")
|
76 |
+
);
|
77 |
+
foreach( $array_tests as $array ) {
|
78 |
+
$comma = join( ',', $array );
|
79 |
+
$ints_array = array_map( 'intval', $array);
|
80 |
+
$ints_comma = join( ',', $ints_array );
|
81 |
+
|
82 |
+
$this->single_test_sanitizer( $comma, 'int[]', $ints_array );
|
83 |
+
$this->single_test_sanitizer( $array, 'int[]', $ints_array );
|
84 |
+
|
85 |
+
$this->single_test_sanitizer( $comma, 'int,', $ints_comma );
|
86 |
+
$this->single_test_sanitizer( $array, 'int,', $ints_comma );
|
87 |
+
}
|
88 |
+
|
89 |
+
$this->single_test_sanitizer( null, 'int[]', array() );
|
90 |
+
|
91 |
+
$this->single_test_sanitizer( null, 'int,', '' );
|
92 |
+
$this->single_test_sanitizer( '', 'int,', '' );
|
93 |
+
|
94 |
+
$this->single_test_sanitizer( null, 'int', null );
|
95 |
+
$this->single_test_sanitizer( '', 'int', null );
|
96 |
+
$this->single_test_sanitizer( '1.234', 'int', 1 );
|
97 |
+
|
98 |
+
$this->single_test_sanitizer( '1.234', 'decimal', '1.234' );
|
99 |
+
$this->single_test_sanitizer( null, 'decimal', null );
|
100 |
+
}
|
101 |
+
|
102 |
+
private function single_test_sanitizer( $value, $rule, $expected ) {
|
103 |
+
//$msg = sprintf( "Sanitized %s: %s to %s", $rule, print_r( $value, true ), print_r( $expected, true ) );
|
104 |
+
$msg = sprintf(
|
105 |
+
"Sanitized %s: %s to %s",
|
106 |
+
$rule, $value === null ? 'null' : $value,
|
107 |
+
$expected === null ? 'null' : $expected
|
108 |
+
);
|
109 |
+
$this->assert( WJECF()->sanitizer()->sanitize( $value, $rule ) === $expected, $msg);
|
110 |
+
|
111 |
+
}
|
112 |
+
/**
|
113 |
+
* Tests if the wrappers return the same values for WooCommerce 3.0 and older WC versions
|
114 |
+
*/
|
115 |
+
public function test_wrappers() {
|
116 |
+
|
117 |
+
$args = array(
|
118 |
+
'posts_per_page' => -1,
|
119 |
+
'orderby' => 'title',
|
120 |
+
'order' => 'asc',
|
121 |
+
'post_type' => 'shop_coupon',
|
122 |
+
'post_status' => 'publish',
|
123 |
+
);
|
124 |
+
$posts = get_posts( $args );
|
125 |
+
foreach ( $posts as $post ) {
|
126 |
+
$coupon = WJECF_WC()->get_coupon( $post->ID );
|
127 |
+
$this->execute_test_for_coupon( $coupon );
|
128 |
+
}
|
129 |
+
|
130 |
+
$args = array(
|
131 |
+
'posts_per_page' => -1,
|
132 |
+
'orderby' => 'title',
|
133 |
+
'order' => 'asc',
|
134 |
+
'post_type' => array( 'product', 'product_variation' ),
|
135 |
+
'post_status' => 'publish',
|
136 |
+
);
|
137 |
+
$posts = get_posts( $args );
|
138 |
+
foreach ( $posts as $post ) {
|
139 |
+
$product = wc_get_product( $post->ID );
|
140 |
+
$this->execute_test_for_product( $product );
|
141 |
+
}
|
142 |
+
|
143 |
+
$msg = sprintf("%d tests executed. Fails: %d Passes: %d", $this->tests, $this->fails, $this->passes );
|
144 |
+
if ( $this->fails != 0 )
|
145 |
+
WP_CLI::error( $msg );
|
146 |
+
else
|
147 |
+
WP_CLI::success( $msg );
|
148 |
+
|
149 |
+
}
|
150 |
+
|
151 |
+
protected function execute_test_for_coupon( $coupon ) {
|
152 |
+
//WP_CLI::log( sprintf("Coupon fields: %s", print_r( $coupon->coupon_custom_fields ) ) );
|
153 |
+
//WP_CLI::log( sprintf("Coupon fields: %s", print_r( $coupon->get_meta_data() ) ) );
|
154 |
+
|
155 |
+
$meta_keys = array_keys( $coupon->coupon_custom_fields );
|
156 |
+
$meta_keys[] = '__non_existing__';
|
157 |
+
|
158 |
+
//WP_CLI::log( sprintf("Coupon fields: %s", print_r( $coupon->coupon_custom_fields ) ) );
|
159 |
+
//WP_CLI::log( sprintf("Coupon fields: %s", print_r( $coupon->get_meta_data() ) ) );
|
160 |
+
|
161 |
+
$wrap_leg = WJECF_WC()->wrap( $coupon, false ); $wrap_leg->use_wc27 = false;
|
162 |
+
$wrap_new = WJECF_WC()->wrap( $coupon, false ); $wrap_new->use_wc27 = true;
|
163 |
+
|
164 |
+
$results = array();
|
165 |
+
$results['new'] = $wrap_new->get_id();
|
166 |
+
$results['legacy'] = $wrap_leg->get_id();
|
167 |
+
$results['old'] = $coupon->id;
|
168 |
+
$this->assert_same( $results, sprintf('Same coupon id %s', current( $results ) ) );
|
169 |
+
|
170 |
+
foreach( $meta_keys as $meta_key ) {
|
171 |
+
for($i=1; $i>=0; $i--) {
|
172 |
+
$single = $i>0;
|
173 |
+
|
174 |
+
$results = array();
|
175 |
+
$results['new'] = $wrap_new->get_meta( $meta_key, $single );
|
176 |
+
$results['legacy'] = $wrap_leg->get_meta( $meta_key, $single );
|
177 |
+
$results['old'] = get_post_meta( $coupon->id, $meta_key, $single );
|
178 |
+
$this->assert_same( $results, sprintf('%s: Same value %s', $meta_key, $single ? 'single' : 'multi' ) );
|
179 |
+
|
180 |
+
}
|
181 |
+
}
|
182 |
+
}
|
183 |
+
|
184 |
+
protected function execute_test_for_product( $product ) {
|
185 |
+
$wrap_leg = WJECF_WC()->wrap( $product, false ); $wrap_leg->use_wc27 = false;
|
186 |
+
$wrap_new = WJECF_WC()->wrap( $product, false ); $wrap_new->use_wc27 = true;
|
187 |
+
|
188 |
+
if ($product instanceof WC_Product_Variation) {
|
189 |
+
$results = array();
|
190 |
+
$results['new'] = $wrap_new->get_product_or_variation_id();
|
191 |
+
$results['legacy'] = $wrap_leg->get_product_or_variation_id();
|
192 |
+
$results['old'] = $product->variation_id;
|
193 |
+
$this->assert_same( $results, sprintf('Same variation id %s', current( $results ) ) );
|
194 |
+
|
195 |
+
$results = array();
|
196 |
+
$results['new'] = $wrap_new->get_variable_product_id();
|
197 |
+
$results['legacy'] = $wrap_leg->get_variable_product_id();
|
198 |
+
$results['old'] = $wrap_leg->get_variable_product_id();
|
199 |
+
$this->assert_same( $results, sprintf('Same variable product (parent) id %s', current( $results ) ) );
|
200 |
+
} else {
|
201 |
+
$results = array();
|
202 |
+
$results['new'] = $wrap_new->get_id();
|
203 |
+
$results['legacy'] = $wrap_leg->get_id();
|
204 |
+
$results['old'] = $product->id;
|
205 |
+
$this->assert_same( $results, sprintf('Same product id %s', current( $results ) ) );
|
206 |
+
}
|
207 |
+
|
208 |
+
$meta_keys = array( 'total_sales', '_price', '__non_existing__');
|
209 |
+
foreach( $meta_keys as $meta_key ) {
|
210 |
+
for($i=1; $i>=0; $i--) {
|
211 |
+
$single = $i>0;
|
212 |
+
|
213 |
+
$results = array();
|
214 |
+
$results['new'] = $wrap_new->get_field( $meta_key, $single );
|
215 |
+
$results['legacy'] = $wrap_leg->get_field( $meta_key, $single );
|
216 |
+
$results['old'] = get_post_meta( $wrap_new->get_product_or_variation_id(), $meta_key, $single );
|
217 |
+
$this->assert_same( $results, sprintf('%s: Same value %s. %s', $meta_key, $single ? 'single' : 'multi', $this->dd( current( $results ) ) ) );
|
218 |
+
|
219 |
+
}
|
220 |
+
}
|
221 |
+
|
222 |
+
|
223 |
+
|
224 |
+
|
225 |
+
}
|
226 |
+
|
227 |
+
protected $tests = 0;
|
228 |
+
protected $fails = 0;
|
229 |
+
protected $passess = 0;
|
230 |
+
|
231 |
+
protected function assert( $true, $test_description ) {
|
232 |
+
if ( $true !== true ) {
|
233 |
+
WP_CLI::error( $test_description );
|
234 |
+
die();
|
235 |
+
}
|
236 |
+
WP_CLI::success( $test_description );
|
237 |
+
}
|
238 |
+
|
239 |
+
protected function assert_same( $results, $test_description ) {
|
240 |
+
$success = true;
|
241 |
+
foreach( $results as $result ) {
|
242 |
+
if ( isset( $prev_result ) && $result !== $prev_result ) {
|
243 |
+
$success = false;
|
244 |
+
break;
|
245 |
+
}
|
246 |
+
$prev_result = $result;
|
247 |
+
}
|
248 |
+
|
249 |
+
$this->tests++;
|
250 |
+
|
251 |
+
if ( $success ) {
|
252 |
+
$this->passes++;
|
253 |
+
WP_CLI::success( $test_description );
|
254 |
+
} else {
|
255 |
+
$this->fails++;
|
256 |
+
foreach( $results as $key => $result ) {
|
257 |
+
WP_CLI::log( sprintf("%s : %s", $key, $this->dd( $result ) ) );
|
258 |
+
}
|
259 |
+
WP_CLI::error( $test_description );
|
260 |
+
}
|
261 |
+
}
|
262 |
+
|
263 |
+
protected function dd( $variable ) {
|
264 |
+
return print_r( $variable, true );
|
265 |
+
}
|
266 |
+
|
267 |
}
|
includes/WJECF_Options.php
CHANGED
@@ -1,99 +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 ( ! is_array( $options ) || empty ( $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 |
}
|
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 ( ! is_array( $options ) || empty ( $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
CHANGED
@@ -1,72 +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 |
}
|
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
CHANGED
@@ -1,417 +1,417 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
defined('ABSPATH') or die();
|
4 |
-
|
5 |
-
/**
|
6 |
-
*
|
7 |
-
* Interface to WooCommerce. Handles version differences / backwards compatibility.
|
8 |
-
*
|
9 |
-
* @since 2.3.7.2
|
10 |
-
*/
|
11 |
-
class WJECF_WC {
|
12 |
-
|
13 |
-
protected $wrappers = array();
|
14 |
-
|
15 |
-
/**
|
16 |
-
* Wrap a data object (WC 2.7 introduced WC_Data)
|
17 |
-
* @param type $object
|
18 |
-
* @return type
|
19 |
-
*/
|
20 |
-
public function wrap( $object, $use_pool = true ) {
|
21 |
-
if ( $use_pool ) {
|
22 |
-
//Prevent a huge amount of wrappers to be initiated; one wrapper per object instance should do the trick
|
23 |
-
foreach( $this->wrappers as $wrapper ) {
|
24 |
-
if ($wrapper->holds( $object ) ) {
|
25 |
-
//error_log('Reusing wrapper ' . get_class( $object ) );
|
26 |
-
return $wrapper;
|
27 |
-
}
|
28 |
-
}
|
29 |
-
}
|
30 |
-
|
31 |
-
if ( is_numeric( $object ) ) {
|
32 |
-
$post_type = get_post_type( $object );
|
33 |
-
if ( $post_type == 'shop_coupon' ) {
|
34 |
-
$object = WJECF_WC()->get_coupon( $object );
|
35 |
-
} elseif ( $post_type == 'product' ) {
|
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 ) {
|
45 |
-
return $this->wrappers[] = new WJECF_Wrap_Coupon( $object );
|
46 |
-
}
|
47 |
-
|
48 |
-
if ( $object instanceof WC_Customer ) {
|
49 |
-
return $this->wrappers[] = new WJECF_Wrap_Customer( $object );
|
50 |
-
}
|
51 |
-
|
52 |
-
if ( $object instanceof WC_Product ) {
|
53 |
-
return $this->wrappers[] = new WJECF_Wrap_Product( $object );
|
54 |
-
}
|
55 |
-
|
56 |
-
throw new Exception( 'Cannot wrap ' . get_class( $object ) );
|
57 |
-
}
|
58 |
-
|
59 |
-
/**
|
60 |
-
* Returns an array of items like stored in WC_Discounts since WC3.2.0
|
61 |
-
*
|
62 |
-
* Note: $item->price is in cents; use wc_remove_number_precision( $item->price ) to compare it to the actual amount
|
63 |
-
*
|
64 |
-
* $item->key = $key;
|
65 |
-
* $item->object = $cart_item;
|
66 |
-
* $item->product = $cart_item['data'];
|
67 |
-
* $item->quantity = $cart_item['quantity'];
|
68 |
-
* $item->price = self::wc_add_number_precision_deep( $item->product->get_price() ) * $item->quantity;
|
69 |
-
*
|
70 |
-
* @param WC_Discounts|null $wc_discounts
|
71 |
-
* @return array of items (stdClass)
|
72 |
-
*/
|
73 |
-
public function get_discount_items( $wc_discounts = null ) {
|
74 |
-
if ( $wc_discounts == null ) {
|
75 |
-
require_once( 'WJECF_WC_Discounts.php' );
|
76 |
-
$wc_discounts = new WJECF_WC_Discounts( WC()->cart );
|
77 |
-
}
|
78 |
-
return $wc_discounts->get_items();
|
79 |
-
}
|
80 |
-
|
81 |
-
/**
|
82 |
-
* Convert a cart_item to an item as generated by WC_Discounts
|
83 |
-
*
|
84 |
-
* @since 2.6.0
|
85 |
-
*/
|
86 |
-
public function cart_item_to_discount_item( $cart_item, $key = null ) {
|
87 |
-
$item = new stdClass();
|
88 |
-
$item->key = $key === null && isset( $cart_item['key'] ) ? $cart_item['key'] : $key; //Note: might yield null
|
89 |
-
$item->object = $cart_item;
|
90 |
-
$item->product = $cart_item['data'];
|
91 |
-
$item->quantity = $cart_item['quantity'];
|
92 |
-
$item->price = $this->wc_add_number_precision_deep( $item->product->get_price() ) * $item->quantity;
|
93 |
-
return $item;
|
94 |
-
}
|
95 |
-
|
96 |
-
/**
|
97 |
-
* Add precision to an array of number and return an array of int.
|
98 |
-
*
|
99 |
-
* @since 2.6.0 (taken from WC 3.2.3)
|
100 |
-
* @param array $value Number to add precision to.
|
101 |
-
* @return int
|
102 |
-
*/
|
103 |
-
public function wc_add_number_precision_deep( $value ) {
|
104 |
-
if ( function_exists( 'wc_add_number_precision_deep' ) ) return wc_add_number_precision_deep( $value );
|
105 |
-
|
106 |
-
if ( is_array( $value ) ) {
|
107 |
-
foreach ( $value as $key => $subvalue ) {
|
108 |
-
$value[ $key ] = $this->wc_add_number_precision_deep( $subvalue );
|
109 |
-
}
|
110 |
-
} else {
|
111 |
-
$value = $this->wc_add_number_precision( $value );
|
112 |
-
}
|
113 |
-
return $value;
|
114 |
-
}
|
115 |
-
|
116 |
-
/**
|
117 |
-
* Add precision to a number and return an int.
|
118 |
-
*
|
119 |
-
* @since 2.6.0 (taken from WC 3.2.3)
|
120 |
-
* @param float $value Number to add precision to.
|
121 |
-
* @return int
|
122 |
-
*/
|
123 |
-
public function wc_add_number_precision( $value ) {
|
124 |
-
if ( function_exists( 'wc_add_number_precision' ) ) return wc_add_number_precision( $value );
|
125 |
-
|
126 |
-
$precision = pow( 10, wc_get_price_decimals() ); //Since WC 2.3.0
|
127 |
-
return intval( round( $value * $precision ) );
|
128 |
-
}
|
129 |
-
|
130 |
-
/**
|
131 |
-
* Remove precision from a number and return a float.
|
132 |
-
*
|
133 |
-
* @since 2.6.0 (taken from WC 3.2.3)
|
134 |
-
* @param float $value Number to add precision to.
|
135 |
-
* @return float
|
136 |
-
*/
|
137 |
-
public function wc_remove_number_precision( $value ) {
|
138 |
-
if ( function_exists( 'wc_remove_number_precision' ) ) return wc_remove_number_precision( $value );
|
139 |
-
|
140 |
-
$precision = pow( 10, wc_get_price_decimals() ); //Since WC 2.3.0
|
141 |
-
return $value / $precision;
|
142 |
-
}
|
143 |
-
|
144 |
-
|
145 |
-
/**
|
146 |
-
* Returns a specific item in the cart.
|
147 |
-
*
|
148 |
-
* @param string $cart_item_key Cart item key.
|
149 |
-
* @return array Item data
|
150 |
-
*/
|
151 |
-
public function get_cart_item( $cart_item_key ) {
|
152 |
-
if ( $this->check_woocommerce_version('2.2.9') ) {
|
153 |
-
return WC()->cart->get_cart_item( $cart_item_key );
|
154 |
-
}
|
155 |
-
|
156 |
-
return isset( WC()->cart->cart_contents[ $cart_item_key ] ) ? WC()->cart->cart_contents[ $cart_item_key ] : array();
|
157 |
-
}
|
158 |
-
|
159 |
-
/**
|
160 |
-
* Get categories of a product (and anchestors)
|
161 |
-
* @param int $product_id
|
162 |
-
* @return array product_cat_ids
|
163 |
-
*/
|
164 |
-
public function wc_get_product_cat_ids( $product_id ) {
|
165 |
-
//Since WC 2.5.0
|
166 |
-
if ( function_exists( 'wc_get_product_cat_ids' ) ) {
|
167 |
-
return wc_get_product_cat_ids( $product_id );
|
168 |
-
}
|
169 |
-
|
170 |
-
$product_cats = wp_get_post_terms( $product_id, 'product_cat', array( "fields" => "ids" ) );
|
171 |
-
|
172 |
-
foreach ( $product_cats as $product_cat ) {
|
173 |
-
$product_cats = array_merge( $product_cats, get_ancestors( $product_cat, 'product_cat' ) );
|
174 |
-
}
|
175 |
-
return $product_cats;
|
176 |
-
}
|
177 |
-
|
178 |
-
/**
|
179 |
-
* Coupon types that apply to individual products. Controls which validation rules will apply.
|
180 |
-
*
|
181 |
-
* @since 2.5.0
|
182 |
-
* @return array
|
183 |
-
*/
|
184 |
-
public function wc_get_product_coupon_types() {
|
185 |
-
//Since WC 2.5.0
|
186 |
-
if ( function_exists( 'wc_get_product_coupon_types' ) ) {
|
187 |
-
return wc_get_product_coupon_types();
|
188 |
-
}
|
189 |
-
return array( 'fixed_product', 'percent_product' );
|
190 |
-
}
|
191 |
-
|
192 |
-
public function wc_get_cart_coupon_types() {
|
193 |
-
//Since WC 2.5.0
|
194 |
-
if ( function_exists( 'wc_get_cart_coupon_types' ) ) {
|
195 |
-
return wc_get_cart_coupon_types();
|
196 |
-
}
|
197 |
-
return array( 'fixed_cart', 'percent' );
|
198 |
-
}
|
199 |
-
|
200 |
-
/**
|
201 |
-
* Output a list of variation attributes for use in the cart forms.
|
202 |
-
*
|
203 |
-
* @param array $args
|
204 |
-
* @since 2.5.1
|
205 |
-
*/
|
206 |
-
public function wc_dropdown_variation_attribute_options( $args = array() ) {
|
207 |
-
if ( function_exists( 'wc_dropdown_variation_attribute_options' ) ) {
|
208 |
-
return wc_dropdown_variation_attribute_options( $args );
|
209 |
-
}
|
210 |
-
|
211 |
-
//Copied from WC2.4.0 wc-template-functions.php
|
212 |
-
$args = wp_parse_args( $args, array(
|
213 |
-
'options' => false,
|
214 |
-
'attribute' => false,
|
215 |
-
'product' => false,
|
216 |
-
'selected' => false,
|
217 |
-
'name' => '',
|
218 |
-
'id' => '',
|
219 |
-
'show_option_none' => __( 'Choose an option', 'woocommerce' )
|
220 |
-
) );
|
221 |
-
|
222 |
-
$options = $args['options'];
|
223 |
-
$product = $args['product'];
|
224 |
-
$attribute = $args['attribute'];
|
225 |
-
$name = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute );
|
226 |
-
$id = $args['id'] ? $args['id'] : sanitize_title( $attribute );
|
227 |
-
|
228 |
-
if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
|
229 |
-
$attributes = $product->get_variation_attributes();
|
230 |
-
$options = $attributes[ $attribute ];
|
231 |
-
}
|
232 |
-
|
233 |
-
echo '<select id="' . esc_attr( $id ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '">';
|
234 |
-
|
235 |
-
if ( $args['show_option_none'] ) {
|
236 |
-
echo '<option value="">' . esc_html( $args['show_option_none'] ) . '</option>';
|
237 |
-
}
|
238 |
-
|
239 |
-
if ( ! empty( $options ) ) {
|
240 |
-
if ( $product && taxonomy_exists( $attribute ) ) {
|
241 |
-
// Get terms if this is a taxonomy - ordered. We need the names too.
|
242 |
-
$terms = wc_get_product_terms( $product->id, $attribute, array( 'fields' => 'all' ) );
|
243 |
-
|
244 |
-
foreach ( $terms as $term ) {
|
245 |
-
if ( in_array( $term->slug, $options ) ) {
|
246 |
-
echo '<option value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $args['selected'] ), $term->slug, false ) . '>' . apply_filters( 'woocommerce_variation_option_name', $term->name ) . '</option>';
|
247 |
-
}
|
248 |
-
}
|
249 |
-
} else {
|
250 |
-
foreach ( $options as $option ) {
|
251 |
-
// This handles < 2.4.0 bw compatibility where text attributes were not sanitized.
|
252 |
-
$selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false );
|
253 |
-
echo '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>';
|
254 |
-
}
|
255 |
-
}
|
256 |
-
}
|
257 |
-
|
258 |
-
echo '</select>';
|
259 |
-
}
|
260 |
-
|
261 |
-
/**
|
262 |
-
* Get attibutes/data for an individual variation from the database and maintain its integrity.
|
263 |
-
* @since 2.5.1
|
264 |
-
* @param int $variation_id
|
265 |
-
* @return array
|
266 |
-
*/
|
267 |
-
public function wc_get_product_variation_attributes( $variation_id ) {
|
268 |
-
if ( function_exists( 'wc_get_product_variation_attributes' ) ) {
|
269 |
-
return wc_get_product_variation_attributes( $variation_id );
|
270 |
-
}
|
271 |
-
|
272 |
-
//Copied from WC2.4.0 wc-product-functions.php
|
273 |
-
|
274 |
-
// Build variation data from meta
|
275 |
-
$all_meta = get_post_meta( $variation_id );
|
276 |
-
$parent_id = wp_get_post_parent_id( $variation_id );
|
277 |
-
$parent_attributes = array_filter( (array) get_post_meta( $parent_id, '_product_attributes', true ) );
|
278 |
-
$found_parent_attributes = array();
|
279 |
-
$variation_attributes = array();
|
280 |
-
|
281 |
-
// Compare to parent variable product attributes and ensure they match
|
282 |
-
foreach ( $parent_attributes as $attribute_name => $options ) {
|
283 |
-
$attribute = 'attribute_' . sanitize_title( $attribute_name );
|
284 |
-
$found_parent_attributes[] = $attribute;
|
285 |
-
if ( ! array_key_exists( $attribute, $variation_attributes ) ) {
|
286 |
-
$variation_attributes[ $attribute ] = ''; // Add it - 'any' will be asumed
|
287 |
-
}
|
288 |
-
}
|
289 |
-
|
290 |
-
// Get the variation attributes from meta
|
291 |
-
foreach ( $all_meta as $name => $value ) {
|
292 |
-
// Only look at valid attribute meta, and also compare variation level attributes and remove any which do not exist at parent level
|
293 |
-
if ( 0 !== strpos( $name, 'attribute_' ) || ! in_array( $name, $found_parent_attributes ) ) {
|
294 |
-
unset( $variation_attributes[ $name ] );
|
295 |
-
continue;
|
296 |
-
}
|
297 |
-
/**
|
298 |
-
* Pre 2.4 handling where 'slugs' were saved instead of the full text attribute.
|
299 |
-
* Attempt to get full version of the text attribute from the parent.
|
300 |
-
*/
|
301 |
-
if ( sanitize_title( $value[0] ) === $value[0] && version_compare( get_post_meta( $parent_id, '_product_version', true ), '2.4.0', '<' ) ) {
|
302 |
-
foreach ( $parent_attributes as $attribute ) {
|
303 |
-
if ( $name !== 'attribute_' . sanitize_title( $attribute['name'] ) ) {
|
304 |
-
continue;
|
305 |
-
}
|
306 |
-
$text_attributes = wc_get_text_attributes( $attribute['value'] );
|
307 |
-
|
308 |
-
foreach ( $text_attributes as $text_attribute ) {
|
309 |
-
if ( sanitize_title( $text_attribute ) === $value[0] ) {
|
310 |
-
$value[0] = $text_attribute;
|
311 |
-
break;
|
312 |
-
}
|
313 |
-
}
|
314 |
-
}
|
315 |
-
}
|
316 |
-
|
317 |
-
$variation_attributes[ $name ] = $value[0];
|
318 |
-
}
|
319 |
-
|
320 |
-
return $variation_attributes;
|
321 |
-
}
|
322 |
-
|
323 |
-
public function find_matching_product_variation( $product, $match_attributes = array() ) {
|
324 |
-
if ( $this->check_woocommerce_version( '3.0') ) {
|
325 |
-
$data_store = WC_Data_Store::load( 'product' );
|
326 |
-
$variation_id = $data_store->find_matching_product_variation( $product, $match_attributes );
|
327 |
-
return $variation_id;
|
328 |
-
}
|
329 |
-
|
330 |
-
return $product->get_matching_variation( $match_attributes );
|
331 |
-
}
|
332 |
-
|
333 |
-
/**
|
334 |
-
* @since 2.4.0 for WC 2.7 compatibility
|
335 |
-
*
|
336 |
-
* Get a WC_Coupon object
|
337 |
-
* @param WC_Coupon|string|WP_Post $coupon The coupon code or a WC_Coupon object
|
338 |
-
* @return WC_Coupon The coupon object
|
339 |
-
*/
|
340 |
-
public function get_coupon( $coupon ) {
|
341 |
-
if ( $coupon instanceof WP_Post ) {
|
342 |
-
$coupon = $coupon->ID;
|
343 |
-
}
|
344 |
-
if ( is_numeric( $coupon ) && ! $this->check_woocommerce_version( '3.0' ) ) {
|
345 |
-
//By id; not neccesary for WC3.0; as the WC_Coupon constructor accepts an id
|
346 |
-
global $wpdb;
|
347 |
-
$coupon_code = $wpdb->get_var( $wpdb->prepare( "SELECT post_title FROM $wpdb->posts WHERE id = %d AND post_type = 'shop_coupon'", $coupon ) );
|
348 |
-
if ( $coupon_code !== null) {
|
349 |
-
$coupon = $coupon_code;
|
350 |
-
}
|
351 |
-
}
|
352 |
-
if ( ! ( $coupon instanceof WC_Coupon ) ) {
|
353 |
-
//By code
|
354 |
-
$coupon = new WC_Coupon( $coupon );
|
355 |
-
}
|
356 |
-
return $coupon;
|
357 |
-
}
|
358 |
-
|
359 |
-
|
360 |
-
//VERSION
|
361 |
-
|
362 |
-
/**
|
363 |
-
* Check whether WooCommerce version is greater or equal than $req_version
|
364 |
-
* @param string @req_version The version to compare to
|
365 |
-
* @return bool true if WooCommerce is at least the given version
|
366 |
-
*/
|
367 |
-
public function check_woocommerce_version( $req_version ) {
|
368 |
-
return version_compare( $this->get_woocommerce_version(), $req_version, '>=' );
|
369 |
-
}
|
370 |
-
|
371 |
-
private $wc_version = null;
|
372 |
-
|
373 |
-
/**
|
374 |
-
* Get the WooCommerce version number
|
375 |
-
* @return string|bool WC Version number or false if WC not detected
|
376 |
-
*/
|
377 |
-
public function get_woocommerce_version() {
|
378 |
-
if ( isset( $this->wc_version ) ) {
|
379 |
-
return $this->wc_version;
|
380 |
-
}
|
381 |
-
|
382 |
-
if ( defined( 'WC_VERSION' ) ) {
|
383 |
-
return $this->wc_version = WC_VERSION;
|
384 |
-
}
|
385 |
-
|
386 |
-
// If get_plugins() isn't available, require it
|
387 |
-
if ( ! function_exists( 'get_plugins' ) ) {
|
388 |
-
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
389 |
-
}
|
390 |
-
// Create the plugins folder and file variables
|
391 |
-
$plugin_folder = get_plugins( '/woocommerce' );
|
392 |
-
$plugin_file = 'woocommerce.php';
|
393 |
-
|
394 |
-
// If the plugin version number is set, return it
|
395 |
-
if ( isset( $plugin_folder[$plugin_file]['Version'] ) ) {
|
396 |
-
return $this->wc_version = $plugin_folder[$plugin_file]['Version'];
|
397 |
-
}
|
398 |
-
|
399 |
-
return $this->wc_version = false; // Not found
|
400 |
-
}
|
401 |
-
|
402 |
-
//INSTANCE
|
403 |
-
|
404 |
-
/**
|
405 |
-
* Singleton Instance
|
406 |
-
*
|
407 |
-
* @static
|
408 |
-
* @return Singleton Instance
|
409 |
-
*/
|
410 |
-
public static function instance() {
|
411 |
-
if ( is_null( self::$_instance ) ) {
|
412 |
-
self::$_instance = new self();
|
413 |
-
}
|
414 |
-
return self::$_instance;
|
415 |
-
}
|
416 |
-
protected static $_instance = null;
|
417 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
defined('ABSPATH') or die();
|
4 |
+
|
5 |
+
/**
|
6 |
+
*
|
7 |
+
* Interface to WooCommerce. Handles version differences / backwards compatibility.
|
8 |
+
*
|
9 |
+
* @since 2.3.7.2
|
10 |
+
*/
|
11 |
+
class WJECF_WC {
|
12 |
+
|
13 |
+
protected $wrappers = array();
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Wrap a data object (WC 2.7 introduced WC_Data)
|
17 |
+
* @param type $object
|
18 |
+
* @return type
|
19 |
+
*/
|
20 |
+
public function wrap( $object, $use_pool = true ) {
|
21 |
+
if ( $use_pool ) {
|
22 |
+
//Prevent a huge amount of wrappers to be initiated; one wrapper per object instance should do the trick
|
23 |
+
foreach( $this->wrappers as $wrapper ) {
|
24 |
+
if ($wrapper->holds( $object ) ) {
|
25 |
+
//error_log('Reusing wrapper ' . get_class( $object ) );
|
26 |
+
return $wrapper;
|
27 |
+
}
|
28 |
+
}
|
29 |
+
}
|
30 |
+
|
31 |
+
if ( is_numeric( $object ) ) {
|
32 |
+
$post_type = get_post_type( $object );
|
33 |
+
if ( $post_type == 'shop_coupon' ) {
|
34 |
+
$object = WJECF_WC()->get_coupon( $object );
|
35 |
+
} elseif ( $post_type == 'product' ) {
|
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 ) {
|
45 |
+
return $this->wrappers[] = new WJECF_Wrap_Coupon( $object );
|
46 |
+
}
|
47 |
+
|
48 |
+
if ( $object instanceof WC_Customer ) {
|
49 |
+
return $this->wrappers[] = new WJECF_Wrap_Customer( $object );
|
50 |
+
}
|
51 |
+
|
52 |
+
if ( $object instanceof WC_Product ) {
|
53 |
+
return $this->wrappers[] = new WJECF_Wrap_Product( $object );
|
54 |
+
}
|
55 |
+
|
56 |
+
throw new Exception( 'Cannot wrap ' . get_class( $object ) );
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Returns an array of items like stored in WC_Discounts since WC3.2.0
|
61 |
+
*
|
62 |
+
* Note: $item->price is in cents; use wc_remove_number_precision( $item->price ) to compare it to the actual amount
|
63 |
+
*
|
64 |
+
* $item->key = $key;
|
65 |
+
* $item->object = $cart_item;
|
66 |
+
* $item->product = $cart_item['data'];
|
67 |
+
* $item->quantity = $cart_item['quantity'];
|
68 |
+
* $item->price = self::wc_add_number_precision_deep( $item->product->get_price() ) * $item->quantity;
|
69 |
+
*
|
70 |
+
* @param WC_Discounts|null $wc_discounts
|
71 |
+
* @return array of items (stdClass)
|
72 |
+
*/
|
73 |
+
public function get_discount_items( $wc_discounts = null ) {
|
74 |
+
if ( $wc_discounts == null ) {
|
75 |
+
require_once( 'WJECF_WC_Discounts.php' );
|
76 |
+
$wc_discounts = new WJECF_WC_Discounts( WC()->cart );
|
77 |
+
}
|
78 |
+
return $wc_discounts->get_items();
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Convert a cart_item to an item as generated by WC_Discounts
|
83 |
+
*
|
84 |
+
* @since 2.6.0
|
85 |
+
*/
|
86 |
+
public function cart_item_to_discount_item( $cart_item, $key = null ) {
|
87 |
+
$item = new stdClass();
|
88 |
+
$item->key = $key === null && isset( $cart_item['key'] ) ? $cart_item['key'] : $key; //Note: might yield null
|
89 |
+
$item->object = $cart_item;
|
90 |
+
$item->product = $cart_item['data'];
|
91 |
+
$item->quantity = $cart_item['quantity'];
|
92 |
+
$item->price = $this->wc_add_number_precision_deep( $item->product->get_price() ) * $item->quantity;
|
93 |
+
return $item;
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Add precision to an array of number and return an array of int.
|
98 |
+
*
|
99 |
+
* @since 2.6.0 (taken from WC 3.2.3)
|
100 |
+
* @param array $value Number to add precision to.
|
101 |
+
* @return int
|
102 |
+
*/
|
103 |
+
public function wc_add_number_precision_deep( $value ) {
|
104 |
+
if ( function_exists( 'wc_add_number_precision_deep' ) ) return wc_add_number_precision_deep( $value );
|
105 |
+
|
106 |
+
if ( is_array( $value ) ) {
|
107 |
+
foreach ( $value as $key => $subvalue ) {
|
108 |
+
$value[ $key ] = $this->wc_add_number_precision_deep( $subvalue );
|
109 |
+
}
|
110 |
+
} else {
|
111 |
+
$value = $this->wc_add_number_precision( $value );
|
112 |
+
}
|
113 |
+
return $value;
|
114 |
+
}
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Add precision to a number and return an int.
|
118 |
+
*
|
119 |
+
* @since 2.6.0 (taken from WC 3.2.3)
|
120 |
+
* @param float $value Number to add precision to.
|
121 |
+
* @return int
|
122 |
+
*/
|
123 |
+
public function wc_add_number_precision( $value ) {
|
124 |
+
if ( function_exists( 'wc_add_number_precision' ) ) return wc_add_number_precision( $value );
|
125 |
+
|
126 |
+
$precision = pow( 10, wc_get_price_decimals() ); //Since WC 2.3.0
|
127 |
+
return intval( round( $value * $precision ) );
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Remove precision from a number and return a float.
|
132 |
+
*
|
133 |
+
* @since 2.6.0 (taken from WC 3.2.3)
|
134 |
+
* @param float $value Number to add precision to.
|
135 |
+
* @return float
|
136 |
+
*/
|
137 |
+
public function wc_remove_number_precision( $value ) {
|
138 |
+
if ( function_exists( 'wc_remove_number_precision' ) ) return wc_remove_number_precision( $value );
|
139 |
+
|
140 |
+
$precision = pow( 10, wc_get_price_decimals() ); //Since WC 2.3.0
|
141 |
+
return $value / $precision;
|
142 |
+
}
|
143 |
+
|
144 |
+
|
145 |
+
/**
|
146 |
+
* Returns a specific item in the cart.
|
147 |
+
*
|
148 |
+
* @param string $cart_item_key Cart item key.
|
149 |
+
* @return array Item data
|
150 |
+
*/
|
151 |
+
public function get_cart_item( $cart_item_key ) {
|
152 |
+
if ( $this->check_woocommerce_version('2.2.9') ) {
|
153 |
+
return WC()->cart->get_cart_item( $cart_item_key );
|
154 |
+
}
|
155 |
+
|
156 |
+
return isset( WC()->cart->cart_contents[ $cart_item_key ] ) ? WC()->cart->cart_contents[ $cart_item_key ] : array();
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* Get categories of a product (and anchestors)
|
161 |
+
* @param int $product_id
|
162 |
+
* @return array product_cat_ids
|
163 |
+
*/
|
164 |
+
public function wc_get_product_cat_ids( $product_id ) {
|
165 |
+
//Since WC 2.5.0
|
166 |
+
if ( function_exists( 'wc_get_product_cat_ids' ) ) {
|
167 |
+
return wc_get_product_cat_ids( $product_id );
|
168 |
+
}
|
169 |
+
|
170 |
+
$product_cats = wp_get_post_terms( $product_id, 'product_cat', array( "fields" => "ids" ) );
|
171 |
+
|
172 |
+
foreach ( $product_cats as $product_cat ) {
|
173 |
+
$product_cats = array_merge( $product_cats, get_ancestors( $product_cat, 'product_cat' ) );
|
174 |
+
}
|
175 |
+
return $product_cats;
|
176 |
+
}
|
177 |
+
|
178 |
+
/**
|
179 |
+
* Coupon types that apply to individual products. Controls which validation rules will apply.
|
180 |
+
*
|
181 |
+
* @since 2.5.0
|
182 |
+
* @return array
|
183 |
+
*/
|
184 |
+
public function wc_get_product_coupon_types() {
|
185 |
+
//Since WC 2.5.0
|
186 |
+
if ( function_exists( 'wc_get_product_coupon_types' ) ) {
|
187 |
+
return wc_get_product_coupon_types();
|
188 |
+
}
|
189 |
+
return array( 'fixed_product', 'percent_product' );
|
190 |
+
}
|
191 |
+
|
192 |
+
public function wc_get_cart_coupon_types() {
|
193 |
+
//Since WC 2.5.0
|
194 |
+
if ( function_exists( 'wc_get_cart_coupon_types' ) ) {
|
195 |
+
return wc_get_cart_coupon_types();
|
196 |
+
}
|
197 |
+
return array( 'fixed_cart', 'percent' );
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Output a list of variation attributes for use in the cart forms.
|
202 |
+
*
|
203 |
+
* @param array $args
|
204 |
+
* @since 2.5.1
|
205 |
+
*/
|
206 |
+
public function wc_dropdown_variation_attribute_options( $args = array() ) {
|
207 |
+
if ( function_exists( 'wc_dropdown_variation_attribute_options' ) ) {
|
208 |
+
return wc_dropdown_variation_attribute_options( $args );
|
209 |
+
}
|
210 |
+
|
211 |
+
//Copied from WC2.4.0 wc-template-functions.php
|
212 |
+
$args = wp_parse_args( $args, array(
|
213 |
+
'options' => false,
|
214 |
+
'attribute' => false,
|
215 |
+
'product' => false,
|
216 |
+
'selected' => false,
|
217 |
+
'name' => '',
|
218 |
+
'id' => '',
|
219 |
+
'show_option_none' => __( 'Choose an option', 'woocommerce' )
|
220 |
+
) );
|
221 |
+
|
222 |
+
$options = $args['options'];
|
223 |
+
$product = $args['product'];
|
224 |
+
$attribute = $args['attribute'];
|
225 |
+
$name = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute );
|
226 |
+
$id = $args['id'] ? $args['id'] : sanitize_title( $attribute );
|
227 |
+
|
228 |
+
if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
|
229 |
+
$attributes = $product->get_variation_attributes();
|
230 |
+
$options = $attributes[ $attribute ];
|
231 |
+
}
|
232 |
+
|
233 |
+
echo '<select id="' . esc_attr( $id ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '">';
|
234 |
+
|
235 |
+
if ( $args['show_option_none'] ) {
|
236 |
+
echo '<option value="">' . esc_html( $args['show_option_none'] ) . '</option>';
|
237 |
+
}
|
238 |
+
|
239 |
+
if ( ! empty( $options ) ) {
|
240 |
+
if ( $product && taxonomy_exists( $attribute ) ) {
|
241 |
+
// Get terms if this is a taxonomy - ordered. We need the names too.
|
242 |
+
$terms = wc_get_product_terms( $product->id, $attribute, array( 'fields' => 'all' ) );
|
243 |
+
|
244 |
+
foreach ( $terms as $term ) {
|
245 |
+
if ( in_array( $term->slug, $options ) ) {
|
246 |
+
echo '<option value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $args['selected'] ), $term->slug, false ) . '>' . apply_filters( 'woocommerce_variation_option_name', $term->name ) . '</option>';
|
247 |
+
}
|
248 |
+
}
|
249 |
+
} else {
|
250 |
+
foreach ( $options as $option ) {
|
251 |
+
// This handles < 2.4.0 bw compatibility where text attributes were not sanitized.
|
252 |
+
$selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false );
|
253 |
+
echo '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>';
|
254 |
+
}
|
255 |
+
}
|
256 |
+
}
|
257 |
+
|
258 |
+
echo '</select>';
|
259 |
+
}
|
260 |
+
|
261 |
+
/**
|
262 |
+
* Get attibutes/data for an individual variation from the database and maintain its integrity.
|
263 |
+
* @since 2.5.1
|
264 |
+
* @param int $variation_id
|
265 |
+
* @return array
|
266 |
+
*/
|
267 |
+
public function wc_get_product_variation_attributes( $variation_id ) {
|
268 |
+
if ( function_exists( 'wc_get_product_variation_attributes' ) ) {
|
269 |
+
return wc_get_product_variation_attributes( $variation_id );
|
270 |
+
}
|
271 |
+
|
272 |
+
//Copied from WC2.4.0 wc-product-functions.php
|
273 |
+
|
274 |
+
// Build variation data from meta
|
275 |
+
$all_meta = get_post_meta( $variation_id );
|
276 |
+
$parent_id = wp_get_post_parent_id( $variation_id );
|
277 |
+
$parent_attributes = array_filter( (array) get_post_meta( $parent_id, '_product_attributes', true ) );
|
278 |
+
$found_parent_attributes = array();
|
279 |
+
$variation_attributes = array();
|
280 |
+
|
281 |
+
// Compare to parent variable product attributes and ensure they match
|
282 |
+
foreach ( $parent_attributes as $attribute_name => $options ) {
|
283 |
+
$attribute = 'attribute_' . sanitize_title( $attribute_name );
|
284 |
+
$found_parent_attributes[] = $attribute;
|
285 |
+
if ( ! array_key_exists( $attribute, $variation_attributes ) ) {
|
286 |
+
$variation_attributes[ $attribute ] = ''; // Add it - 'any' will be asumed
|
287 |
+
}
|
288 |
+
}
|
289 |
+
|
290 |
+
// Get the variation attributes from meta
|
291 |
+
foreach ( $all_meta as $name => $value ) {
|
292 |
+
// Only look at valid attribute meta, and also compare variation level attributes and remove any which do not exist at parent level
|
293 |
+
if ( 0 !== strpos( $name, 'attribute_' ) || ! in_array( $name, $found_parent_attributes ) ) {
|
294 |
+
unset( $variation_attributes[ $name ] );
|
295 |
+
continue;
|
296 |
+
}
|
297 |
+
/**
|
298 |
+
* Pre 2.4 handling where 'slugs' were saved instead of the full text attribute.
|
299 |
+
* Attempt to get full version of the text attribute from the parent.
|
300 |
+
*/
|
301 |
+
if ( sanitize_title( $value[0] ) === $value[0] && version_compare( get_post_meta( $parent_id, '_product_version', true ), '2.4.0', '<' ) ) {
|
302 |
+
foreach ( $parent_attributes as $attribute ) {
|
303 |
+
if ( $name !== 'attribute_' . sanitize_title( $attribute['name'] ) ) {
|
304 |
+
continue;
|
305 |
+
}
|
306 |
+
$text_attributes = wc_get_text_attributes( $attribute['value'] );
|
307 |
+
|
308 |
+
foreach ( $text_attributes as $text_attribute ) {
|
309 |
+
if ( sanitize_title( $text_attribute ) === $value[0] ) {
|
310 |
+
$value[0] = $text_attribute;
|
311 |
+
break;
|
312 |
+
}
|
313 |
+
}
|
314 |
+
}
|
315 |
+
}
|
316 |
+
|
317 |
+
$variation_attributes[ $name ] = $value[0];
|
318 |
+
}
|
319 |
+
|
320 |
+
return $variation_attributes;
|
321 |
+
}
|
322 |
+
|
323 |
+
public function find_matching_product_variation( $product, $match_attributes = array() ) {
|
324 |
+
if ( $this->check_woocommerce_version( '3.0') ) {
|
325 |
+
$data_store = WC_Data_Store::load( 'product' );
|
326 |
+
$variation_id = $data_store->find_matching_product_variation( $product, $match_attributes );
|
327 |
+
return $variation_id;
|
328 |
+
}
|
329 |
+
|
330 |
+
return $product->get_matching_variation( $match_attributes );
|
331 |
+
}
|
332 |
+
|
333 |
+
/**
|
334 |
+
* @since 2.4.0 for WC 2.7 compatibility
|
335 |
+
*
|
336 |
+
* Get a WC_Coupon object
|
337 |
+
* @param WC_Coupon|string|WP_Post $coupon The coupon code or a WC_Coupon object
|
338 |
+
* @return WC_Coupon The coupon object
|
339 |
+
*/
|
340 |
+
public function get_coupon( $coupon ) {
|
341 |
+
if ( $coupon instanceof WP_Post ) {
|
342 |
+
$coupon = $coupon->ID;
|
343 |
+
}
|
344 |
+
if ( is_numeric( $coupon ) && ! $this->check_woocommerce_version( '3.0' ) ) {
|
345 |
+
//By id; not neccesary for WC3.0; as the WC_Coupon constructor accepts an id
|
346 |
+
global $wpdb;
|
347 |
+
$coupon_code = $wpdb->get_var( $wpdb->prepare( "SELECT post_title FROM $wpdb->posts WHERE id = %d AND post_type = 'shop_coupon'", $coupon ) );
|
348 |
+
if ( $coupon_code !== null) {
|
349 |
+
$coupon = $coupon_code;
|
350 |
+
}
|
351 |
+
}
|
352 |
+
if ( ! ( $coupon instanceof WC_Coupon ) ) {
|
353 |
+
//By code
|
354 |
+
$coupon = new WC_Coupon( $coupon );
|
355 |
+
}
|
356 |
+
return $coupon;
|
357 |
+
}
|
358 |
+
|
359 |
+
|
360 |
+
//VERSION
|
361 |
+
|
362 |
+
/**
|
363 |
+
* Check whether WooCommerce version is greater or equal than $req_version
|
364 |
+
* @param string @req_version The version to compare to
|
365 |
+
* @return bool true if WooCommerce is at least the given version
|
366 |
+
*/
|
367 |
+
public function check_woocommerce_version( $req_version ) {
|
368 |
+
return version_compare( $this->get_woocommerce_version(), $req_version, '>=' );
|
369 |
+
}
|
370 |
+
|
371 |
+
private $wc_version = null;
|
372 |
+
|
373 |
+
/**
|
374 |
+
* Get the WooCommerce version number
|
375 |
+
* @return string|bool WC Version number or false if WC not detected
|
376 |
+
*/
|
377 |
+
public function get_woocommerce_version() {
|
378 |
+
if ( isset( $this->wc_version ) ) {
|
379 |
+
return $this->wc_version;
|
380 |
+
}
|
381 |
+
|
382 |
+
if ( defined( 'WC_VERSION' ) ) {
|
383 |
+
return $this->wc_version = WC_VERSION;
|
384 |
+
}
|
385 |
+
|
386 |
+
// If get_plugins() isn't available, require it
|
387 |
+
if ( ! function_exists( 'get_plugins' ) ) {
|
388 |
+
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
389 |
+
}
|
390 |
+
// Create the plugins folder and file variables
|
391 |
+
$plugin_folder = get_plugins( '/woocommerce' );
|
392 |
+
$plugin_file = 'woocommerce.php';
|
393 |
+
|
394 |
+
// If the plugin version number is set, return it
|
395 |
+
if ( isset( $plugin_folder[$plugin_file]['Version'] ) ) {
|
396 |
+
return $this->wc_version = $plugin_folder[$plugin_file]['Version'];
|
397 |
+
}
|
398 |
+
|
399 |
+
return $this->wc_version = false; // Not found
|
400 |
+
}
|
401 |
+
|
402 |
+
//INSTANCE
|
403 |
+
|
404 |
+
/**
|
405 |
+
* Singleton Instance
|
406 |
+
*
|
407 |
+
* @static
|
408 |
+
* @return Singleton Instance
|
409 |
+
*/
|
410 |
+
public static function instance() {
|
411 |
+
if ( is_null( self::$_instance ) ) {
|
412 |
+
self::$_instance = new self();
|
413 |
+
}
|
414 |
+
return self::$_instance;
|
415 |
+
}
|
416 |
+
protected static $_instance = null;
|
417 |
+
}
|
includes/WJECF_WC_Discounts.php
CHANGED
@@ -1,70 +1,70 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
defined('ABSPATH') or die();
|
4 |
-
|
5 |
-
|
6 |
-
/**
|
7 |
-
* Class that replaces the get_items() a WC_Discounts (WC3.2.0) object for WC < 3.2.0
|
8 |
-
*
|
9 |
-
* @since 2.6.0
|
10 |
-
*/
|
11 |
-
class WJECF_WC_Discounts {
|
12 |
-
|
13 |
-
public function __construct( $object = array() ) {
|
14 |
-
if ( is_a( $object, 'WC_Cart' ) ) {
|
15 |
-
$this->set_items_from_cart( $object );
|
16 |
-
return;
|
17 |
-
}
|
18 |
-
throw new Exception('WJECF_WC_Discounts must be passed a WC_Cart object');
|
19 |
-
}
|
20 |
-
|
21 |
-
/**
|
22 |
-
* Get items.
|
23 |
-
*
|
24 |
-
* @since 3.2.0
|
25 |
-
* @return object[]
|
26 |
-
*/
|
27 |
-
public function get_items() {
|
28 |
-
return $this->items;
|
29 |
-
}
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Normalise cart items which will be discounted.
|
33 |
-
*
|
34 |
-
* @since 3.2.0
|
35 |
-
* @param WC_Cart $cart Cart object.
|
36 |
-
*/
|
37 |
-
public function set_items_from_cart( $cart ) {
|
38 |
-
$this->items = $this->discounts = array();
|
39 |
-
|
40 |
-
if ( ! is_a( $cart, 'WC_Cart' ) ) {
|
41 |
-
return;
|
42 |
-
}
|
43 |
-
|
44 |
-
$this->object = $cart;
|
45 |
-
|
46 |
-
foreach ( $cart->get_cart() as $key => $cart_item ) {
|
47 |
-
$this->items[ $key ] = WJECF_WC()->cart_item_to_discount_item( $cart_item, $key );
|
48 |
-
}
|
49 |
-
|
50 |
-
uasort( $this->items, array( $this, 'sort_by_price' ) );
|
51 |
-
}
|
52 |
-
|
53 |
-
/**
|
54 |
-
* Sort by price.
|
55 |
-
*
|
56 |
-
* @since 3.2.0
|
57 |
-
* @param array $a First element.
|
58 |
-
* @param array $b Second element.
|
59 |
-
* @return int
|
60 |
-
*/
|
61 |
-
protected function sort_by_price( $a, $b ) {
|
62 |
-
$price_1 = $a->price * $a->quantity;
|
63 |
-
$price_2 = $b->price * $b->quantity;
|
64 |
-
if ( $price_1 === $price_2 ) {
|
65 |
-
return 0;
|
66 |
-
}
|
67 |
-
return ( $price_1 < $price_2 ) ? 1 : -1;
|
68 |
-
}
|
69 |
-
|
70 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
defined('ABSPATH') or die();
|
4 |
+
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Class that replaces the get_items() a WC_Discounts (WC3.2.0) object for WC < 3.2.0
|
8 |
+
*
|
9 |
+
* @since 2.6.0
|
10 |
+
*/
|
11 |
+
class WJECF_WC_Discounts {
|
12 |
+
|
13 |
+
public function __construct( $object = array() ) {
|
14 |
+
if ( is_a( $object, 'WC_Cart' ) ) {
|
15 |
+
$this->set_items_from_cart( $object );
|
16 |
+
return;
|
17 |
+
}
|
18 |
+
throw new Exception('WJECF_WC_Discounts must be passed a WC_Cart object');
|
19 |
+
}
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Get items.
|
23 |
+
*
|
24 |
+
* @since 3.2.0
|
25 |
+
* @return object[]
|
26 |
+
*/
|
27 |
+
public function get_items() {
|
28 |
+
return $this->items;
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Normalise cart items which will be discounted.
|
33 |
+
*
|
34 |
+
* @since 3.2.0
|
35 |
+
* @param WC_Cart $cart Cart object.
|
36 |
+
*/
|
37 |
+
public function set_items_from_cart( $cart ) {
|
38 |
+
$this->items = $this->discounts = array();
|
39 |
+
|
40 |
+
if ( ! is_a( $cart, 'WC_Cart' ) ) {
|
41 |
+
return;
|
42 |
+
}
|
43 |
+
|
44 |
+
$this->object = $cart;
|
45 |
+
|
46 |
+
foreach ( $cart->get_cart() as $key => $cart_item ) {
|
47 |
+
$this->items[ $key ] = WJECF_WC()->cart_item_to_discount_item( $cart_item, $key );
|
48 |
+
}
|
49 |
+
|
50 |
+
uasort( $this->items, array( $this, 'sort_by_price' ) );
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Sort by price.
|
55 |
+
*
|
56 |
+
* @since 3.2.0
|
57 |
+
* @param array $a First element.
|
58 |
+
* @param array $b Second element.
|
59 |
+
* @return int
|
60 |
+
*/
|
61 |
+
protected function sort_by_price( $a, $b ) {
|
62 |
+
$price_1 = $a->price * $a->quantity;
|
63 |
+
$price_2 = $b->price * $b->quantity;
|
64 |
+
if ( $price_1 === $price_2 ) {
|
65 |
+
return 0;
|
66 |
+
}
|
67 |
+
return ( $price_1 < $price_2 ) ? 1 : -1;
|
68 |
+
}
|
69 |
+
|
70 |
+
}
|
includes/WJECF_WPML.php
CHANGED
@@ -1,80 +1,80 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
defined('ABSPATH') or die();
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Class to make WJECF compatible with WPML
|
7 |
-
*/
|
8 |
-
class WJECF_WPML extends Abstract_WJECF_Plugin {
|
9 |
-
|
10 |
-
public function __construct() {
|
11 |
-
$this->set_plugin_data( array(
|
12 |
-
'description' => __( 'Compatiblity with WPML.', 'woocommerce-jos-autocoupon' ),
|
13 |
-
'dependencies' => array(),
|
14 |
-
'can_be_disabled' => true
|
15 |
-
) );
|
16 |
-
}
|
17 |
-
|
18 |
-
public function init_hook() {
|
19 |
-
global $sitepress;
|
20 |
-
if ( isset( $sitepress ) ) {
|
21 |
-
//WJECF_Controller hooks
|
22 |
-
add_filter( 'wjecf_get_product_id', array( $this, 'filter_get_product_id' ), 10 );
|
23 |
-
add_filter( 'wjecf_get_product_ids', array( $this, 'filter_get_product_ids' ), 10 );
|
24 |
-
add_filter( 'wjecf_get_product_cat_ids', array( $this, 'filter_get_product_cat_ids' ), 10 );
|
25 |
-
}
|
26 |
-
}
|
27 |
-
|
28 |
-
//HOOKS
|
29 |
-
|
30 |
-
public function filter_get_product_ids( $product_ids ) {
|
31 |
-
return $this->get_translated_object_ids( $product_ids, 'product' );
|
32 |
-
}
|
33 |
-
|
34 |
-
public function filter_get_product_cat_ids( $product_cat_ids ) {
|
35 |
-
return $this->get_translated_object_ids( $product_cat_ids, 'product_cat' );
|
36 |
-
}
|
37 |
-
|
38 |
-
public function filter_get_product_id( $product_id ) {
|
39 |
-
return $this->get_translated_object_id( $product_id, 'product' );
|
40 |
-
}
|
41 |
-
|
42 |
-
//FUNCTIONS
|
43 |
-
|
44 |
-
|
45 |
-
/**
|
46 |
-
* Get the ids of all the translations. Otherwise return the original array
|
47 |
-
*
|
48 |
-
* @param int|array $product_ids The product_ids to find the translations for
|
49 |
-
* @return array The product ids of all translations
|
50 |
-
*
|
51 |
-
*/
|
52 |
-
public function get_translated_object_ids( $object_ids, $object_type ) {
|
53 |
-
//Make sure it's an array
|
54 |
-
if ( ! is_array( $object_ids ) ) {
|
55 |
-
$object_ids = array( $object_ids );
|
56 |
-
}
|
57 |
-
|
58 |
-
$translated_object_ids = array();
|
59 |
-
foreach( $object_ids as $object_id) {
|
60 |
-
$translated_object_ids[] = apply_filters( 'wpml_object_id', $object_id, $object_type );
|
61 |
-
}
|
62 |
-
$this->log( 'debug', 'Translated ' . $object_type . ': ' . implode( ',', $object_ids ) . ' to: ' . implode( ',', $translated_object_ids ) );
|
63 |
-
return $translated_object_ids;
|
64 |
-
}
|
65 |
-
|
66 |
-
/**
|
67 |
-
* Get translated object id
|
68 |
-
* @param int $object_id
|
69 |
-
* @param string $object_type
|
70 |
-
* @return int|bool false if not found
|
71 |
-
*/
|
72 |
-
public function get_translated_object_id( $object_id, $object_type ) {
|
73 |
-
$translated_object_ids = $this->get_translated_object_ids( array( $object_id ), $object_type );
|
74 |
-
if ( empty( $translated_object_ids ) ) {
|
75 |
-
return false;
|
76 |
-
}
|
77 |
-
return reset( $translated_object_ids );
|
78 |
-
}
|
79 |
-
|
80 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
defined('ABSPATH') or die();
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Class to make WJECF compatible with WPML
|
7 |
+
*/
|
8 |
+
class WJECF_WPML extends Abstract_WJECF_Plugin {
|
9 |
+
|
10 |
+
public function __construct() {
|
11 |
+
$this->set_plugin_data( array(
|
12 |
+
'description' => __( 'Compatiblity with WPML.', 'woocommerce-jos-autocoupon' ),
|
13 |
+
'dependencies' => array(),
|
14 |
+
'can_be_disabled' => true
|
15 |
+
) );
|
16 |
+
}
|
17 |
+
|
18 |
+
public function init_hook() {
|
19 |
+
global $sitepress;
|
20 |
+
if ( isset( $sitepress ) ) {
|
21 |
+
//WJECF_Controller hooks
|
22 |
+
add_filter( 'wjecf_get_product_id', array( $this, 'filter_get_product_id' ), 10 );
|
23 |
+
add_filter( 'wjecf_get_product_ids', array( $this, 'filter_get_product_ids' ), 10 );
|
24 |
+
add_filter( 'wjecf_get_product_cat_ids', array( $this, 'filter_get_product_cat_ids' ), 10 );
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
//HOOKS
|
29 |
+
|
30 |
+
public function filter_get_product_ids( $product_ids ) {
|
31 |
+
return $this->get_translated_object_ids( $product_ids, 'product' );
|
32 |
+
}
|
33 |
+
|
34 |
+
public function filter_get_product_cat_ids( $product_cat_ids ) {
|
35 |
+
return $this->get_translated_object_ids( $product_cat_ids, 'product_cat' );
|
36 |
+
}
|
37 |
+
|
38 |
+
public function filter_get_product_id( $product_id ) {
|
39 |
+
return $this->get_translated_object_id( $product_id, 'product' );
|
40 |
+
}
|
41 |
+
|
42 |
+
//FUNCTIONS
|
43 |
+
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Get the ids of all the translations. Otherwise return the original array
|
47 |
+
*
|
48 |
+
* @param int|array $product_ids The product_ids to find the translations for
|
49 |
+
* @return array The product ids of all translations
|
50 |
+
*
|
51 |
+
*/
|
52 |
+
public function get_translated_object_ids( $object_ids, $object_type ) {
|
53 |
+
//Make sure it's an array
|
54 |
+
if ( ! is_array( $object_ids ) ) {
|
55 |
+
$object_ids = array( $object_ids );
|
56 |
+
}
|
57 |
+
|
58 |
+
$translated_object_ids = array();
|
59 |
+
foreach( $object_ids as $object_id) {
|
60 |
+
$translated_object_ids[] = apply_filters( 'wpml_object_id', $object_id, $object_type );
|
61 |
+
}
|
62 |
+
$this->log( 'debug', 'Translated ' . $object_type . ': ' . implode( ',', $object_ids ) . ' to: ' . implode( ',', $translated_object_ids ) );
|
63 |
+
return $translated_object_ids;
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Get translated object id
|
68 |
+
* @param int $object_id
|
69 |
+
* @param string $object_type
|
70 |
+
* @return int|bool false if not found
|
71 |
+
*/
|
72 |
+
public function get_translated_object_id( $object_id, $object_type ) {
|
73 |
+
$translated_object_ids = $this->get_translated_object_ids( array( $object_id ), $object_type );
|
74 |
+
if ( empty( $translated_object_ids ) ) {
|
75 |
+
return false;
|
76 |
+
}
|
77 |
+
return reset( $translated_object_ids );
|
78 |
+
}
|
79 |
+
|
80 |
+
}
|
includes/WJECF_Wrap.php
CHANGED
@@ -1,497 +1,497 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
defined('ABSPATH') or die();
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Wrapper for WC objects. Helps to maintain compatibility between both WC2 and WC3
|
7 |
-
*/
|
8 |
-
class WJECF_Wrap {
|
9 |
-
protected $object = null;
|
10 |
-
|
11 |
-
public function __construct( $object ) {
|
12 |
-
$this->object = $object;
|
13 |
-
//error_log('Wrapping ' . get_class( $object ) );
|
14 |
-
}
|
15 |
-
|
16 |
-
public $use_wc27 = true;
|
17 |
-
public function get_id() {
|
18 |
-
//Since WC 2.7
|
19 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_id' ) ) ) {
|
20 |
-
return $this->object->get_id();
|
21 |
-
}
|
22 |
-
return $this->object->id;
|
23 |
-
}
|
24 |
-
|
25 |
-
public function holds( $object ) {
|
26 |
-
return $object === $this->object;
|
27 |
-
}
|
28 |
-
|
29 |
-
/**
|
30 |
-
* Get Meta Data by Key.
|
31 |
-
*
|
32 |
-
* If no value found:
|
33 |
-
* If $single is true, an empty string is returned.
|
34 |
-
* If $single is false, an empty array is returned.
|
35 |
-
*
|
36 |
-
* @since 2.4.0
|
37 |
-
* @param string $key
|
38 |
-
* @param bool $single return first found meta, or all
|
39 |
-
* @return mixed
|
40 |
-
*/
|
41 |
-
public final function get_meta( $meta_key, $single = true ) {
|
42 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_meta' ) ) ) {
|
43 |
-
return $this->get_meta_wc27( $meta_key, $single );
|
44 |
-
}
|
45 |
-
|
46 |
-
return $this->get_meta_legacy( $meta_key, $single );
|
47 |
-
}
|
48 |
-
|
49 |
-
protected function get_meta_wc27( $meta_key, $single = true ) {
|
50 |
-
$values = $this->object->get_meta( $meta_key, $single );
|
51 |
-
if ($single) {
|
52 |
-
return $values; //it's just one, dispite the plural in the name!
|
53 |
-
}
|
54 |
-
|
55 |
-
if ( $values === '' ) {
|
56 |
-
return array(); //get_meta returns empty string if meta does not exist
|
57 |
-
}
|
58 |
-
|
59 |
-
return wp_list_pluck( array_values( $values ), 'value' ); //when not using array_values; the index might not start with 0
|
60 |
-
}
|
61 |
-
|
62 |
-
protected function get_meta_legacy( $meta_key, $single = true ) {
|
63 |
-
throw new Exception( sprintf( '%s::get_meta_legacy not implemented', get_class( $this ) ) );
|
64 |
-
}
|
65 |
-
|
66 |
-
/**
|
67 |
-
* Update single meta data item by meta key.
|
68 |
-
* Call save() if the values must to be persisted.
|
69 |
-
* @since 2.4.0
|
70 |
-
* @param string $meta_key
|
71 |
-
* @param mixed $value The value; use null to clear
|
72 |
-
*/
|
73 |
-
public final function set_meta( $meta_key, $value ) {
|
74 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'update_meta_data' ) ) ) {
|
75 |
-
if ( $value === null ) {
|
76 |
-
$this->object->delete_meta_data( $meta_key );
|
77 |
-
} else {
|
78 |
-
$this->object->update_meta_data( $meta_key, $value );
|
79 |
-
}
|
80 |
-
return;
|
81 |
-
}
|
82 |
-
|
83 |
-
$this->set_meta_legacy( $meta_key, $value );
|
84 |
-
}
|
85 |
-
|
86 |
-
protected function set_meta_legacy( $meta_key, $value ) {
|
87 |
-
throw new Exception( sprintf( '%s::set_meta_legacy not implemented', get_class( $this ) ) );
|
88 |
-
}
|
89 |
-
|
90 |
-
}
|
91 |
-
|
92 |
-
/**
|
93 |
-
* Wrap a data object ( Coupons and products were converted to WC_Data since WC 2.7.0 )
|
94 |
-
*/
|
95 |
-
class WJECF_Wrap_Coupon extends WJECF_Wrap {
|
96 |
-
|
97 |
-
public function exists() {
|
98 |
-
return $this->get_id() > 0;
|
99 |
-
}
|
100 |
-
|
101 |
-
public function get_code() {
|
102 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_code' ) ) ) {
|
103 |
-
return $this->object->get_code();
|
104 |
-
}
|
105 |
-
|
106 |
-
return $this->object->code;
|
107 |
-
}
|
108 |
-
|
109 |
-
public function get_description() {
|
110 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_description' ) ) ) {
|
111 |
-
return $this->object->get_description();
|
112 |
-
}
|
113 |
-
|
114 |
-
$post = get_post( $this->get_id() );
|
115 |
-
return $post->post_excerpt;
|
116 |
-
}
|
117 |
-
|
118 |
-
public function get_amount() {
|
119 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_amount' ) ) ) {
|
120 |
-
return $this->object->get_amount();
|
121 |
-
}
|
122 |
-
|
123 |
-
return $this->object->coupon_amount;
|
124 |
-
}
|
125 |
-
|
126 |
-
public function get_individual_use() {
|
127 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_individual_use' ) ) ) {
|
128 |
-
return $this->object->get_individual_use();
|
129 |
-
}
|
130 |
-
|
131 |
-
return $this->object->individual_use == 'yes';
|
132 |
-
}
|
133 |
-
|
134 |
-
public function get_limit_usage_to_x_items() {
|
135 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_limit_usage_to_x_items' ) ) ) {
|
136 |
-
return $this->object->get_limit_usage_to_x_items();
|
137 |
-
}
|
138 |
-
|
139 |
-
return $this->object->limit_usage_to_x_items;
|
140 |
-
}
|
141 |
-
|
142 |
-
public function set_limit_usage_to_x_items( $limit_usage_to_x_items ) {
|
143 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'set_limit_usage_to_x_items' ) ) ) {
|
144 |
-
$this->object->set_limit_usage_to_x_items( $limit_usage_to_x_items );
|
145 |
-
} else {
|
146 |
-
$this->object->limit_usage_to_x_items = $limit_usage_to_x_items;
|
147 |
-
}
|
148 |
-
}
|
149 |
-
|
150 |
-
public function get_discount_type() {
|
151 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_discount_type' ) ) ) {
|
152 |
-
return $this->object->get_discount_type();
|
153 |
-
}
|
154 |
-
|
155 |
-
return $this->object->discount_type;
|
156 |
-
}
|
157 |
-
|
158 |
-
public function set_discount_type( $discount_type ) {
|
159 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'set_discount_type' ) ) ) {
|
160 |
-
$this->object->set_discount_type( $discount_type );
|
161 |
-
} else {
|
162 |
-
$this->object->discount_type = $discount_type;
|
163 |
-
$this->object->type = $discount_type;
|
164 |
-
}
|
165 |
-
}
|
166 |
-
|
167 |
-
|
168 |
-
public function get_email_restrictions() {
|
169 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_email_restrictions' ) ) ) {
|
170 |
-
return $this->object->get_email_restrictions();
|
171 |
-
}
|
172 |
-
|
173 |
-
return $this->object->customer_email;
|
174 |
-
}
|
175 |
-
|
176 |
-
public function get_product_ids() {
|
177 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_product_ids' ) ) ) {
|
178 |
-
return $this->object->get_product_ids();
|
179 |
-
}
|
180 |
-
|
181 |
-
return $this->object->product_ids;
|
182 |
-
}
|
183 |
-
|
184 |
-
public function get_free_shipping() {
|
185 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_free_shipping' ) ) ) {
|
186 |
-
return $this->object->get_free_shipping();
|
187 |
-
}
|
188 |
-
|
189 |
-
return $this->object->enable_free_shipping();
|
190 |
-
}
|
191 |
-
|
192 |
-
public function get_product_categories() {
|
193 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_product_categories' ) ) ) {
|
194 |
-
return $this->object->get_product_categories();
|
195 |
-
}
|
196 |
-
|
197 |
-
return $this->object->product_categories;
|
198 |
-
}
|
199 |
-
|
200 |
-
public function get_minimum_amount() {
|
201 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_minimum_amount' ) ) ) {
|
202 |
-
return $this->object->get_minimum_amount();
|
203 |
-
}
|
204 |
-
|
205 |
-
return $this->object->minimum_amount;
|
206 |
-
}
|
207 |
-
|
208 |
-
/**
|
209 |
-
* Set the product IDs this coupon cannot be used with.
|
210 |
-
* @since 2.4.2 (For WC3.0)
|
211 |
-
* @param array $excluded_product_ids
|
212 |
-
* @throws WC_Data_Exception
|
213 |
-
*/
|
214 |
-
public function set_excluded_product_ids( $excluded_product_ids ) {
|
215 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'set_excluded_product_ids' ) ) ) {
|
216 |
-
$this->object->set_excluded_product_ids( $excluded_product_ids );
|
217 |
-
} else {
|
218 |
-
//NOTE: Prior to WC2.7 it was called exclude_ instead of excluded_
|
219 |
-
$this->object->exclude_product_ids = $excluded_product_ids;
|
220 |
-
}
|
221 |
-
}
|
222 |
-
|
223 |
-
/**
|
224 |
-
* Set the product category IDs this coupon cannot be used with.
|
225 |
-
* @since 2.4.2 (For WC3.0)
|
226 |
-
* @param array $excluded_product_categories
|
227 |
-
* @throws WC_Data_Exception
|
228 |
-
*/
|
229 |
-
public function set_excluded_product_categories( $excluded_product_categories ) {
|
230 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'set_excluded_product_categories' ) ) ) {
|
231 |
-
$this->object->set_excluded_product_categories( $excluded_product_categories );
|
232 |
-
} else {
|
233 |
-
//NOTE: Prior to WC2.7 it was called exclude_ instead of excluded_
|
234 |
-
$this->object->exclude_product_categories = $excluded_product_categories;
|
235 |
-
}
|
236 |
-
}
|
237 |
-
|
238 |
-
/**
|
239 |
-
* Set if this coupon should excluded sale items or not.
|
240 |
-
* @since 2.4.2 (For WC3.0)
|
241 |
-
* @param bool $exclude_sale_items
|
242 |
-
* @throws WC_Data_Exception
|
243 |
-
*/
|
244 |
-
public function set_exclude_sale_items( $exclude_sale_items ) {
|
245 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'set_exclude_sale_items' ) ) ) {
|
246 |
-
$this->object->set_exclude_sale_items( $exclude_sale_items );
|
247 |
-
} else {
|
248 |
-
//NOTE: Prior to WC2.7 it was yes/no instead of boolean
|
249 |
-
$this->object->exclude_sale_items = $exclude_sale_items ? 'yes' : 'no';
|
250 |
-
}
|
251 |
-
}
|
252 |
-
|
253 |
-
/**
|
254 |
-
* Check the type of the coupon
|
255 |
-
* @param string|array $type The type(s) we want to check for
|
256 |
-
* @return bool True if the coupon is of the type
|
257 |
-
*/
|
258 |
-
public function is_type( $type ) {
|
259 |
-
//Backwards compatibility 2.2.11
|
260 |
-
if ( method_exists( $this->object, 'is_type' ) ) {
|
261 |
-
return $this->object->is_type( $type );
|
262 |
-
}
|
263 |
-
|
264 |
-
return ( $this->object->discount_type == $type || ( is_array( $type ) && in_array( $this->object->discount_type, $type ) ) ) ? true : false;
|
265 |
-
}
|
266 |
-
|
267 |
-
protected function set_meta_legacy( $meta_key, $value ) {
|
268 |
-
$this->maybe_get_custom_fields();
|
269 |
-
//WJECF()->log('...setting legacy meta ' . $meta_key );
|
270 |
-
$this->legacy_custom_fields[ $meta_key ] = array( $value );
|
271 |
-
$this->legacy_unsaved_keys[] = $meta_key;
|
272 |
-
}
|
273 |
-
|
274 |
-
/**
|
275 |
-
* Save the metadata
|
276 |
-
* @return id of this object
|
277 |
-
*/
|
278 |
-
public function save() {
|
279 |
-
//WJECF()->log('Saving ' . $this->get_id() );
|
280 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'save' ) ) ) {
|
281 |
-
return $this->object->save();
|
282 |
-
}
|
283 |
-
|
284 |
-
//Save the unsaved...
|
285 |
-
foreach( $this->legacy_unsaved_keys as $meta_key ) {
|
286 |
-
//WJECF()->log('...saving legacy meta ' . $meta_key );
|
287 |
-
$value = reset( $this->legacy_custom_fields[ $meta_key ] );
|
288 |
-
if ( $value === null ) {
|
289 |
-
delete_post_meta( $this->get_id(), $meta_key );
|
290 |
-
} else {
|
291 |
-
update_post_meta( $this->get_id(), $meta_key, $value );
|
292 |
-
}
|
293 |
-
}
|
294 |
-
$this->legacy_unsaved_keys = array();
|
295 |
-
|
296 |
-
return $this->get_id();
|
297 |
-
}
|
298 |
-
|
299 |
-
protected $legacy_custom_fields = null; // [ 'meta_key' => [ array_of_values ] ]
|
300 |
-
protected $legacy_unsaved_keys = array();
|
301 |
-
|
302 |
-
protected function maybe_get_custom_fields() {
|
303 |
-
//Read custom fields if not yet done
|
304 |
-
if ( is_null( $this->legacy_custom_fields ) ) {
|
305 |
-
$this->legacy_custom_fields = $this->object->coupon_custom_fields;
|
306 |
-
}
|
307 |
-
}
|
308 |
-
|
309 |
-
protected function get_meta_legacy( $meta_key, $single = true ) {
|
310 |
-
//Read custom fields if not yet done
|
311 |
-
$this->maybe_get_custom_fields();
|
312 |
-
|
313 |
-
if ( isset( $this->legacy_custom_fields[ $meta_key ] ) ) {
|
314 |
-
$values = $this->legacy_custom_fields[ $meta_key ];
|
315 |
-
//WP_CLI::log( "LEGACY:" . print_r( $values, true ));
|
316 |
-
if ($single) {
|
317 |
-
return maybe_unserialize( reset( $values ) ); //reset yields the first
|
318 |
-
}
|
319 |
-
$values = array_map( 'maybe_unserialize', $values );
|
320 |
-
return $values;
|
321 |
-
}
|
322 |
-
|
323 |
-
return $single ? '' : array();
|
324 |
-
}
|
325 |
-
|
326 |
-
}
|
327 |
-
|
328 |
-
class WJECF_Wrap_Product extends WJECF_Wrap {
|
329 |
-
|
330 |
-
protected $legacy_custom_fields = null; // [ 'meta_key' => [ array_of_values ] ]
|
331 |
-
protected $legacy_unsaved_keys = array();
|
332 |
-
|
333 |
-
protected function get_meta_legacy( $meta_key, $single = true ) {
|
334 |
-
if ( isset( $this->legacy_custom_fields[ $meta_key ] ) ) {
|
335 |
-
$values = $this->legacy_custom_fields[ $meta_key ];
|
336 |
-
//WP_CLI::log( "LEGACY:" . print_r( $values, true ));
|
337 |
-
if ($single) {
|
338 |
-
return maybe_unserialize( reset( $values ) ); //reset yields the first
|
339 |
-
}
|
340 |
-
$values = array_map( 'maybe_unserialize', $values );
|
341 |
-
return $values;
|
342 |
-
}
|
343 |
-
|
344 |
-
return get_post_meta( $this->get_product_or_variation_id(), $meta_key, $single );
|
345 |
-
}
|
346 |
-
|
347 |
-
public function set_meta_legacy( $meta_key, $value ) {
|
348 |
-
$this->legacy_custom_fields[ $meta_key ] = array( 0 => $value );
|
349 |
-
$this->legacy_unsaved_keys[] = $meta_key;
|
350 |
-
}
|
351 |
-
|
352 |
-
/**
|
353 |
-
* Combines get_meta or get_prop (in legacy WC those were the same thing, in WC3.0+ there is a difference)
|
354 |
-
* @param string $field_name
|
355 |
-
* @param bool $single
|
356 |
-
* @return
|
357 |
-
*/
|
358 |
-
public function get_field($field_name, $single = true) {
|
359 |
-
if ( $this->use_wc27 ) {
|
360 |
-
$values = $this->get_meta($field_name, $single);
|
361 |
-
if ( ! empty( $values ) ) return $values;
|
362 |
-
|
363 |
-
if ( is_callable( array( $this->object, 'get_prop' ) ) ) {
|
364 |
-
$value = $this->object->get_prop($field_name);
|
365 |
-
if ( ! empty( $value ) ) return $single ? $value : array( $value );
|
366 |
-
}
|
367 |
-
}
|
368 |
-
|
369 |
-
return get_post_meta( $this->get_product_or_variation_id(), $field_name, $single );
|
370 |
-
}
|
371 |
-
|
372 |
-
private function is_variation() {
|
373 |
-
return $this->object instanceof WC_Product_Variation;
|
374 |
-
}
|
375 |
-
|
376 |
-
/**
|
377 |
-
* Retrieve the id of the product or the variation id if it's a variant.
|
378 |
-
*
|
379 |
-
* (2.4.0: Moved from WJECF_Controller to WJECF_WC)
|
380 |
-
*
|
381 |
-
* @param WC_Product $product
|
382 |
-
* @return int|bool The variation or product id. False if not a valid product
|
383 |
-
*/
|
384 |
-
public function get_product_or_variation_id() {
|
385 |
-
if ( $this->is_variation() ) {
|
386 |
-
return $this->get_variation_id();
|
387 |
-
} elseif ( $this->object instanceof WC_Product ) {
|
388 |
-
return $this->get_id();
|
389 |
-
} else {
|
390 |
-
return false;
|
391 |
-
}
|
392 |
-
}
|
393 |
-
|
394 |
-
/**
|
395 |
-
* Retrieve the id of the parent product if it's a variation; otherwise retrieve this products id
|
396 |
-
*
|
397 |
-
* (2.4.0: Moved from WJECF_Controller to WJECF_WC)
|
398 |
-
*
|
399 |
-
* @param WC_Product $product
|
400 |
-
* @return int|bool The product id. False if this product is not a variation
|
401 |
-
*/
|
402 |
-
public function get_variable_product_id() {
|
403 |
-
if ( ! $this->is_variation() ) {
|
404 |
-
return false;
|
405 |
-
}
|
406 |
-
|
407 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_parent_id' ) ) ) {
|
408 |
-
return $this->object->get_parent_id();
|
409 |
-
} else {
|
410 |
-
return wp_get_post_parent_id( $this->object->variation_id );
|
411 |
-
}
|
412 |
-
}
|
413 |
-
|
414 |
-
/**
|
415 |
-
* Get current variation id
|
416 |
-
* @return int|bool False if this is not a variation
|
417 |
-
*/
|
418 |
-
protected function get_variation_id() {
|
419 |
-
if ( ! $this->is_variation() ) {
|
420 |
-
return false;
|
421 |
-
}
|
422 |
-
|
423 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_id' ) ) ) {
|
424 |
-
return $this->object->get_id();
|
425 |
-
} elseif ( $this->use_wc27 && is_callable( array( $this->object, 'get_variation_id' ) ) ) {
|
426 |
-
return $this->object->get_variation_id();
|
427 |
-
}
|
428 |
-
return $this->object->variation_id;
|
429 |
-
}
|
430 |
-
|
431 |
-
|
432 |
-
public function get_name() {
|
433 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_name' ) ) ) {
|
434 |
-
return $this->object->get_name();
|
435 |
-
} else {
|
436 |
-
return $this->object->post->post_title;
|
437 |
-
}
|
438 |
-
}
|
439 |
-
|
440 |
-
public function get_description() {
|
441 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_description' ) ) ) {
|
442 |
-
return $this->object->get_description();
|
443 |
-
} else {
|
444 |
-
return $this->object->post->post_content;
|
445 |
-
}
|
446 |
-
}
|
447 |
-
|
448 |
-
public function get_short_description() {
|
449 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_short_description' ) ) ) {
|
450 |
-
return $this->object->get_short_description();
|
451 |
-
} else {
|
452 |
-
return $this->object->post->post_excerpt;
|
453 |
-
}
|
454 |
-
}
|
455 |
-
|
456 |
-
public function get_status() {
|
457 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_status' ) ) ) {
|
458 |
-
return $this->object->get_status();
|
459 |
-
} else {
|
460 |
-
return $this->object->post->post_status;
|
461 |
-
}
|
462 |
-
}
|
463 |
-
|
464 |
-
public function get_tag_ids() {
|
465 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_tag_ids' ) ) ) {
|
466 |
-
return $this->object->get_tag_ids();
|
467 |
-
} else {
|
468 |
-
return $this->legacy_get_term_ids( 'product_tag' );
|
469 |
-
}
|
470 |
-
}
|
471 |
-
|
472 |
-
protected function legacy_get_term_ids( $taxonomy ) {
|
473 |
-
$terms = get_the_terms( $this->get_id(), $taxonomy );
|
474 |
-
if ( false === $terms || is_wp_error( $terms ) ) {
|
475 |
-
return array();
|
476 |
-
}
|
477 |
-
return wp_list_pluck( $terms, 'term_id' );
|
478 |
-
}
|
479 |
-
|
480 |
-
/**
|
481 |
-
* If set, get the default attributes for a variable product.
|
482 |
-
*
|
483 |
-
* @param string $attribute_name
|
484 |
-
* @return string
|
485 |
-
*/
|
486 |
-
public function get_variation_default_attribute( $attribute_name ) {
|
487 |
-
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_variation_default_attribute' ) ) ) {
|
488 |
-
return $this->object->get_variation_default_attribute( $attribute_name );
|
489 |
-
}
|
490 |
-
return '';
|
491 |
-
}
|
492 |
-
}
|
493 |
-
|
494 |
-
|
495 |
-
class WJECF_Wrap_Customer extends WJECF_Wrap {
|
496 |
-
|
497 |
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
defined('ABSPATH') or die();
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Wrapper for WC objects. Helps to maintain compatibility between both WC2 and WC3
|
7 |
+
*/
|
8 |
+
class WJECF_Wrap {
|
9 |
+
protected $object = null;
|
10 |
+
|
11 |
+
public function __construct( $object ) {
|
12 |
+
$this->object = $object;
|
13 |
+
//error_log('Wrapping ' . get_class( $object ) );
|
14 |
+
}
|
15 |
+
|
16 |
+
public $use_wc27 = true;
|
17 |
+
public function get_id() {
|
18 |
+
//Since WC 2.7
|
19 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_id' ) ) ) {
|
20 |
+
return $this->object->get_id();
|
21 |
+
}
|
22 |
+
return $this->object->id;
|
23 |
+
}
|
24 |
+
|
25 |
+
public function holds( $object ) {
|
26 |
+
return $object === $this->object;
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Get Meta Data by Key.
|
31 |
+
*
|
32 |
+
* If no value found:
|
33 |
+
* If $single is true, an empty string is returned.
|
34 |
+
* If $single is false, an empty array is returned.
|
35 |
+
*
|
36 |
+
* @since 2.4.0
|
37 |
+
* @param string $key
|
38 |
+
* @param bool $single return first found meta, or all
|
39 |
+
* @return mixed
|
40 |
+
*/
|
41 |
+
public final function get_meta( $meta_key, $single = true ) {
|
42 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_meta' ) ) ) {
|
43 |
+
return $this->get_meta_wc27( $meta_key, $single );
|
44 |
+
}
|
45 |
+
|
46 |
+
return $this->get_meta_legacy( $meta_key, $single );
|
47 |
+
}
|
48 |
+
|
49 |
+
protected function get_meta_wc27( $meta_key, $single = true ) {
|
50 |
+
$values = $this->object->get_meta( $meta_key, $single );
|
51 |
+
if ($single) {
|
52 |
+
return $values; //it's just one, dispite the plural in the name!
|
53 |
+
}
|
54 |
+
|
55 |
+
if ( $values === '' ) {
|
56 |
+
return array(); //get_meta returns empty string if meta does not exist
|
57 |
+
}
|
58 |
+
|
59 |
+
return wp_list_pluck( array_values( $values ), 'value' ); //when not using array_values; the index might not start with 0
|
60 |
+
}
|
61 |
+
|
62 |
+
protected function get_meta_legacy( $meta_key, $single = true ) {
|
63 |
+
throw new Exception( sprintf( '%s::get_meta_legacy not implemented', get_class( $this ) ) );
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Update single meta data item by meta key.
|
68 |
+
* Call save() if the values must to be persisted.
|
69 |
+
* @since 2.4.0
|
70 |
+
* @param string $meta_key
|
71 |
+
* @param mixed $value The value; use null to clear
|
72 |
+
*/
|
73 |
+
public final function set_meta( $meta_key, $value ) {
|
74 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'update_meta_data' ) ) ) {
|
75 |
+
if ( $value === null ) {
|
76 |
+
$this->object->delete_meta_data( $meta_key );
|
77 |
+
} else {
|
78 |
+
$this->object->update_meta_data( $meta_key, $value );
|
79 |
+
}
|
80 |
+
return;
|
81 |
+
}
|
82 |
+
|
83 |
+
$this->set_meta_legacy( $meta_key, $value );
|
84 |
+
}
|
85 |
+
|
86 |
+
protected function set_meta_legacy( $meta_key, $value ) {
|
87 |
+
throw new Exception( sprintf( '%s::set_meta_legacy not implemented', get_class( $this ) ) );
|
88 |
+
}
|
89 |
+
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Wrap a data object ( Coupons and products were converted to WC_Data since WC 2.7.0 )
|
94 |
+
*/
|
95 |
+
class WJECF_Wrap_Coupon extends WJECF_Wrap {
|
96 |
+
|
97 |
+
public function exists() {
|
98 |
+
return $this->get_id() > 0;
|
99 |
+
}
|
100 |
+
|
101 |
+
public function get_code() {
|
102 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_code' ) ) ) {
|
103 |
+
return $this->object->get_code();
|
104 |
+
}
|
105 |
+
|
106 |
+
return $this->object->code;
|
107 |
+
}
|
108 |
+
|
109 |
+
public function get_description() {
|
110 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_description' ) ) ) {
|
111 |
+
return $this->object->get_description();
|
112 |
+
}
|
113 |
+
|
114 |
+
$post = get_post( $this->get_id() );
|
115 |
+
return $post->post_excerpt;
|
116 |
+
}
|
117 |
+
|
118 |
+
public function get_amount() {
|
119 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_amount' ) ) ) {
|
120 |
+
return $this->object->get_amount();
|
121 |
+
}
|
122 |
+
|
123 |
+
return $this->object->coupon_amount;
|
124 |
+
}
|
125 |
+
|
126 |
+
public function get_individual_use() {
|
127 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_individual_use' ) ) ) {
|
128 |
+
return $this->object->get_individual_use();
|
129 |
+
}
|
130 |
+
|
131 |
+
return $this->object->individual_use == 'yes';
|
132 |
+
}
|
133 |
+
|
134 |
+
public function get_limit_usage_to_x_items() {
|
135 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_limit_usage_to_x_items' ) ) ) {
|
136 |
+
return $this->object->get_limit_usage_to_x_items();
|
137 |
+
}
|
138 |
+
|
139 |
+
return $this->object->limit_usage_to_x_items;
|
140 |
+
}
|
141 |
+
|
142 |
+
public function set_limit_usage_to_x_items( $limit_usage_to_x_items ) {
|
143 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'set_limit_usage_to_x_items' ) ) ) {
|
144 |
+
$this->object->set_limit_usage_to_x_items( $limit_usage_to_x_items );
|
145 |
+
} else {
|
146 |
+
$this->object->limit_usage_to_x_items = $limit_usage_to_x_items;
|
147 |
+
}
|
148 |
+
}
|
149 |
+
|
150 |
+
public function get_discount_type() {
|
151 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_discount_type' ) ) ) {
|
152 |
+
return $this->object->get_discount_type();
|
153 |
+
}
|
154 |
+
|
155 |
+
return $this->object->discount_type;
|
156 |
+
}
|
157 |
+
|
158 |
+
public function set_discount_type( $discount_type ) {
|
159 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'set_discount_type' ) ) ) {
|
160 |
+
$this->object->set_discount_type( $discount_type );
|
161 |
+
} else {
|
162 |
+
$this->object->discount_type = $discount_type;
|
163 |
+
$this->object->type = $discount_type;
|
164 |
+
}
|
165 |
+
}
|
166 |
+
|
167 |
+
|
168 |
+
public function get_email_restrictions() {
|
169 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_email_restrictions' ) ) ) {
|
170 |
+
return $this->object->get_email_restrictions();
|
171 |
+
}
|
172 |
+
|
173 |
+
return $this->object->customer_email;
|
174 |
+
}
|
175 |
+
|
176 |
+
public function get_product_ids() {
|
177 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_product_ids' ) ) ) {
|
178 |
+
return $this->object->get_product_ids();
|
179 |
+
}
|
180 |
+
|
181 |
+
return $this->object->product_ids;
|
182 |
+
}
|
183 |
+
|
184 |
+
public function get_free_shipping() {
|
185 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_free_shipping' ) ) ) {
|
186 |
+
return $this->object->get_free_shipping();
|
187 |
+
}
|
188 |
+
|
189 |
+
return $this->object->enable_free_shipping();
|
190 |
+
}
|
191 |
+
|
192 |
+
public function get_product_categories() {
|
193 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_product_categories' ) ) ) {
|
194 |
+
return $this->object->get_product_categories();
|
195 |
+
}
|
196 |
+
|
197 |
+
return $this->object->product_categories;
|
198 |
+
}
|
199 |
+
|
200 |
+
public function get_minimum_amount() {
|
201 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_minimum_amount' ) ) ) {
|
202 |
+
return $this->object->get_minimum_amount();
|
203 |
+
}
|
204 |
+
|
205 |
+
return $this->object->minimum_amount;
|
206 |
+
}
|
207 |
+
|
208 |
+
/**
|
209 |
+
* Set the product IDs this coupon cannot be used with.
|
210 |
+
* @since 2.4.2 (For WC3.0)
|
211 |
+
* @param array $excluded_product_ids
|
212 |
+
* @throws WC_Data_Exception
|
213 |
+
*/
|
214 |
+
public function set_excluded_product_ids( $excluded_product_ids ) {
|
215 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'set_excluded_product_ids' ) ) ) {
|
216 |
+
$this->object->set_excluded_product_ids( $excluded_product_ids );
|
217 |
+
} else {
|
218 |
+
//NOTE: Prior to WC2.7 it was called exclude_ instead of excluded_
|
219 |
+
$this->object->exclude_product_ids = $excluded_product_ids;
|
220 |
+
}
|
221 |
+
}
|
222 |
+
|
223 |
+
/**
|
224 |
+
* Set the product category IDs this coupon cannot be used with.
|
225 |
+
* @since 2.4.2 (For WC3.0)
|
226 |
+
* @param array $excluded_product_categories
|
227 |
+
* @throws WC_Data_Exception
|
228 |
+
*/
|
229 |
+
public function set_excluded_product_categories( $excluded_product_categories ) {
|
230 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'set_excluded_product_categories' ) ) ) {
|
231 |
+
$this->object->set_excluded_product_categories( $excluded_product_categories );
|
232 |
+
} else {
|
233 |
+
//NOTE: Prior to WC2.7 it was called exclude_ instead of excluded_
|
234 |
+
$this->object->exclude_product_categories = $excluded_product_categories;
|
235 |
+
}
|
236 |
+
}
|
237 |
+
|
238 |
+
/**
|
239 |
+
* Set if this coupon should excluded sale items or not.
|
240 |
+
* @since 2.4.2 (For WC3.0)
|
241 |
+
* @param bool $exclude_sale_items
|
242 |
+
* @throws WC_Data_Exception
|
243 |
+
*/
|
244 |
+
public function set_exclude_sale_items( $exclude_sale_items ) {
|
245 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'set_exclude_sale_items' ) ) ) {
|
246 |
+
$this->object->set_exclude_sale_items( $exclude_sale_items );
|
247 |
+
} else {
|
248 |
+
//NOTE: Prior to WC2.7 it was yes/no instead of boolean
|
249 |
+
$this->object->exclude_sale_items = $exclude_sale_items ? 'yes' : 'no';
|
250 |
+
}
|
251 |
+
}
|
252 |
+
|
253 |
+
/**
|
254 |
+
* Check the type of the coupon
|
255 |
+
* @param string|array $type The type(s) we want to check for
|
256 |
+
* @return bool True if the coupon is of the type
|
257 |
+
*/
|
258 |
+
public function is_type( $type ) {
|
259 |
+
//Backwards compatibility 2.2.11
|
260 |
+
if ( method_exists( $this->object, 'is_type' ) ) {
|
261 |
+
return $this->object->is_type( $type );
|
262 |
+
}
|
263 |
+
|
264 |
+
return ( $this->object->discount_type == $type || ( is_array( $type ) && in_array( $this->object->discount_type, $type ) ) ) ? true : false;
|
265 |
+
}
|
266 |
+
|
267 |
+
protected function set_meta_legacy( $meta_key, $value ) {
|
268 |
+
$this->maybe_get_custom_fields();
|
269 |
+
//WJECF()->log('...setting legacy meta ' . $meta_key );
|
270 |
+
$this->legacy_custom_fields[ $meta_key ] = array( $value );
|
271 |
+
$this->legacy_unsaved_keys[] = $meta_key;
|
272 |
+
}
|
273 |
+
|
274 |
+
/**
|
275 |
+
* Save the metadata
|
276 |
+
* @return id of this object
|
277 |
+
*/
|
278 |
+
public function save() {
|
279 |
+
//WJECF()->log('Saving ' . $this->get_id() );
|
280 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'save' ) ) ) {
|
281 |
+
return $this->object->save();
|
282 |
+
}
|
283 |
+
|
284 |
+
//Save the unsaved...
|
285 |
+
foreach( $this->legacy_unsaved_keys as $meta_key ) {
|
286 |
+
//WJECF()->log('...saving legacy meta ' . $meta_key );
|
287 |
+
$value = reset( $this->legacy_custom_fields[ $meta_key ] );
|
288 |
+
if ( $value === null ) {
|
289 |
+
delete_post_meta( $this->get_id(), $meta_key );
|
290 |
+
} else {
|
291 |
+
update_post_meta( $this->get_id(), $meta_key, $value );
|
292 |
+
}
|
293 |
+
}
|
294 |
+
$this->legacy_unsaved_keys = array();
|
295 |
+
|
296 |
+
return $this->get_id();
|
297 |
+
}
|
298 |
+
|
299 |
+
protected $legacy_custom_fields = null; // [ 'meta_key' => [ array_of_values ] ]
|
300 |
+
protected $legacy_unsaved_keys = array();
|
301 |
+
|
302 |
+
protected function maybe_get_custom_fields() {
|
303 |
+
//Read custom fields if not yet done
|
304 |
+
if ( is_null( $this->legacy_custom_fields ) ) {
|
305 |
+
$this->legacy_custom_fields = $this->object->coupon_custom_fields;
|
306 |
+
}
|
307 |
+
}
|
308 |
+
|
309 |
+
protected function get_meta_legacy( $meta_key, $single = true ) {
|
310 |
+
//Read custom fields if not yet done
|
311 |
+
$this->maybe_get_custom_fields();
|
312 |
+
|
313 |
+
if ( isset( $this->legacy_custom_fields[ $meta_key ] ) ) {
|
314 |
+
$values = $this->legacy_custom_fields[ $meta_key ];
|
315 |
+
//WP_CLI::log( "LEGACY:" . print_r( $values, true ));
|
316 |
+
if ($single) {
|
317 |
+
return maybe_unserialize( reset( $values ) ); //reset yields the first
|
318 |
+
}
|
319 |
+
$values = array_map( 'maybe_unserialize', $values );
|
320 |
+
return $values;
|
321 |
+
}
|
322 |
+
|
323 |
+
return $single ? '' : array();
|
324 |
+
}
|
325 |
+
|
326 |
+
}
|
327 |
+
|
328 |
+
class WJECF_Wrap_Product extends WJECF_Wrap {
|
329 |
+
|
330 |
+
protected $legacy_custom_fields = null; // [ 'meta_key' => [ array_of_values ] ]
|
331 |
+
protected $legacy_unsaved_keys = array();
|
332 |
+
|
333 |
+
protected function get_meta_legacy( $meta_key, $single = true ) {
|
334 |
+
if ( isset( $this->legacy_custom_fields[ $meta_key ] ) ) {
|
335 |
+
$values = $this->legacy_custom_fields[ $meta_key ];
|
336 |
+
//WP_CLI::log( "LEGACY:" . print_r( $values, true ));
|
337 |
+
if ($single) {
|
338 |
+
return maybe_unserialize( reset( $values ) ); //reset yields the first
|
339 |
+
}
|
340 |
+
$values = array_map( 'maybe_unserialize', $values );
|
341 |
+
return $values;
|
342 |
+
}
|
343 |
+
|
344 |
+
return get_post_meta( $this->get_product_or_variation_id(), $meta_key, $single );
|
345 |
+
}
|
346 |
+
|
347 |
+
public function set_meta_legacy( $meta_key, $value ) {
|
348 |
+
$this->legacy_custom_fields[ $meta_key ] = array( 0 => $value );
|
349 |
+
$this->legacy_unsaved_keys[] = $meta_key;
|
350 |
+
}
|
351 |
+
|
352 |
+
/**
|
353 |
+
* Combines get_meta or get_prop (in legacy WC those were the same thing, in WC3.0+ there is a difference)
|
354 |
+
* @param string $field_name
|
355 |
+
* @param bool $single
|
356 |
+
* @return
|
357 |
+
*/
|
358 |
+
public function get_field($field_name, $single = true) {
|
359 |
+
if ( $this->use_wc27 ) {
|
360 |
+
$values = $this->get_meta($field_name, $single);
|
361 |
+
if ( ! empty( $values ) ) return $values;
|
362 |
+
|
363 |
+
if ( is_callable( array( $this->object, 'get_prop' ) ) ) {
|
364 |
+
$value = $this->object->get_prop($field_name);
|
365 |
+
if ( ! empty( $value ) ) return $single ? $value : array( $value );
|
366 |
+
}
|
367 |
+
}
|
368 |
+
|
369 |
+
return get_post_meta( $this->get_product_or_variation_id(), $field_name, $single );
|
370 |
+
}
|
371 |
+
|
372 |
+
private function is_variation() {
|
373 |
+
return $this->object instanceof WC_Product_Variation;
|
374 |
+
}
|
375 |
+
|
376 |
+
/**
|
377 |
+
* Retrieve the id of the product or the variation id if it's a variant.
|
378 |
+
*
|
379 |
+
* (2.4.0: Moved from WJECF_Controller to WJECF_WC)
|
380 |
+
*
|
381 |
+
* @param WC_Product $product
|
382 |
+
* @return int|bool The variation or product id. False if not a valid product
|
383 |
+
*/
|
384 |
+
public function get_product_or_variation_id() {
|
385 |
+
if ( $this->is_variation() ) {
|
386 |
+
return $this->get_variation_id();
|
387 |
+
} elseif ( $this->object instanceof WC_Product ) {
|
388 |
+
return $this->get_id();
|
389 |
+
} else {
|
390 |
+
return false;
|
391 |
+
}
|
392 |
+
}
|
393 |
+
|
394 |
+
/**
|
395 |
+
* Retrieve the id of the parent product if it's a variation; otherwise retrieve this products id
|
396 |
+
*
|
397 |
+
* (2.4.0: Moved from WJECF_Controller to WJECF_WC)
|
398 |
+
*
|
399 |
+
* @param WC_Product $product
|
400 |
+
* @return int|bool The product id. False if this product is not a variation
|
401 |
+
*/
|
402 |
+
public function get_variable_product_id() {
|
403 |
+
if ( ! $this->is_variation() ) {
|
404 |
+
return false;
|
405 |
+
}
|
406 |
+
|
407 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_parent_id' ) ) ) {
|
408 |
+
return $this->object->get_parent_id();
|
409 |
+
} else {
|
410 |
+
return wp_get_post_parent_id( $this->object->variation_id );
|
411 |
+
}
|
412 |
+
}
|
413 |
+
|
414 |
+
/**
|
415 |
+
* Get current variation id
|
416 |
+
* @return int|bool False if this is not a variation
|
417 |
+
*/
|
418 |
+
protected function get_variation_id() {
|
419 |
+
if ( ! $this->is_variation() ) {
|
420 |
+
return false;
|
421 |
+
}
|
422 |
+
|
423 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_id' ) ) ) {
|
424 |
+
return $this->object->get_id();
|
425 |
+
} elseif ( $this->use_wc27 && is_callable( array( $this->object, 'get_variation_id' ) ) ) {
|
426 |
+
return $this->object->get_variation_id();
|
427 |
+
}
|
428 |
+
return $this->object->variation_id;
|
429 |
+
}
|
430 |
+
|
431 |
+
|
432 |
+
public function get_name() {
|
433 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_name' ) ) ) {
|
434 |
+
return $this->object->get_name();
|
435 |
+
} else {
|
436 |
+
return $this->object->post->post_title;
|
437 |
+
}
|
438 |
+
}
|
439 |
+
|
440 |
+
public function get_description() {
|
441 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_description' ) ) ) {
|
442 |
+
return $this->object->get_description();
|
443 |
+
} else {
|
444 |
+
return $this->object->post->post_content;
|
445 |
+
}
|
446 |
+
}
|
447 |
+
|
448 |
+
public function get_short_description() {
|
449 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_short_description' ) ) ) {
|
450 |
+
return $this->object->get_short_description();
|
451 |
+
} else {
|
452 |
+
return $this->object->post->post_excerpt;
|
453 |
+
}
|
454 |
+
}
|
455 |
+
|
456 |
+
public function get_status() {
|
457 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_status' ) ) ) {
|
458 |
+
return $this->object->get_status();
|
459 |
+
} else {
|
460 |
+
return $this->object->post->post_status;
|
461 |
+
}
|
462 |
+
}
|
463 |
+
|
464 |
+
public function get_tag_ids() {
|
465 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_tag_ids' ) ) ) {
|
466 |
+
return $this->object->get_tag_ids();
|
467 |
+
} else {
|
468 |
+
return $this->legacy_get_term_ids( 'product_tag' );
|
469 |
+
}
|
470 |
+
}
|
471 |
+
|
472 |
+
protected function legacy_get_term_ids( $taxonomy ) {
|
473 |
+
$terms = get_the_terms( $this->get_id(), $taxonomy );
|
474 |
+
if ( false === $terms || is_wp_error( $terms ) ) {
|
475 |
+
return array();
|
476 |
+
}
|
477 |
+
return wp_list_pluck( $terms, 'term_id' );
|
478 |
+
}
|
479 |
+
|
480 |
+
/**
|
481 |
+
* If set, get the default attributes for a variable product.
|
482 |
+
*
|
483 |
+
* @param string $attribute_name
|
484 |
+
* @return string
|
485 |
+
*/
|
486 |
+
public function get_variation_default_attribute( $attribute_name ) {
|
487 |
+
if ( $this->use_wc27 && is_callable( array( $this->object, 'get_variation_default_attribute' ) ) ) {
|
488 |
+
return $this->object->get_variation_default_attribute( $attribute_name );
|
489 |
+
}
|
490 |
+
return '';
|
491 |
+
}
|
492 |
+
}
|
493 |
+
|
494 |
+
|
495 |
+
class WJECF_Wrap_Customer extends WJECF_Wrap {
|
496 |
+
|
497 |
}
|
includes/admin/WJECF_Admin.php
CHANGED
@@ -1,457 +1,457 @@
|
|
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 |
-
add_action('woocommerce_coupon_options_usage_restriction', array( $this, 'on_woocommerce_coupon_options_usage_restriction' ), 20, 1);
|
34 |
-
|
35 |
-
add_action( 'wjecf_coupon_metabox_checkout', array( $this, 'admin_coupon_metabox_checkout' ), 10, 2 );
|
36 |
-
add_action( 'wjecf_coupon_metabox_customer', array( $this, 'admin_coupon_metabox_customer' ), 10, 2 );
|
37 |
-
//add_action( 'wjecf_coupon_metabox_misc', array( $this, 'admin_coupon_metabox_misc' ), 10, 2 );
|
38 |
-
|
39 |
-
$this->add_inline_style( '
|
40 |
-
#woocommerce-coupon-data .wjecf-not-wide { width:50% }
|
41 |
-
');
|
42 |
-
}
|
43 |
-
|
44 |
-
// ===========================================================================
|
45 |
-
// START - ADMIN NOTICES
|
46 |
-
// Allows notices to be displayed on the admin pages
|
47 |
-
// ===========================================================================
|
48 |
-
|
49 |
-
private $notices = array();
|
50 |
-
|
51 |
-
/**
|
52 |
-
* Enqueue a notice to display on the admin page
|
53 |
-
* @param stirng $html Please embed in <p> tags
|
54 |
-
* @param string $class
|
55 |
-
*/
|
56 |
-
public function enqueue_notice( $html, $class = 'notice-info' ) {
|
57 |
-
$this->notices[] = array( 'class' => $class, 'html' => $html );
|
58 |
-
}
|
59 |
-
|
60 |
-
public function admin_notices() {
|
61 |
-
foreach( $this->notices as $notice ) {
|
62 |
-
echo '<div class="notice ' . $notice['class'] . '">';
|
63 |
-
echo '<p><strong>WooCommerce Extended Coupon Features</strong> – ';
|
64 |
-
echo $notice['html'];
|
65 |
-
echo '</div>';
|
66 |
-
}
|
67 |
-
$this->notices = array();
|
68 |
-
}
|
69 |
-
|
70 |
-
// ===========================================================================
|
71 |
-
// END - ADMIN NOTICES
|
72 |
-
// ===========================================================================
|
73 |
-
|
74 |
-
//2.3.6 Inline css
|
75 |
-
private $admin_css = '';
|
76 |
-
|
77 |
-
/**
|
78 |
-
* 2.3.6
|
79 |
-
* @return void
|
80 |
-
*/
|
81 |
-
function on_admin_head() {
|
82 |
-
//Output inline style for the admin pages
|
83 |
-
if ( ! empty( $this->admin_css ) ) {
|
84 |
-
echo '<style type="text/css">' . $this->admin_css . '</style>';
|
85 |
-
$this->admin_css = '';
|
86 |
-
}
|
87 |
-
|
88 |
-
//Enqueue scripts
|
89 |
-
wp_enqueue_script( "wjecf-admin", WJECF()->plugin_url() . "assets/js/wjecf-admin.js", array( 'jquery' ), WJECF()->plugin_version() );
|
90 |
-
wp_localize_script( 'wjecf-admin', 'wjecf_admin_i18n', array(
|
91 |
-
'label_and' => __( '(AND)', 'woocommerce-jos-autocoupon' ),
|
92 |
-
'label_or' => __( '(OR)', 'woocommerce-jos-autocoupon' )
|
93 |
-
) );
|
94 |
-
|
95 |
-
}
|
96 |
-
|
97 |
-
//Add tabs to the coupon option page
|
98 |
-
public function admin_coupon_options_tabs( $tabs ) {
|
99 |
-
|
100 |
-
$tabs['extended_features_checkout'] = array(
|
101 |
-
'label' => __( 'Checkout', 'woocommerce-jos-autocoupon' ),
|
102 |
-
'target' => 'wjecf_coupondata_checkout',
|
103 |
-
'class' => 'wjecf_coupondata_checkout',
|
104 |
-
);
|
105 |
-
|
106 |
-
$tabs['extended_features_misc'] = array(
|
107 |
-
'label' => __( 'Miscellaneous', 'woocommerce-jos-autocoupon' ),
|
108 |
-
'target' => 'wjecf_coupondata_misc',
|
109 |
-
'class' => 'wjecf_coupondata_misc',
|
110 |
-
);
|
111 |
-
|
112 |
-
return $tabs;
|
113 |
-
}
|
114 |
-
|
115 |
-
//Add panels to the coupon option page
|
116 |
-
public function admin_coupon_options_panels() {
|
117 |
-
global $thepostid, $post;
|
118 |
-
$thepostid = empty( $thepostid ) ? $post->ID : $thepostid;
|
119 |
-
?>
|
120 |
-
<div id="wjecf_coupondata_checkout" class="panel woocommerce_options_panel">
|
121 |
-
<?php
|
122 |
-
do_action( 'wjecf_coupon_metabox_checkout', $thepostid, $post );
|
123 |
-
do_action( 'wjecf_coupon_metabox_customer', $thepostid, $post );
|
124 |
-
$this->admin_coupon_data_footer();
|
125 |
-
?>
|
126 |
-
</div>
|
127 |
-
<div id="wjecf_coupondata_misc" class="panel woocommerce_options_panel">
|
128 |
-
<?php
|
129 |
-
//Allow other classes to inject options
|
130 |
-
do_action( 'wjecf_woocommerce_coupon_options_extended_features', $thepostid, $post );
|
131 |
-
do_action( 'wjecf_coupon_metabox_misc', $thepostid, $post );
|
132 |
-
$this->admin_coupon_data_footer();
|
133 |
-
?>
|
134 |
-
</div>
|
135 |
-
<?php
|
136 |
-
}
|
137 |
-
|
138 |
-
public function admin_coupon_data_footer() {
|
139 |
-
$documentation_url = WJECF()->plugin_url( 'docs/index.html' );
|
140 |
-
if ( ! WJECF()->is_pro() ) {
|
141 |
-
$documentation_url = 'http://www.soft79.nl/documentation/wjecf';
|
142 |
-
?>
|
143 |
-
<h3><?php _e( 'Do you find WooCommerce Extended Coupon Features useful?', 'woocommerce-jos-autocoupon'); ?></h3>
|
144 |
-
<p class="form-field"><label for="wjecf_donate_button"><?php
|
145 |
-
echo esc_html( __('Express your gratitude', 'woocommerce-jos-autocoupon' ) );
|
146 |
-
?></label>
|
147 |
-
<a id="wjecf_donate_button" href="<?php echo $this->get_donate_url(); ?>" target="_blank" class="button button-primary">
|
148 |
-
<?php
|
149 |
-
echo esc_html( __('Donate to the developer', 'woocommerce-jos-autocoupon' ) );
|
150 |
-
?></a><br>
|
151 |
-
Or get the PRO version at <a href="http://www.soft79.nl" target="_blank">www.soft79.nl</a>.
|
152 |
-
</p>
|
153 |
-
<?php
|
154 |
-
}
|
155 |
-
//Documentation link
|
156 |
-
echo '<h3>' . __( 'Documentation', 'woocommerce-jos-autocoupon' ) . '</h3>';
|
157 |
-
echo '<p><a href="' . $documentation_url . '" target="_blank">' .
|
158 |
-
__( 'WooCommerce Extended Coupon Features Documentation', 'woocommerce-jos-autocoupon' ) . '</a></p>';
|
159 |
-
|
160 |
-
}
|
161 |
-
|
162 |
-
// //Tab 'extended features'
|
163 |
-
//public function admin_coupon_metabox_products( $thepostid, $post ) {
|
164 |
-
|
165 |
-
//since 2.5.0 moved to the 'Usage restriction' tab
|
166 |
-
public function on_woocommerce_coupon_options_usage_restriction() {
|
167 |
-
global $thepostid, $post;
|
168 |
-
$thepostid = empty( $thepostid ) ? $post->ID : $thepostid;
|
169 |
-
|
170 |
-
//See WooCommerce class-wc-meta-box-coupon-data.php function ouput
|
171 |
-
|
172 |
-
echo "<h3>" . esc_html( __( 'Matching products', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
|
173 |
-
//=============================
|
174 |
-
// AND instead of OR the products
|
175 |
-
WJECF_Admin_Html::render_select_with_default( array(
|
176 |
-
'id' => '_wjecf_products_and',
|
177 |
-
'label' => __( 'Products Operator', 'woocommerce-jos-autocoupon' ),
|
178 |
-
'options' => array( 'no' => __( 'OR', 'woocommerce-jos-autocoupon' ), 'yes' => __( 'AND', 'woocommerce-jos-autocoupon' ) ),
|
179 |
-
'default_value' => 'no',
|
180 |
-
'class' => 'wjecf-not-wide',
|
181 |
-
/* 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).' */
|
182 |
-
'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' ),
|
183 |
-
'desc_tip' => true
|
184 |
-
) );
|
185 |
-
|
186 |
-
//=============================
|
187 |
-
// 2.2.3.1 AND instead of OR the categories
|
188 |
-
WJECF_Admin_Html::render_select_with_default( array(
|
189 |
-
'id' => '_wjecf_categories_and',
|
190 |
-
'label' => __( 'Categories Operator', 'woocommerce-jos-autocoupon' ),
|
191 |
-
'options' => array( 'no' => __( 'OR', 'woocommerce-jos-autocoupon' ), 'yes' => __( 'AND', 'woocommerce-jos-autocoupon' ) ),
|
192 |
-
'default_value' => 'no',
|
193 |
-
'class' => 'wjecf-not-wide',
|
194 |
-
/* 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).' */
|
195 |
-
'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' ),
|
196 |
-
'desc_tip' => true
|
197 |
-
) );
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
// Minimum quantity of matching products (product/category)
|
202 |
-
woocommerce_wp_text_input( array(
|
203 |
-
'id' => '_wjecf_min_matching_product_qty',
|
204 |
-
'label' => __( 'Minimum quantity of matching products', 'woocommerce-jos-autocoupon' ),
|
205 |
-
'placeholder' => __( 'No minimum', 'woocommerce' ),
|
206 |
-
'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' ),
|
207 |
-
'data_type' => 'decimal',
|
208 |
-
'desc_tip' => true
|
209 |
-
) );
|
210 |
-
|
211 |
-
// Maximum quantity of matching products (product/category)
|
212 |
-
woocommerce_wp_text_input( array(
|
213 |
-
'id' => '_wjecf_max_matching_product_qty',
|
214 |
-
'label' => __( 'Maximum quantity of matching products', 'woocommerce-jos-autocoupon' ),
|
215 |
-
'placeholder' => __( 'No maximum', 'woocommerce' ),
|
216 |
-
'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' ),
|
217 |
-
'data_type' => 'decimal',
|
218 |
-
'desc_tip' => true
|
219 |
-
) );
|
220 |
-
|
221 |
-
// Minimum subtotal of matching products (product/category)
|
222 |
-
woocommerce_wp_text_input( array(
|
223 |
-
'id' => '_wjecf_min_matching_product_subtotal',
|
224 |
-
'label' => __( 'Minimum subtotal of matching products', 'woocommerce-jos-autocoupon' ),
|
225 |
-
'placeholder' => __( 'No minimum', 'woocommerce' ),
|
226 |
-
'description' => __( 'Minimum price subtotal of the products that match the given product or category restrictions (see tab \'usage restriction\').', 'woocommerce-jos-autocoupon' ),
|
227 |
-
'data_type' => 'price',
|
228 |
-
'desc_tip' => true
|
229 |
-
) );
|
230 |
-
|
231 |
-
// Maximum subtotal of matching products (product/category)
|
232 |
-
woocommerce_wp_text_input( array(
|
233 |
-
'id' => '_wjecf_max_matching_product_subtotal',
|
234 |
-
'label' => __( 'Maximum subtotal of matching products', 'woocommerce-jos-autocoupon' ),
|
235 |
-
'placeholder' => __( 'No maximum', 'woocommerce' ),
|
236 |
-
'description' => __( 'Maximum price subtotal of the products that match the given product or category restrictions (see tab \'usage restriction\').', 'woocommerce-jos-autocoupon' ),
|
237 |
-
'data_type' => 'price',
|
238 |
-
'desc_tip' => true
|
239 |
-
) );
|
240 |
-
}
|
241 |
-
|
242 |
-
public function admin_coupon_metabox_checkout( $thepostid, $post ) {
|
243 |
-
|
244 |
-
echo "<h3>" . esc_html( __( 'Checkout', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
|
245 |
-
|
246 |
-
//=============================
|
247 |
-
// Shipping methods
|
248 |
-
?>
|
249 |
-
<p class="form-field"><label for="wjecf_shipping_methods"><?php _e( 'Shipping methods', 'woocommerce-jos-autocoupon' ); ?></label>
|
250 |
-
<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' ); ?>">
|
251 |
-
<?php
|
252 |
-
$coupon_shipping_method_ids = WJECF()->get_coupon_shipping_method_ids( $thepostid );
|
253 |
-
$shipping_methods = WC()->shipping->load_shipping_methods();
|
254 |
-
|
255 |
-
if ( $shipping_methods ) foreach ( $shipping_methods as $shipping_method ) {
|
256 |
-
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>';
|
257 |
-
}
|
258 |
-
?>
|
259 |
-
</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' ) ); ?>
|
260 |
-
</p>
|
261 |
-
<?php
|
262 |
-
|
263 |
-
//=============================
|
264 |
-
// Payment methods
|
265 |
-
?>
|
266 |
-
<p class="form-field"><label for="wjecf_payment_methods"><?php _e( 'Payment methods', 'woocommerce-jos-autocoupon' ); ?></label>
|
267 |
-
<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' ); ?>">
|
268 |
-
<?php
|
269 |
-
$coupon_payment_method_ids = WJECF()->get_coupon_payment_method_ids( $thepostid );
|
270 |
-
//DONT USE WC()->payment_gateways->available_payment_gateways() AS IT CAN CRASH IN UNKNOWN OCCASIONS
|
271 |
-
$payment_methods = WC()->payment_gateways->payment_gateways();
|
272 |
-
if ( $payment_methods ) foreach ( $payment_methods as $payment_method ) {
|
273 |
-
if ('yes' === $payment_method->enabled) {
|
274 |
-
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>';
|
275 |
-
}
|
276 |
-
}
|
277 |
-
?>
|
278 |
-
</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' ) ); ?>
|
279 |
-
</p>
|
280 |
-
<?php
|
281 |
-
}
|
282 |
-
|
283 |
-
public function admin_coupon_metabox_customer( $thepostid, $post ) {
|
284 |
-
|
285 |
-
//=============================
|
286 |
-
//Title: "CUSTOMER RESTRICTIONS"
|
287 |
-
echo "<h3>" . esc_html( __( 'Customer restrictions', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
|
288 |
-
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";
|
289 |
-
|
290 |
-
//=============================
|
291 |
-
// User ids
|
292 |
-
?>
|
293 |
-
<p class="form-field"><label><?php _e( 'Allowed Customers', 'woocommerce-jos-autocoupon' ); ?></label>
|
294 |
-
<?php
|
295 |
-
$coupon_customer_ids = WJECF()->get_coupon_customer_ids( $thepostid );
|
296 |
-
WJECF_Admin_Html::render_admin_customer_selector( 'wjecf_customer_ids', '_wjecf_customer_ids', $coupon_customer_ids );
|
297 |
-
echo WJECF_Admin_Html::wc_help_tip( __( 'Only these customers may use this coupon.', 'woocommerce-jos-autocoupon' ) );
|
298 |
-
?>
|
299 |
-
</p>
|
300 |
-
<?php
|
301 |
-
|
302 |
-
//=============================
|
303 |
-
// User roles
|
304 |
-
?>
|
305 |
-
<p class="form-field"><label for="wjecf_customer_roles"><?php _e( 'Allowed User Roles', 'woocommerce-jos-autocoupon' ); ?></label>
|
306 |
-
<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' ); ?>">
|
307 |
-
<?php
|
308 |
-
$coupon_customer_roles = WJECF()->get_coupon_customer_roles( $thepostid );
|
309 |
-
|
310 |
-
$available_customer_roles = array_reverse( get_editable_roles() );
|
311 |
-
foreach ( $available_customer_roles as $role_id => $role ) {
|
312 |
-
$role_name = translate_user_role($role['name'] );
|
313 |
-
|
314 |
-
echo '<option value="' . esc_attr( $role_id ) . '"'
|
315 |
-
. selected( in_array( $role_id, $coupon_customer_roles ), true, false ) . '>'
|
316 |
-
. esc_html( $role_name ) . '</option>';
|
317 |
-
}
|
318 |
-
?>
|
319 |
-
</select>
|
320 |
-
<?php echo WJECF_Admin_Html::wc_help_tip( __( 'Only these User Roles may use this coupon.', 'woocommerce-jos-autocoupon' ) ); ?>
|
321 |
-
</p>
|
322 |
-
<?php
|
323 |
-
|
324 |
-
//=============================
|
325 |
-
// Excluded user roles
|
326 |
-
?>
|
327 |
-
<p class="form-field"><label for="wjecf_excluded_customer_roles"><?php _e( 'Disallowed User Roles', 'woocommerce-jos-autocoupon' ); ?></label>
|
328 |
-
<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' ); ?>">
|
329 |
-
<?php
|
330 |
-
$coupon_excluded_customer_roles = WJECF()->get_coupon_excluded_customer_roles( $thepostid );
|
331 |
-
|
332 |
-
foreach ( $available_customer_roles as $role_id => $role ) {
|
333 |
-
$role_name = translate_user_role($role['name'] );
|
334 |
-
|
335 |
-
echo '<option value="' . esc_attr( $role_id ) . '"'
|
336 |
-
. selected( in_array( $role_id, $coupon_excluded_customer_roles ), true, false ) . '>'
|
337 |
-
. esc_html( $role_name ) . '</option>';
|
338 |
-
}
|
339 |
-
?>
|
340 |
-
</select>
|
341 |
-
<?php echo WJECF_Admin_Html::wc_help_tip( __( 'These User Roles will be specifically excluded from using this coupon.', 'woocommerce-jos-autocoupon' ) ); ?>
|
342 |
-
</p>
|
343 |
-
<?php
|
344 |
-
}
|
345 |
-
|
346 |
-
public function admin_coupon_meta_fields( $coupon ) {
|
347 |
-
$fields = array(
|
348 |
-
'_wjecf_min_matching_product_qty' => 'int',
|
349 |
-
'_wjecf_max_matching_product_qty' => 'int',
|
350 |
-
'_wjecf_min_matching_product_subtotal' => 'decimal',
|
351 |
-
'_wjecf_max_matching_product_subtotal' => 'decimal',
|
352 |
-
'_wjecf_products_and' => 'yesno',
|
353 |
-
'_wjecf_categories_and' => 'yesno',
|
354 |
-
'_wjecf_shipping_methods' => 'clean',
|
355 |
-
'_wjecf_payment_methods' => 'clean',
|
356 |
-
'_wjecf_customer_ids' => 'int,',
|
357 |
-
'_wjecf_customer_roles' => 'clean',
|
358 |
-
'_wjecf_excluded_customer_roles' => 'clean'
|
359 |
-
);
|
360 |
-
|
361 |
-
//Espagueti
|
362 |
-
if ( WJECF()->is_pro() ) {
|
363 |
-
$fields = array_merge( $fields, WJECF()->admin_coupon_meta_fields( $coupon ) );
|
364 |
-
}
|
365 |
-
return $fields;
|
366 |
-
}
|
367 |
-
|
368 |
-
/**
|
369 |
-
* Get an array with all the metafields for all the WJECF plugins
|
370 |
-
*
|
371 |
-
* @see Abstract_WJECF_Plugin::admin_coupon_meta_fields()
|
372 |
-
*
|
373 |
-
* @param type $coupon
|
374 |
-
* @return type
|
375 |
-
*/
|
376 |
-
function get_all_coupon_meta_fields( $coupon ) {
|
377 |
-
//Collect the meta_fields of all the WJECF plugins
|
378 |
-
$fields = array();
|
379 |
-
foreach ( WJECF()->get_plugins() as $name => $plugin ) {
|
380 |
-
if ( $plugin->plugin_is_enabled() ) {
|
381 |
-
$fields = array_merge( $fields, $plugin->admin_coupon_meta_fields( $coupon ) );
|
382 |
-
}
|
383 |
-
}
|
384 |
-
return $fields;
|
385 |
-
}
|
386 |
-
|
387 |
-
function process_shop_coupon_meta( $post_id, $post ) {
|
388 |
-
$coupon = WJECF_WC()->get_coupon( $post );
|
389 |
-
$wrap_coupon = WJECF_Wrap( $coupon );
|
390 |
-
$sanitizer = WJECF()->sanitizer();
|
391 |
-
|
392 |
-
$fields = $this->get_all_coupon_meta_fields( $coupon );
|
393 |
-
foreach( $fields as $key => $rule ) {
|
394 |
-
//If array contains [ 'callback' => callback, 'args' => args[] ]
|
395 |
-
//Then that callback will be called with the given args (optional)
|
396 |
-
|
397 |
-
if ( is_array( $rule ) && isset( $rule['callback'] ) && is_callable( $rule['callback'] ) ) {
|
398 |
-
$args = array( 'key' => $key );
|
399 |
-
if ( isset( $rule['args'] ) ) $args = array_merge( $args, $rule['args'] );
|
400 |
-
|
401 |
-
$value = call_user_func( $rule['callback'], $args );
|
402 |
-
} else {
|
403 |
-
$value = $sanitizer->sanitize( isset( $_POST[$key] ) ? $_POST[$key] : null, $rule );
|
404 |
-
}
|
405 |
-
if ( $value === '' ) $value = null; //Don't save empty entries
|
406 |
-
|
407 |
-
$wrap_coupon->set_meta( $key, $value ); //Always single
|
408 |
-
|
409 |
-
//error_log(sprintf("%s => %s", $key, is_array($value) ? 'array' : $value));
|
410 |
-
}
|
411 |
-
|
412 |
-
$wrap_coupon->save();
|
413 |
-
}
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
/**
|
418 |
-
* 2.3.6
|
419 |
-
* Add inline style (css) to the admin page. Must be called BEFORE admin_head !
|
420 |
-
* @param string $css
|
421 |
-
* @return void
|
422 |
-
*/
|
423 |
-
public function add_inline_style( $css ) {
|
424 |
-
$this->admin_css .= $css;
|
425 |
-
}
|
426 |
-
|
427 |
-
|
428 |
-
/**
|
429 |
-
*
|
430 |
-
* 2.3.4
|
431 |
-
* Parse an array or comma separated string; make sure they are valid ints and return as comma separated string
|
432 |
-
* @deprecated 2.5.1 Use WJECF()->sanitizer->sanitize( ..., 'int[]' ) instead
|
433 |
-
* @param array|string $int_array
|
434 |
-
* @return string comma separated int array
|
435 |
-
*/
|
436 |
-
public function comma_separated_int_array( $int_array ) {
|
437 |
-
_deprecated_function( 'comma_separated_int_array', '2.5.1', 'WJECF()->sanitizer->sanitize()' );
|
438 |
-
return WJECF()->sanitizer->sanitize( $int_array, 'int[]' );
|
439 |
-
}
|
440 |
-
|
441 |
-
/**
|
442 |
-
* Add donate-link to plugin page
|
443 |
-
*/
|
444 |
-
function wjecf_plugin_meta( $links, $file ) {
|
445 |
-
if ( strpos( $file, 'woocommerce-jos-autocoupon.php' ) !== false ) {
|
446 |
-
$links = array_merge( $links, array( '<a href="' . WJECF_Admin::get_donate_url() . '" title="Support the development" target="_blank">Donate</a>' ) );
|
447 |
-
}
|
448 |
-
return $links;
|
449 |
-
}
|
450 |
-
|
451 |
-
|
452 |
-
public static function get_donate_url() {
|
453 |
-
return "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=5T9XQBCS2QHRY&lc=NL&item_name=Jos%20Koenis&item_number=wordpress%2dplugin¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted";
|
454 |
-
}
|
455 |
-
}
|
456 |
-
|
457 |
}
|
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 |
+
add_action('woocommerce_coupon_options_usage_restriction', array( $this, 'on_woocommerce_coupon_options_usage_restriction' ), 20, 1);
|
34 |
+
|
35 |
+
add_action( 'wjecf_coupon_metabox_checkout', array( $this, 'admin_coupon_metabox_checkout' ), 10, 2 );
|
36 |
+
add_action( 'wjecf_coupon_metabox_customer', array( $this, 'admin_coupon_metabox_customer' ), 10, 2 );
|
37 |
+
//add_action( 'wjecf_coupon_metabox_misc', array( $this, 'admin_coupon_metabox_misc' ), 10, 2 );
|
38 |
+
|
39 |
+
$this->add_inline_style( '
|
40 |
+
#woocommerce-coupon-data .wjecf-not-wide { width:50% }
|
41 |
+
');
|
42 |
+
}
|
43 |
+
|
44 |
+
// ===========================================================================
|
45 |
+
// START - ADMIN NOTICES
|
46 |
+
// Allows notices to be displayed on the admin pages
|
47 |
+
// ===========================================================================
|
48 |
+
|
49 |
+
private $notices = array();
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Enqueue a notice to display on the admin page
|
53 |
+
* @param stirng $html Please embed in <p> tags
|
54 |
+
* @param string $class
|
55 |
+
*/
|
56 |
+
public function enqueue_notice( $html, $class = 'notice-info' ) {
|
57 |
+
$this->notices[] = array( 'class' => $class, 'html' => $html );
|
58 |
+
}
|
59 |
+
|
60 |
+
public function admin_notices() {
|
61 |
+
foreach( $this->notices as $notice ) {
|
62 |
+
echo '<div class="notice ' . $notice['class'] . '">';
|
63 |
+
echo '<p><strong>WooCommerce Extended Coupon Features</strong> – ';
|
64 |
+
echo $notice['html'];
|
65 |
+
echo '</div>';
|
66 |
+
}
|
67 |
+
$this->notices = array();
|
68 |
+
}
|
69 |
+
|
70 |
+
// ===========================================================================
|
71 |
+
// END - ADMIN NOTICES
|
72 |
+
// ===========================================================================
|
73 |
+
|
74 |
+
//2.3.6 Inline css
|
75 |
+
private $admin_css = '';
|
76 |
+
|
77 |
+
/**
|
78 |
+
* 2.3.6
|
79 |
+
* @return void
|
80 |
+
*/
|
81 |
+
function on_admin_head() {
|
82 |
+
//Output inline style for the admin pages
|
83 |
+
if ( ! empty( $this->admin_css ) ) {
|
84 |
+
echo '<style type="text/css">' . $this->admin_css . '</style>';
|
85 |
+
$this->admin_css = '';
|
86 |
+
}
|
87 |
+
|
88 |
+
//Enqueue scripts
|
89 |
+
wp_enqueue_script( "wjecf-admin", WJECF()->plugin_url() . "assets/js/wjecf-admin.js", array( 'jquery' ), WJECF()->plugin_version() );
|
90 |
+
wp_localize_script( 'wjecf-admin', 'wjecf_admin_i18n', array(
|
91 |
+
'label_and' => __( '(AND)', 'woocommerce-jos-autocoupon' ),
|
92 |
+
'label_or' => __( '(OR)', 'woocommerce-jos-autocoupon' )
|
93 |
+
) );
|
94 |
+
|
95 |
+
}
|
96 |
+
|
97 |
+
//Add tabs to the coupon option page
|
98 |
+
public function admin_coupon_options_tabs( $tabs ) {
|
99 |
+
|
100 |
+
$tabs['extended_features_checkout'] = array(
|
101 |
+
'label' => __( 'Checkout', 'woocommerce-jos-autocoupon' ),
|
102 |
+
'target' => 'wjecf_coupondata_checkout',
|
103 |
+
'class' => 'wjecf_coupondata_checkout',
|
104 |
+
);
|
105 |
+
|
106 |
+
$tabs['extended_features_misc'] = array(
|
107 |
+
'label' => __( 'Miscellaneous', 'woocommerce-jos-autocoupon' ),
|
108 |
+
'target' => 'wjecf_coupondata_misc',
|
109 |
+
'class' => 'wjecf_coupondata_misc',
|
110 |
+
);
|
111 |
+
|
112 |
+
return $tabs;
|
113 |
+
}
|
114 |
+
|
115 |
+
//Add panels to the coupon option page
|
116 |
+
public function admin_coupon_options_panels() {
|
117 |
+
global $thepostid, $post;
|
118 |
+
$thepostid = empty( $thepostid ) ? $post->ID : $thepostid;
|
119 |
+
?>
|
120 |
+
<div id="wjecf_coupondata_checkout" class="panel woocommerce_options_panel">
|
121 |
+
<?php
|
122 |
+
do_action( 'wjecf_coupon_metabox_checkout', $thepostid, $post );
|
123 |
+
do_action( 'wjecf_coupon_metabox_customer', $thepostid, $post );
|
124 |
+
$this->admin_coupon_data_footer();
|
125 |
+
?>
|
126 |
+
</div>
|
127 |
+
<div id="wjecf_coupondata_misc" class="panel woocommerce_options_panel">
|
128 |
+
<?php
|
129 |
+
//Allow other classes to inject options
|
130 |
+
do_action( 'wjecf_woocommerce_coupon_options_extended_features', $thepostid, $post );
|
131 |
+
do_action( 'wjecf_coupon_metabox_misc', $thepostid, $post );
|
132 |
+
$this->admin_coupon_data_footer();
|
133 |
+
?>
|
134 |
+
</div>
|
135 |
+
<?php
|
136 |
+
}
|
137 |
+
|
138 |
+
public function admin_coupon_data_footer() {
|
139 |
+
$documentation_url = WJECF()->plugin_url( 'docs/index.html' );
|
140 |
+
if ( ! WJECF()->is_pro() ) {
|
141 |
+
$documentation_url = 'http://www.soft79.nl/documentation/wjecf';
|
142 |
+
?>
|
143 |
+
<h3><?php _e( 'Do you find WooCommerce Extended Coupon Features useful?', 'woocommerce-jos-autocoupon'); ?></h3>
|
144 |
+
<p class="form-field"><label for="wjecf_donate_button"><?php
|
145 |
+
echo esc_html( __('Express your gratitude', 'woocommerce-jos-autocoupon' ) );
|
146 |
+
?></label>
|
147 |
+
<a id="wjecf_donate_button" href="<?php echo $this->get_donate_url(); ?>" target="_blank" class="button button-primary">
|
148 |
+
<?php
|
149 |
+
echo esc_html( __('Donate to the developer', 'woocommerce-jos-autocoupon' ) );
|
150 |
+
?></a><br>
|
151 |
+
Or get the PRO version at <a href="http://www.soft79.nl" target="_blank">www.soft79.nl</a>.
|
152 |
+
</p>
|
153 |
+
<?php
|
154 |
+
}
|
155 |
+
//Documentation link
|
156 |
+
echo '<h3>' . __( 'Documentation', 'woocommerce-jos-autocoupon' ) . '</h3>';
|
157 |
+
echo '<p><a href="' . $documentation_url . '" target="_blank">' .
|
158 |
+
__( 'WooCommerce Extended Coupon Features Documentation', 'woocommerce-jos-autocoupon' ) . '</a></p>';
|
159 |
+
|
160 |
+
}
|
161 |
+
|
162 |
+
// //Tab 'extended features'
|
163 |
+
//public function admin_coupon_metabox_products( $thepostid, $post ) {
|
164 |
+
|
165 |
+
//since 2.5.0 moved to the 'Usage restriction' tab
|
166 |
+
public function on_woocommerce_coupon_options_usage_restriction() {
|
167 |
+
global $thepostid, $post;
|
168 |
+
$thepostid = empty( $thepostid ) ? $post->ID : $thepostid;
|
169 |
+
|
170 |
+
//See WooCommerce class-wc-meta-box-coupon-data.php function ouput
|
171 |
+
|
172 |
+
echo "<h3>" . esc_html( __( 'Matching products', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
|
173 |
+
//=============================
|
174 |
+
// AND instead of OR the products
|
175 |
+
WJECF_Admin_Html::render_select_with_default( array(
|
176 |
+
'id' => '_wjecf_products_and',
|
177 |
+
'label' => __( 'Products Operator', 'woocommerce-jos-autocoupon' ),
|
178 |
+
'options' => array( 'no' => __( 'OR', 'woocommerce-jos-autocoupon' ), 'yes' => __( 'AND', 'woocommerce-jos-autocoupon' ) ),
|
179 |
+
'default_value' => 'no',
|
180 |
+
'class' => 'wjecf-not-wide',
|
181 |
+
/* 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).' */
|
182 |
+
'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' ),
|
183 |
+
'desc_tip' => true
|
184 |
+
) );
|
185 |
+
|
186 |
+
//=============================
|
187 |
+
// 2.2.3.1 AND instead of OR the categories
|
188 |
+
WJECF_Admin_Html::render_select_with_default( array(
|
189 |
+
'id' => '_wjecf_categories_and',
|
190 |
+
'label' => __( 'Categories Operator', 'woocommerce-jos-autocoupon' ),
|
191 |
+
'options' => array( 'no' => __( 'OR', 'woocommerce-jos-autocoupon' ), 'yes' => __( 'AND', 'woocommerce-jos-autocoupon' ) ),
|
192 |
+
'default_value' => 'no',
|
193 |
+
'class' => 'wjecf-not-wide',
|
194 |
+
/* 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).' */
|
195 |
+
'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' ),
|
196 |
+
'desc_tip' => true
|
197 |
+
) );
|
198 |
+
|
199 |
+
|
200 |
+
|
201 |
+
// Minimum quantity of matching products (product/category)
|
202 |
+
woocommerce_wp_text_input( array(
|
203 |
+
'id' => '_wjecf_min_matching_product_qty',
|
204 |
+
'label' => __( 'Minimum quantity of matching products', 'woocommerce-jos-autocoupon' ),
|
205 |
+
'placeholder' => __( 'No minimum', 'woocommerce' ),
|
206 |
+
'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' ),
|
207 |
+
'data_type' => 'decimal',
|
208 |
+
'desc_tip' => true
|
209 |
+
) );
|
210 |
+
|
211 |
+
// Maximum quantity of matching products (product/category)
|
212 |
+
woocommerce_wp_text_input( array(
|
213 |
+
'id' => '_wjecf_max_matching_product_qty',
|
214 |
+
'label' => __( 'Maximum quantity of matching products', 'woocommerce-jos-autocoupon' ),
|
215 |
+
'placeholder' => __( 'No maximum', 'woocommerce' ),
|
216 |
+
'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' ),
|
217 |
+
'data_type' => 'decimal',
|
218 |
+
'desc_tip' => true
|
219 |
+
) );
|
220 |
+
|
221 |
+
// Minimum subtotal of matching products (product/category)
|
222 |
+
woocommerce_wp_text_input( array(
|
223 |
+
'id' => '_wjecf_min_matching_product_subtotal',
|
224 |
+
'label' => __( 'Minimum subtotal of matching products', 'woocommerce-jos-autocoupon' ),
|
225 |
+
'placeholder' => __( 'No minimum', 'woocommerce' ),
|
226 |
+
'description' => __( 'Minimum price subtotal of the products that match the given product or category restrictions (see tab \'usage restriction\').', 'woocommerce-jos-autocoupon' ),
|
227 |
+
'data_type' => 'price',
|
228 |
+
'desc_tip' => true
|
229 |
+
) );
|
230 |
+
|
231 |
+
// Maximum subtotal of matching products (product/category)
|
232 |
+
woocommerce_wp_text_input( array(
|
233 |
+
'id' => '_wjecf_max_matching_product_subtotal',
|
234 |
+
'label' => __( 'Maximum subtotal of matching products', 'woocommerce-jos-autocoupon' ),
|
235 |
+
'placeholder' => __( 'No maximum', 'woocommerce' ),
|
236 |
+
'description' => __( 'Maximum price subtotal of the products that match the given product or category restrictions (see tab \'usage restriction\').', 'woocommerce-jos-autocoupon' ),
|
237 |
+
'data_type' => 'price',
|
238 |
+
'desc_tip' => true
|
239 |
+
) );
|
240 |
+
}
|
241 |
+
|
242 |
+
public function admin_coupon_metabox_checkout( $thepostid, $post ) {
|
243 |
+
|
244 |
+
echo "<h3>" . esc_html( __( 'Checkout', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
|
245 |
+
|
246 |
+
//=============================
|
247 |
+
// Shipping methods
|
248 |
+
?>
|
249 |
+
<p class="form-field"><label for="wjecf_shipping_methods"><?php _e( 'Shipping methods', 'woocommerce-jos-autocoupon' ); ?></label>
|
250 |
+
<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' ); ?>">
|
251 |
+
<?php
|
252 |
+
$coupon_shipping_method_ids = WJECF()->get_coupon_shipping_method_ids( $thepostid );
|
253 |
+
$shipping_methods = WC()->shipping->load_shipping_methods();
|
254 |
+
|
255 |
+
if ( $shipping_methods ) foreach ( $shipping_methods as $shipping_method ) {
|
256 |
+
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>';
|
257 |
+
}
|
258 |
+
?>
|
259 |
+
</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' ) ); ?>
|
260 |
+
</p>
|
261 |
+
<?php
|
262 |
+
|
263 |
+
//=============================
|
264 |
+
// Payment methods
|
265 |
+
?>
|
266 |
+
<p class="form-field"><label for="wjecf_payment_methods"><?php _e( 'Payment methods', 'woocommerce-jos-autocoupon' ); ?></label>
|
267 |
+
<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' ); ?>">
|
268 |
+
<?php
|
269 |
+
$coupon_payment_method_ids = WJECF()->get_coupon_payment_method_ids( $thepostid );
|
270 |
+
//DONT USE WC()->payment_gateways->available_payment_gateways() AS IT CAN CRASH IN UNKNOWN OCCASIONS
|
271 |
+
$payment_methods = WC()->payment_gateways->payment_gateways();
|
272 |
+
if ( $payment_methods ) foreach ( $payment_methods as $payment_method ) {
|
273 |
+
if ('yes' === $payment_method->enabled) {
|
274 |
+
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>';
|
275 |
+
}
|
276 |
+
}
|
277 |
+
?>
|
278 |
+
</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' ) ); ?>
|
279 |
+
</p>
|
280 |
+
<?php
|
281 |
+
}
|
282 |
+
|
283 |
+
public function admin_coupon_metabox_customer( $thepostid, $post ) {
|
284 |
+
|
285 |
+
//=============================
|
286 |
+
//Title: "CUSTOMER RESTRICTIONS"
|
287 |
+
echo "<h3>" . esc_html( __( 'Customer restrictions', 'woocommerce-jos-autocoupon' ) ). "</h3>\n";
|
288 |
+
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";
|
289 |
+
|
290 |
+
//=============================
|
291 |
+
// User ids
|
292 |
+
?>
|
293 |
+
<p class="form-field"><label><?php _e( 'Allowed Customers', 'woocommerce-jos-autocoupon' ); ?></label>
|
294 |
+
<?php
|
295 |
+
$coupon_customer_ids = WJECF()->get_coupon_customer_ids( $thepostid );
|
296 |
+
WJECF_Admin_Html::render_admin_customer_selector( 'wjecf_customer_ids', '_wjecf_customer_ids', $coupon_customer_ids );
|
297 |
+
echo WJECF_Admin_Html::wc_help_tip( __( 'Only these customers may use this coupon.', 'woocommerce-jos-autocoupon' ) );
|
298 |
+
?>
|
299 |
+
</p>
|
300 |
+
<?php
|
301 |
+
|
302 |
+
//=============================
|
303 |
+
// User roles
|
304 |
+
?>
|
305 |
+
<p class="form-field"><label for="wjecf_customer_roles"><?php _e( 'Allowed User Roles', 'woocommerce-jos-autocoupon' ); ?></label>
|
306 |
+
<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' ); ?>">
|
307 |
+
<?php
|
308 |
+
$coupon_customer_roles = WJECF()->get_coupon_customer_roles( $thepostid );
|
309 |
+
|
310 |
+
$available_customer_roles = array_reverse( get_editable_roles() );
|
311 |
+
foreach ( $available_customer_roles as $role_id => $role ) {
|
312 |
+
$role_name = translate_user_role($role['name'] );
|
313 |
+
|
314 |
+
echo '<option value="' . esc_attr( $role_id ) . '"'
|
315 |
+
. selected( in_array( $role_id, $coupon_customer_roles ), true, false ) . '>'
|
316 |
+
. esc_html( $role_name ) . '</option>';
|
317 |
+
}
|
318 |
+
?>
|
319 |
+
</select>
|
320 |
+
<?php echo WJECF_Admin_Html::wc_help_tip( __( 'Only these User Roles may use this coupon.', 'woocommerce-jos-autocoupon' ) ); ?>
|
321 |
+
</p>
|
322 |
+
<?php
|
323 |
+
|
324 |
+
//=============================
|
325 |
+
// Excluded user roles
|
326 |
+
?>
|
327 |
+
<p class="form-field"><label for="wjecf_excluded_customer_roles"><?php _e( 'Disallowed User Roles', 'woocommerce-jos-autocoupon' ); ?></label>
|
328 |
+
<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' ); ?>">
|
329 |
+
<?php
|
330 |
+
$coupon_excluded_customer_roles = WJECF()->get_coupon_excluded_customer_roles( $thepostid );
|
331 |
+
|
332 |
+
foreach ( $available_customer_roles as $role_id => $role ) {
|
333 |
+
$role_name = translate_user_role($role['name'] );
|
334 |
+
|
335 |
+
echo '<option value="' . esc_attr( $role_id ) . '"'
|
336 |
+
. selected( in_array( $role_id, $coupon_excluded_customer_roles ), true, false ) . '>'
|
337 |
+
. esc_html( $role_name ) . '</option>';
|
338 |
+
}
|
339 |
+
?>
|
340 |
+
</select>
|
341 |
+
<?php echo WJECF_Admin_Html::wc_help_tip( __( 'These User Roles will be specifically excluded from using this coupon.', 'woocommerce-jos-autocoupon' ) ); ?>
|
342 |
+
</p>
|
343 |
+
<?php
|
344 |
+
}
|
345 |
+
|
346 |
+
public function admin_coupon_meta_fields( $coupon ) {
|
347 |
+
$fields = array(
|
348 |
+
'_wjecf_min_matching_product_qty' => 'int',
|
349 |
+
'_wjecf_max_matching_product_qty' => 'int',
|
350 |
+
'_wjecf_min_matching_product_subtotal' => 'decimal',
|
351 |
+
'_wjecf_max_matching_product_subtotal' => 'decimal',
|
352 |
+
'_wjecf_products_and' => 'yesno',
|
353 |
+
'_wjecf_categories_and' => 'yesno',
|
354 |
+
'_wjecf_shipping_methods' => 'clean',
|
355 |
+
'_wjecf_payment_methods' => 'clean',
|
356 |
+
'_wjecf_customer_ids' => 'int,',
|
357 |
+
'_wjecf_customer_roles' => 'clean',
|
358 |
+
'_wjecf_excluded_customer_roles' => 'clean'
|
359 |
+
);
|
360 |
+
|
361 |
+
//Espagueti
|
362 |
+
if ( WJECF()->is_pro() ) {
|
363 |
+
$fields = array_merge( $fields, WJECF()->admin_coupon_meta_fields( $coupon ) );
|
364 |
+
}
|
365 |
+
return $fields;
|
366 |
+
}
|
367 |
+
|
368 |
+
/**
|
369 |
+
* Get an array with all the metafields for all the WJECF plugins
|
370 |
+
*
|
371 |
+
* @see Abstract_WJECF_Plugin::admin_coupon_meta_fields()
|
372 |
+
*
|
373 |
+
* @param type $coupon
|
374 |
+
* @return type
|
375 |
+
*/
|
376 |
+
function get_all_coupon_meta_fields( $coupon ) {
|
377 |
+
//Collect the meta_fields of all the WJECF plugins
|
378 |
+
$fields = array();
|
379 |
+
foreach ( WJECF()->get_plugins() as $name => $plugin ) {
|
380 |
+
if ( $plugin->plugin_is_enabled() ) {
|
381 |
+
$fields = array_merge( $fields, $plugin->admin_coupon_meta_fields( $coupon ) );
|
382 |
+
}
|
383 |
+
}
|
384 |
+
return $fields;
|
385 |
+
}
|
386 |
+
|
387 |
+
function process_shop_coupon_meta( $post_id, $post ) {
|
388 |
+
$coupon = WJECF_WC()->get_coupon( $post );
|
389 |
+
$wrap_coupon = WJECF_Wrap( $coupon );
|
390 |
+
$sanitizer = WJECF()->sanitizer();
|
391 |
+
|
392 |
+
$fields = $this->get_all_coupon_meta_fields( $coupon );
|
393 |
+
foreach( $fields as $key => $rule ) {
|
394 |
+
//If array contains [ 'callback' => callback, 'args' => args[] ]
|
395 |
+
//Then that callback will be called with the given args (optional)
|
396 |
+
|
397 |
+
if ( is_array( $rule ) && isset( $rule['callback'] ) && is_callable( $rule['callback'] ) ) {
|
398 |
+
$args = array( 'key' => $key );
|
399 |
+
if ( isset( $rule['args'] ) ) $args = array_merge( $args, $rule['args'] );
|
400 |
+
|
401 |
+
$value = call_user_func( $rule['callback'], $args );
|
402 |
+
} else {
|
403 |
+
$value = $sanitizer->sanitize( isset( $_POST[$key] ) ? $_POST[$key] : null, $rule );
|
404 |
+
}
|
405 |
+
if ( $value === '' ) $value = null; //Don't save empty entries
|
406 |
+
|
407 |
+
$wrap_coupon->set_meta( $key, $value ); //Always single
|
408 |
+
|
409 |
+
//error_log(sprintf("%s => %s", $key, is_array($value) ? 'array' : $value));
|
410 |
+
}
|
411 |
+
|
412 |
+
$wrap_coupon->save();
|
413 |
+
}
|
414 |
+
|
415 |
+
|
416 |
+
|
417 |
+
/**
|
418 |
+
* 2.3.6
|
419 |
+
* Add inline style (css) to the admin page. Must be called BEFORE admin_head !
|
420 |
+
* @param string $css
|
421 |
+
* @return void
|
422 |
+
*/
|
423 |
+
public function add_inline_style( $css ) {
|
424 |
+
$this->admin_css .= $css;
|
425 |
+
}
|
426 |
+
|
427 |
+
|
428 |
+
/**
|
429 |
+
*
|
430 |
+
* 2.3.4
|
431 |
+
* Parse an array or comma separated string; make sure they are valid ints and return as comma separated string
|
432 |
+
* @deprecated 2.5.1 Use WJECF()->sanitizer->sanitize( ..., 'int[]' ) instead
|
433 |
+
* @param array|string $int_array
|
434 |
+
* @return string comma separated int array
|
435 |
+
*/
|
436 |
+
public function comma_separated_int_array( $int_array ) {
|
437 |
+
_deprecated_function( 'comma_separated_int_array', '2.5.1', 'WJECF()->sanitizer->sanitize()' );
|
438 |
+
return WJECF()->sanitizer->sanitize( $int_array, 'int[]' );
|
439 |
+
}
|
440 |
+
|
441 |
+
/**
|
442 |
+
* Add donate-link to plugin page
|
443 |
+
*/
|
444 |
+
function wjecf_plugin_meta( $links, $file ) {
|
445 |
+
if ( strpos( $file, 'woocommerce-jos-autocoupon.php' ) !== false ) {
|
446 |
+
$links = array_merge( $links, array( '<a href="' . WJECF_Admin::get_donate_url() . '" title="Support the development" target="_blank">Donate</a>' ) );
|
447 |
+
}
|
448 |
+
return $links;
|
449 |
+
}
|
450 |
+
|
451 |
+
|
452 |
+
public static function get_donate_url() {
|
453 |
+
return "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=5T9XQBCS2QHRY&lc=NL&item_name=Jos%20Koenis&item_number=wordpress%2dplugin¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted";
|
454 |
+
}
|
455 |
+
}
|
456 |
+
|
457 |
}
|
includes/admin/WJECF_Admin_Data_Update.php
CHANGED
@@ -1,83 +1,83 @@
|
|
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");
|
33 |
-
$wpdb->update( _get_meta_table('post'), $set, $where );
|
34 |
-
|
35 |
-
//RENAME meta_key woocommerce-jos-autocoupon TO _wjecf_is_auto_coupon
|
36 |
-
$where = array("meta_key" => "woocommerce-jos-autocoupon");
|
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( __( 'Please note, you\'re using an older version of this plugin, while the data was upgraded to a newer version.' , 'woocommerce-jos-autocoupon' ), '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( __( 'Data succesfully upgraded to the newest version.', 'woocommerce-jos-autocoupon' ), 'notice-success');
|
59 |
-
}
|
60 |
-
}
|
61 |
-
|
62 |
-
// function admin_notice_allow_cart_excluded() {
|
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 |
?>
|
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");
|
33 |
+
$wpdb->update( _get_meta_table('post'), $set, $where );
|
34 |
+
|
35 |
+
//RENAME meta_key woocommerce-jos-autocoupon TO _wjecf_is_auto_coupon
|
36 |
+
$where = array("meta_key" => "woocommerce-jos-autocoupon");
|
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( __( 'Please note, you\'re using an older version of this plugin, while the data was upgraded to a newer version.' , 'woocommerce-jos-autocoupon' ), '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( __( 'Data succesfully upgraded to the newest version.', 'woocommerce-jos-autocoupon' ), 'notice-success');
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
// function admin_notice_allow_cart_excluded() {
|
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
CHANGED
@@ -1,333 +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 . ' – ' . 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 |
}
|
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 . ' – ' . 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
CHANGED
@@ -1,269 +1,269 @@
|
|
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';
|
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 |
-
add_filter( 'plugin_action_links_' . WJECF()->plugin_basename(), array( $this, 'plugin_action_links' ) );
|
27 |
-
}
|
28 |
-
|
29 |
-
public function action_admin_menu() {
|
30 |
-
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' ) );
|
31 |
-
}
|
32 |
-
|
33 |
-
public function action_admin_config_page() {
|
34 |
-
?>
|
35 |
-
<h2><?php _e( 'WooCommerce Extended Coupon Features', 'woocommerce-jos-autocoupon' ); ?></h2>
|
36 |
-
<form method="post" action="options.php">
|
37 |
-
<?php
|
38 |
-
settings_fields( self::SETTINGS_PAGE );
|
39 |
-
do_settings_sections( self::SETTINGS_PAGE );
|
40 |
-
submit_button();
|
41 |
-
?>
|
42 |
-
</form>
|
43 |
-
<?php
|
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 |
-
do_action( 'wjecf_admin_before_settings' );
|
52 |
-
|
53 |
-
// Section DEBUG
|
54 |
-
add_settings_section(
|
55 |
-
self::DOM_PREFIX . 'section_debug',
|
56 |
-
__( 'Advanced settings', 'woocommerce-jos-autocoupon' ),
|
57 |
-
array( &$this, 'render_section' ),
|
58 |
-
$page
|
59 |
-
);
|
60 |
-
|
61 |
-
add_settings_field(
|
62 |
-
self::DOM_PREFIX . 'debug_mode',
|
63 |
-
__( 'Debug mode', 'woocommerce-jos-autocoupon' ),
|
64 |
-
array( $this, 'render_setting_debug_mode' ),
|
65 |
-
$page,
|
66 |
-
self::DOM_PREFIX . 'section_debug'
|
67 |
-
);
|
68 |
-
|
69 |
-
if ( WJECF()->get_option( 'debug_mode' ) === true ) {
|
70 |
-
foreach ( WJECF()->get_plugins() as $name => $plugin ) {
|
71 |
-
if ( $plugin->get_plugin_data('hidden') ) {
|
72 |
-
continue;
|
73 |
-
}
|
74 |
-
|
75 |
-
if ( $plugin->get_plugin_data('can_be_disabled') || WJECF()->get_option('debug_mode') ) {
|
76 |
-
add_settings_field(
|
77 |
-
self::DOM_PREFIX . 'plugin-' . $name,
|
78 |
-
$plugin->get_plugin_class_name(),
|
79 |
-
array( $this, 'render_setting_plugin' ),
|
80 |
-
$page,
|
81 |
-
self::DOM_PREFIX . 'section_debug', //section
|
82 |
-
array(
|
83 |
-
'plugin' => $plugin,
|
84 |
-
) //arguments
|
85 |
-
);
|
86 |
-
}
|
87 |
-
}
|
88 |
-
} else {
|
89 |
-
$disabled_plugins = WJECF()->get_option('disabled_plugins');
|
90 |
-
if ( ! empty( $disabled_plugins ) ) {
|
91 |
-
add_settings_field(
|
92 |
-
self::DOM_PREFIX . 'disabled_plugins',
|
93 |
-
__( 'Disabled plugins', 'woocommerce-jos-autocoupon' ),
|
94 |
-
array( $this, 'render_setting_disabled_plugins' ),
|
95 |
-
$page,
|
96 |
-
self::DOM_PREFIX . 'section_debug' //section
|
97 |
-
);
|
98 |
-
}
|
99 |
-
}
|
100 |
-
|
101 |
-
do_action( 'wjecf_admin_after_settings' );
|
102 |
-
}
|
103 |
-
|
104 |
-
/**
|
105 |
-
* Show action links on the plugin screen.
|
106 |
-
*
|
107 |
-
* @since 2.5.6
|
108 |
-
* @param mixed $links Plugin Action links
|
109 |
-
* @return array
|
110 |
-
*/
|
111 |
-
public function plugin_action_links( $links ) {
|
112 |
-
$action_links = array(
|
113 |
-
'settings' => sprintf(
|
114 |
-
'<a href="%s" title="%s">%s</a>',
|
115 |
-
$this->get_settings_page_url(),
|
116 |
-
esc_attr( __( 'Settings', 'woocommerce' ) ),
|
117 |
-
esc_attr( __( 'Settings', 'woocommerce' ) )
|
118 |
-
)
|
119 |
-
);
|
120 |
-
return array_merge( $action_links, $links );
|
121 |
-
}
|
122 |
-
|
123 |
-
/**
|
124 |
-
* The url to the WooCommerce Extended Coupon Features settings page
|
125 |
-
*
|
126 |
-
* @since 2.5.6
|
127 |
-
* @return string
|
128 |
-
*/
|
129 |
-
public function get_settings_page_url() {
|
130 |
-
return admin_url( 'options-general.php?page=' . self::SETTINGS_PAGE );
|
131 |
-
}
|
132 |
-
|
133 |
-
|
134 |
-
/**
|
135 |
-
* Sanitize the posted settings
|
136 |
-
* @param type $input
|
137 |
-
* @return type
|
138 |
-
*/
|
139 |
-
public function validate_settings( $input ) {
|
140 |
-
|
141 |
-
$options = WJECF()->get_options();
|
142 |
-
|
143 |
-
//disabled_plugins
|
144 |
-
if ( isset( $input['disabled_plugins'] ) && is_array( $input['disabled_plugins'] ) ) {
|
145 |
-
foreach( $input['disabled_plugins'] as $class_name => $disabled ) {
|
146 |
-
|
147 |
-
$plugin = WJECF()->get_plugin( $class_name );
|
148 |
-
if ( $plugin === false ) {
|
149 |
-
continue; //unknown / invalid plugin
|
150 |
-
}
|
151 |
-
|
152 |
-
//Never disable those
|
153 |
-
if ( ! $plugin->get_plugin_data('can_be_disabled') ) $disabled = 'no';
|
154 |
-
|
155 |
-
//false if not found; otherwise the index
|
156 |
-
$index = array_search( $class_name, $options['disabled_plugins'] );
|
157 |
-
|
158 |
-
if ( $disabled == 'yes' && $index === false ) {
|
159 |
-
$options['disabled_plugins'][] = $class_name;
|
160 |
-
}
|
161 |
-
elseif ( $disabled == 'no' && $index !== false )
|
162 |
-
{
|
163 |
-
unset( $options['disabled_plugins'][$index] );
|
164 |
-
}
|
165 |
-
}
|
166 |
-
}
|
167 |
-
|
168 |
-
//debug_mode
|
169 |
-
$options['debug_mode'] = isset( $input['debug_mode'] ) && $input['debug_mode'] === 'yes';
|
170 |
-
|
171 |
-
$options = apply_filters( 'wjecf_admin_validate_settings', $options, $input );
|
172 |
-
return $options;
|
173 |
-
|
174 |
-
}
|
175 |
-
|
176 |
-
public function render_section( $section ) {
|
177 |
-
switch ( $section['id'] ) {
|
178 |
-
case self::DOM_PREFIX . 'section_debug':
|
179 |
-
$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' );
|
180 |
-
$body = sprintf( $body, admin_url( 'admin.php?page=wc-status&tab=logs' ) );
|
181 |
-
printf( '<p>%s</p>', $body );
|
182 |
-
break;
|
183 |
-
}
|
184 |
-
}
|
185 |
-
|
186 |
-
/**
|
187 |
-
*
|
188 |
-
* Renders the enable/disable checkbox for a plugin
|
189 |
-
*
|
190 |
-
* Arguments: [ 'plugin' => WJECF_Plugin object ]
|
191 |
-
*
|
192 |
-
* @param array $arguments
|
193 |
-
* @return void
|
194 |
-
*/
|
195 |
-
public function render_setting_plugin( $arguments ) {
|
196 |
-
//var_dump($arguments);
|
197 |
-
|
198 |
-
$plugin = $arguments['plugin'];
|
199 |
-
$plugin_name = $plugin->get_plugin_class_name();
|
200 |
-
$plugin_disabled = $plugin->get_plugin_data('can_be_disabled') && in_array( $plugin_name, WJECF()->get_option( 'disabled_plugins' ) );
|
201 |
-
|
202 |
-
//This field yields the value if the checbox is not checked
|
203 |
-
//Don't draw this if plugin can't be disabled; as a disabled checkbox will not return a value
|
204 |
-
$args = array(
|
205 |
-
'type' => 'hidden',
|
206 |
-
'id' => self::DOM_PREFIX . 'plugin-' . $plugin_name . '-enabled',
|
207 |
-
'name' => sprintf( "%s[disabled_plugins][%s]", self::OPTION_NAME, $plugin_name ),
|
208 |
-
'value' => $plugin->get_plugin_data('can_be_disabled') ? 'yes' : 'no' //yes = disabled
|
209 |
-
);
|
210 |
-
WJECF_Admin_Html::render_input( $args );
|
211 |
-
|
212 |
-
$args = array(
|
213 |
-
'type' => 'checkbox',
|
214 |
-
'id' => self::DOM_PREFIX . 'plugin-' . $plugin_name . '-disabled',
|
215 |
-
'name' => sprintf( "%s[disabled_plugins][%s]", self::OPTION_NAME, $plugin_name ),
|
216 |
-
'value' => $plugin_disabled ? 'yes' : 'no',
|
217 |
-
'cbvalue' => 'no' //no = enabled
|
218 |
-
);
|
219 |
-
if ( ! $plugin->get_plugin_data('can_be_disabled') ) $args['disabled'] = true;
|
220 |
-
|
221 |
-
WJECF_Admin_Html::render_input( $args );
|
222 |
-
|
223 |
-
WJECF_Admin_Html::render_tag(
|
224 |
-
'label',
|
225 |
-
array( "for" => esc_attr( $args['id'] ) ),
|
226 |
-
__( 'Enabled', 'woocommerce' )
|
227 |
-
);
|
228 |
-
echo '<br>';
|
229 |
-
|
230 |
-
printf( '<p><i>%s</i></p>',
|
231 |
-
$plugin->get_plugin_description()
|
232 |
-
);
|
233 |
-
|
234 |
-
//echo $plugin->get_plugin_description();
|
235 |
-
//echo "</p>\n";
|
236 |
-
//echo "</li>\n";
|
237 |
-
}
|
238 |
-
|
239 |
-
public function render_setting_disabled_plugins() {
|
240 |
-
echo "<ul>";
|
241 |
-
foreach( WJECF()->get_option( 'disabled_plugins' ) as $class_name ) {
|
242 |
-
$plugin = WJECF()->get_plugin( $class_name );
|
243 |
-
if ( $plugin ) {
|
244 |
-
echo "<li><strong>" . $class_name . "</strong><br><i>" . $plugin->get_plugin_description() . "</i></li>";
|
245 |
-
}
|
246 |
-
}
|
247 |
-
echo "</ul>";
|
248 |
-
}
|
249 |
-
|
250 |
-
public function render_setting_debug_mode() {
|
251 |
-
$option_name = 'debug_mode';
|
252 |
-
$args = array(
|
253 |
-
'type' => 'checkbox',
|
254 |
-
'id' => self::DOM_PREFIX . $option_name,
|
255 |
-
'name' => sprintf( "%s[%s]", self::OPTION_NAME, $option_name ),
|
256 |
-
'value' => WJECF()->get_option( $option_name ) ? 'yes' : 'no'
|
257 |
-
);
|
258 |
-
WJECF_Admin_Html::render_input( $args );
|
259 |
-
|
260 |
-
WJECF_Admin_Html::render_tag(
|
261 |
-
'label',
|
262 |
-
array( "for" => esc_attr( $args['id'] ) ),
|
263 |
-
__( 'Enabled', 'woocommerce' )
|
264 |
-
);
|
265 |
-
|
266 |
-
}
|
267 |
-
|
268 |
-
|
269 |
}
|
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';
|
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 |
+
add_filter( 'plugin_action_links_' . WJECF()->plugin_basename(), array( $this, 'plugin_action_links' ) );
|
27 |
+
}
|
28 |
+
|
29 |
+
public function action_admin_menu() {
|
30 |
+
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' ) );
|
31 |
+
}
|
32 |
+
|
33 |
+
public function action_admin_config_page() {
|
34 |
+
?>
|
35 |
+
<h2><?php _e( 'WooCommerce Extended Coupon Features', 'woocommerce-jos-autocoupon' ); ?></h2>
|
36 |
+
<form method="post" action="options.php">
|
37 |
+
<?php
|
38 |
+
settings_fields( self::SETTINGS_PAGE );
|
39 |
+
do_settings_sections( self::SETTINGS_PAGE );
|
40 |
+
submit_button();
|
41 |
+
?>
|
42 |
+
</form>
|
43 |
+
<?php
|
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 |
+
do_action( 'wjecf_admin_before_settings' );
|
52 |
+
|
53 |
+
// Section DEBUG
|
54 |
+
add_settings_section(
|
55 |
+
self::DOM_PREFIX . 'section_debug',
|
56 |
+
__( 'Advanced settings', 'woocommerce-jos-autocoupon' ),
|
57 |
+
array( &$this, 'render_section' ),
|
58 |
+
$page
|
59 |
+
);
|
60 |
+
|
61 |
+
add_settings_field(
|
62 |
+
self::DOM_PREFIX . 'debug_mode',
|
63 |
+
__( 'Debug mode', 'woocommerce-jos-autocoupon' ),
|
64 |
+
array( $this, 'render_setting_debug_mode' ),
|
65 |
+
$page,
|
66 |
+
self::DOM_PREFIX . 'section_debug'
|
67 |
+
);
|
68 |
+
|
69 |
+
if ( WJECF()->get_option( 'debug_mode' ) === true ) {
|
70 |
+
foreach ( WJECF()->get_plugins() as $name => $plugin ) {
|
71 |
+
if ( $plugin->get_plugin_data('hidden') ) {
|
72 |
+
continue;
|
73 |
+
}
|
74 |
+
|
75 |
+
if ( $plugin->get_plugin_data('can_be_disabled') || WJECF()->get_option('debug_mode') ) {
|
76 |
+
add_settings_field(
|
77 |
+
self::DOM_PREFIX . 'plugin-' . $name,
|
78 |
+
$plugin->get_plugin_class_name(),
|
79 |
+
array( $this, 'render_setting_plugin' ),
|
80 |
+
$page,
|
81 |
+
self::DOM_PREFIX . 'section_debug', //section
|
82 |
+
array(
|
83 |
+
'plugin' => $plugin,
|
84 |
+
) //arguments
|
85 |
+
);
|
86 |
+
}
|
87 |
+
}
|
88 |
+
} else {
|
89 |
+
$disabled_plugins = WJECF()->get_option('disabled_plugins');
|
90 |
+
if ( ! empty( $disabled_plugins ) ) {
|
91 |
+
add_settings_field(
|
92 |
+
self::DOM_PREFIX . 'disabled_plugins',
|
93 |
+
__( 'Disabled plugins', 'woocommerce-jos-autocoupon' ),
|
94 |
+
array( $this, 'render_setting_disabled_plugins' ),
|
95 |
+
$page,
|
96 |
+
self::DOM_PREFIX . 'section_debug' //section
|
97 |
+
);
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
do_action( 'wjecf_admin_after_settings' );
|
102 |
+
}
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Show action links on the plugin screen.
|
106 |
+
*
|
107 |
+
* @since 2.5.6
|
108 |
+
* @param mixed $links Plugin Action links
|
109 |
+
* @return array
|
110 |
+
*/
|
111 |
+
public function plugin_action_links( $links ) {
|
112 |
+
$action_links = array(
|
113 |
+
'settings' => sprintf(
|
114 |
+
'<a href="%s" title="%s">%s</a>',
|
115 |
+
$this->get_settings_page_url(),
|
116 |
+
esc_attr( __( 'Settings', 'woocommerce' ) ),
|
117 |
+
esc_attr( __( 'Settings', 'woocommerce' ) )
|
118 |
+
)
|
119 |
+
);
|
120 |
+
return array_merge( $action_links, $links );
|
121 |
+
}
|
122 |
+
|
123 |
+
/**
|
124 |
+
* The url to the WooCommerce Extended Coupon Features settings page
|
125 |
+
*
|
126 |
+
* @since 2.5.6
|
127 |
+
* @return string
|
128 |
+
*/
|
129 |
+
public function get_settings_page_url() {
|
130 |
+
return admin_url( 'options-general.php?page=' . self::SETTINGS_PAGE );
|
131 |
+
}
|
132 |
+
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Sanitize the posted settings
|
136 |
+
* @param type $input
|
137 |
+
* @return type
|
138 |
+
*/
|
139 |
+
public function validate_settings( $input ) {
|
140 |
+
|
141 |
+
$options = WJECF()->get_options();
|
142 |
+
|
143 |
+
//disabled_plugins
|
144 |
+
if ( isset( $input['disabled_plugins'] ) && is_array( $input['disabled_plugins'] ) ) {
|
145 |
+
foreach( $input['disabled_plugins'] as $class_name => $disabled ) {
|
146 |
+
|
147 |
+
$plugin = WJECF()->get_plugin( $class_name );
|
148 |
+
if ( $plugin === false ) {
|
149 |
+
continue; //unknown / invalid plugin
|
150 |
+
}
|
151 |
+
|
152 |
+
//Never disable those
|
153 |
+
if ( ! $plugin->get_plugin_data('can_be_disabled') ) $disabled = 'no';
|
154 |
+
|
155 |
+
//false if not found; otherwise the index
|
156 |
+
$index = array_search( $class_name, $options['disabled_plugins'] );
|
157 |
+
|
158 |
+
if ( $disabled == 'yes' && $index === false ) {
|
159 |
+
$options['disabled_plugins'][] = $class_name;
|
160 |
+
}
|
161 |
+
elseif ( $disabled == 'no' && $index !== false )
|
162 |
+
{
|
163 |
+
unset( $options['disabled_plugins'][$index] );
|
164 |
+
}
|
165 |
+
}
|
166 |
+
}
|
167 |
+
|
168 |
+
//debug_mode
|
169 |
+
$options['debug_mode'] = isset( $input['debug_mode'] ) && $input['debug_mode'] === 'yes';
|
170 |
+
|
171 |
+
$options = apply_filters( 'wjecf_admin_validate_settings', $options, $input );
|
172 |
+
return $options;
|
173 |
+
|
174 |
+
}
|
175 |
+
|
176 |
+
public function render_section( $section ) {
|
177 |
+
switch ( $section['id'] ) {
|
178 |
+
case self::DOM_PREFIX . 'section_debug':
|
179 |
+
$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' );
|
180 |
+
$body = sprintf( $body, admin_url( 'admin.php?page=wc-status&tab=logs' ) );
|
181 |
+
printf( '<p>%s</p>', $body );
|
182 |
+
break;
|
183 |
+
}
|
184 |
+
}
|
185 |
+
|
186 |
+
/**
|
187 |
+
*
|
188 |
+
* Renders the enable/disable checkbox for a plugin
|
189 |
+
*
|
190 |
+
* Arguments: [ 'plugin' => WJECF_Plugin object ]
|
191 |
+
*
|
192 |
+
* @param array $arguments
|
193 |
+
* @return void
|
194 |
+
*/
|
195 |
+
public function render_setting_plugin( $arguments ) {
|
196 |
+
//var_dump($arguments);
|
197 |
+
|
198 |
+
$plugin = $arguments['plugin'];
|
199 |
+
$plugin_name = $plugin->get_plugin_class_name();
|
200 |
+
$plugin_disabled = $plugin->get_plugin_data('can_be_disabled') && in_array( $plugin_name, WJECF()->get_option( 'disabled_plugins' ) );
|
201 |
+
|
202 |
+
//This field yields the value if the checbox is not checked
|
203 |
+
//Don't draw this if plugin can't be disabled; as a disabled checkbox will not return a value
|
204 |
+
$args = array(
|
205 |
+
'type' => 'hidden',
|
206 |
+
'id' => self::DOM_PREFIX . 'plugin-' . $plugin_name . '-enabled',
|
207 |
+
'name' => sprintf( "%s[disabled_plugins][%s]", self::OPTION_NAME, $plugin_name ),
|
208 |
+
'value' => $plugin->get_plugin_data('can_be_disabled') ? 'yes' : 'no' //yes = disabled
|
209 |
+
);
|
210 |
+
WJECF_Admin_Html::render_input( $args );
|
211 |
+
|
212 |
+
$args = array(
|
213 |
+
'type' => 'checkbox',
|
214 |
+
'id' => self::DOM_PREFIX . 'plugin-' . $plugin_name . '-disabled',
|
215 |
+
'name' => sprintf( "%s[disabled_plugins][%s]", self::OPTION_NAME, $plugin_name ),
|
216 |
+
'value' => $plugin_disabled ? 'yes' : 'no',
|
217 |
+
'cbvalue' => 'no' //no = enabled
|
218 |
+
);
|
219 |
+
if ( ! $plugin->get_plugin_data('can_be_disabled') ) $args['disabled'] = true;
|
220 |
+
|
221 |
+
WJECF_Admin_Html::render_input( $args );
|
222 |
+
|
223 |
+
WJECF_Admin_Html::render_tag(
|
224 |
+
'label',
|
225 |
+
array( "for" => esc_attr( $args['id'] ) ),
|
226 |
+
__( 'Enabled', 'woocommerce' )
|
227 |
+
);
|
228 |
+
echo '<br>';
|
229 |
+
|
230 |
+
printf( '<p><i>%s</i></p>',
|
231 |
+
$plugin->get_plugin_description()
|
232 |
+
);
|
233 |
+
|
234 |
+
//echo $plugin->get_plugin_description();
|
235 |
+
//echo "</p>\n";
|
236 |
+
//echo "</li>\n";
|
237 |
+
}
|
238 |
+
|
239 |
+
public function render_setting_disabled_plugins() {
|
240 |
+
echo "<ul>";
|
241 |
+
foreach( WJECF()->get_option( 'disabled_plugins' ) as $class_name ) {
|
242 |
+
$plugin = WJECF()->get_plugin( $class_name );
|
243 |
+
if ( $plugin ) {
|
244 |
+
echo "<li><strong>" . $class_name . "</strong><br><i>" . $plugin->get_plugin_description() . "</i></li>";
|
245 |
+
}
|
246 |
+
}
|
247 |
+
echo "</ul>";
|
248 |
+
}
|
249 |
+
|
250 |
+
public function render_setting_debug_mode() {
|
251 |
+
$option_name = 'debug_mode';
|
252 |
+
$args = array(
|
253 |
+
'type' => 'checkbox',
|
254 |
+
'id' => self::DOM_PREFIX . $option_name,
|
255 |
+
'name' => sprintf( "%s[%s]", self::OPTION_NAME, $option_name ),
|
256 |
+
'value' => WJECF()->get_option( $option_name ) ? 'yes' : 'no'
|
257 |
+
);
|
258 |
+
WJECF_Admin_Html::render_input( $args );
|
259 |
+
|
260 |
+
WJECF_Admin_Html::render_tag(
|
261 |
+
'label',
|
262 |
+
array( "for" => esc_attr( $args['id'] ) ),
|
263 |
+
__( 'Enabled', 'woocommerce' )
|
264 |
+
);
|
265 |
+
|
266 |
+
}
|
267 |
+
|
268 |
+
|
269 |
}
|
readme.txt
CHANGED
@@ -4,8 +4,8 @@ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=5T9XQ
|
|
4 |
Tags: woocommerce, coupons, discount
|
5 |
Requires at least: 4.7
|
6 |
Requires PHP: 5.3
|
7 |
-
Tested up to: 4.9.
|
8 |
-
Stable tag: 2.6.
|
9 |
License: GPLv2 or later
|
10 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
11 |
|
@@ -108,7 +108,15 @@ Sure! [This](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=5T9XQ
|
|
108 |
|
109 |
== Changelog ==
|
110 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
= 2.6.2 =
|
|
|
112 |
* FEATURE: Auto-coupon compatibility with the 'WooCommerce Free Gift Coupons'-plugin
|
113 |
* FIX: CATEGORIES AND in combination with variable products
|
114 |
* FIX: Call to undefined function wc_add_notice()
|
4 |
Tags: woocommerce, coupons, discount
|
5 |
Requires at least: 4.7
|
6 |
Requires PHP: 5.3
|
7 |
+
Tested up to: 4.9.6
|
8 |
+
Stable tag: 2.6.3
|
9 |
License: GPLv2 or later
|
10 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
11 |
|
108 |
|
109 |
== Changelog ==
|
110 |
|
111 |
+
= 2.6.3 =
|
112 |
+
*Release Date - 2018-06-04*
|
113 |
+
* FIX: WJECF_Controller: Don't use wp_get_current_user() for admin-orders
|
114 |
+
* FIX: WJECF_Controller: Don't use WC()->cart->subtotal for admin-orders
|
115 |
+
* FIX: Possible division by zero when calculating multiplier value
|
116 |
+
* FEATURE: Filter 'wjecf_coupon_multiplier_value' to allow overriding the coupon's multiplier value
|
117 |
+
|
118 |
= 2.6.2 =
|
119 |
+
*Release Date - 2018-04-02*
|
120 |
* FEATURE: Auto-coupon compatibility with the 'WooCommerce Free Gift Coupons'-plugin
|
121 |
* FIX: CATEGORIES AND in combination with variable products
|
122 |
* FIX: Call to undefined function wc_add_notice()
|
woocommerce-jos-autocoupon.php
CHANGED
@@ -3,14 +3,14 @@
|
|
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.6.
|
7 |
* Author: Soft79
|
8 |
* License: GPL2
|
9 |
* WC requires at least: 2.6.0
|
10 |
-
* WC tested up to: 3.
|
11 |
*/
|
12 |
|
13 |
-
if ( ! defined('WJECF_VERSION') ) define ('WJECF_VERSION', '2.6.
|
14 |
|
15 |
// Changelog: see readme.txt
|
16 |
|
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.6.3
|
7 |
* Author: Soft79
|
8 |
* License: GPL2
|
9 |
* WC requires at least: 2.6.0
|
10 |
+
* WC tested up to: 3.4.1
|
11 |
*/
|
12 |
|
13 |
+
if ( ! defined('WJECF_VERSION') ) define ('WJECF_VERSION', '2.6.3');
|
14 |
|
15 |
// Changelog: see readme.txt
|
16 |
|