Completed
Pull Request — master (#11785)
by Mike
09:46
created

WC_Meta_Box_Coupon_Data::save()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 41
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 34
nc 2
nop 2
dl 0
loc 41
rs 8.8571
c 1
b 0
f 0
1
<?php
2
/**
3
 * Coupon Data
4
 *
5
 * Display the coupon data meta box.
6
 *
7
 * @author      WooThemes
8
 * @category    Admin
9
 * @package     WooCommerce/Admin/Meta Boxes
10
 * @version     2.1.0
11
 */
12
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit; // Exit if accessed directly
15
}
16
17
/**
18
 * WC_Meta_Box_Coupon_Data Class.
19
 */
20
class WC_Meta_Box_Coupon_Data {
21
22
	/**
23
	 * Output the metabox.
24
	 *
25
	 * @param WP_Post $post
26
	 */
27
	public static function output( $post ) {
28
		wp_nonce_field( 'woocommerce_save_data', 'woocommerce_meta_nonce' );
29
30
		$coupon = new WC_Coupon( $post->ID );
31
		?>
32
		<style type="text/css">
33
			#edit-slug-box, #minor-publishing-actions { display:none }
34
		</style>
35
		<div id="coupon_options" class="panel-wrap coupon_data">
36
37
			<div class="wc-tabs-back"></div>
38
39
			<ul class="coupon_data_tabs wc-tabs" style="display:none;">
40
				<?php
41
					$coupon_data_tabs = apply_filters( 'woocommerce_coupon_data_tabs', array(
42
						'general' => array(
43
							'label'  => __( 'General', 'woocommerce' ),
44
							'target' => 'general_coupon_data',
45
							'class'  => 'general_coupon_data',
46
						),
47
						'usage_restriction' => array(
48
							'label'  => __( 'Usage Restriction', 'woocommerce' ),
49
							'target' => 'usage_restriction_coupon_data',
50
							'class'  => '',
51
						),
52
						'usage_limit' => array(
53
							'label'  => __( 'Usage Limits', 'woocommerce' ),
54
							'target' => 'usage_limit_coupon_data',
55
							'class'  => '',
56
						)
57
					) );
58
59 View Code Duplication
					foreach ( $coupon_data_tabs as $key => $tab ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
60
						?><li class="<?php echo $key; ?>_options <?php echo $key; ?>_tab <?php echo implode( ' ' , (array) $tab['class'] ); ?>">
61
							<a href="#<?php echo $tab['target']; ?>"><?php echo esc_html( $tab['label'] ); ?></a>
62
						</li><?php
63
					}
64
				?>
65
			</ul>
66
			<div id="general_coupon_data" class="panel woocommerce_options_panel"><?php
67
68
				// Type
69
				woocommerce_wp_select( array( 'id' => 'discount_type', 'label' => __( 'Discount type', 'woocommerce' ), 'options' => wc_get_coupon_types() ) );
70
71
				// Amount
72
				woocommerce_wp_text_input( array( 'id' => 'coupon_amount', 'label' => __( 'Coupon amount', 'woocommerce' ), 'placeholder' => wc_format_localized_price( 0 ), 'description' => __( 'Value of the coupon.', 'woocommerce' ), 'data_type' => 'price', 'desc_tip' => true ) );
73
74
				// Free Shipping
75
				woocommerce_wp_checkbox( array( 'id' => 'free_shipping', 'label' => __( 'Allow free shipping', 'woocommerce' ), 'description' => sprintf( __( 'Check this box if the coupon grants free shipping. A <a href="%s">free shipping method</a> must be enabled in your shipping zone and be set to require "a valid free shipping coupon" (see the "Free Shipping Requires" setting).', 'woocommerce' ), 'https://docs.woocommerce.com/document/free-shipping/' ) ) );
76
77
				// Expiry date
78
				woocommerce_wp_text_input( array( 'id' => 'expiry_date', 'value' => date( 'Y-m-d', $coupon->get_date_expires() ), 'label' => __( 'Coupon expiry date', 'woocommerce' ), 'placeholder' => _x( 'YYYY-MM-DD', 'placeholder', 'woocommerce' ), 'description' => '', 'class' => 'date-picker', 'custom_attributes' => array( 'pattern' => "[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" ) ) );
79
80
				do_action( 'woocommerce_coupon_options' );
81
82
			?></div>
83
			<div id="usage_restriction_coupon_data" class="panel woocommerce_options_panel"><?php
84
85
				echo '<div class="options_group">';
86
87
				// minimum spend
88
				woocommerce_wp_text_input( array( 'id' => 'minimum_amount', 'label' => __( 'Minimum spend', 'woocommerce' ), 'placeholder' => __( 'No minimum', 'woocommerce' ), 'description' => __( 'This field allows you to set the minimum spend (subtotal, including taxes) allowed to use the coupon.', 'woocommerce' ), 'data_type' => 'price', 'desc_tip' => true ) );
89
90
				// maximum spend
91
				woocommerce_wp_text_input( array( 'id' => 'maximum_amount', 'label' => __( 'Maximum spend', 'woocommerce' ), 'placeholder' => __( 'No maximum', 'woocommerce' ), 'description' => __( 'This field allows you to set the maximum spend (subtotal, including taxes) allowed when using the coupon.', 'woocommerce' ), 'data_type' => 'price', 'desc_tip' => true ) );
92
93
				// Individual use
94
				woocommerce_wp_checkbox( array( 'id' => 'individual_use', 'label' => __( 'Individual use only', 'woocommerce' ), 'description' => __( 'Check this box if the coupon cannot be used in conjunction with other coupons.', 'woocommerce' ) ) );
95
96
				// Exclude Sale Products
97
				woocommerce_wp_checkbox( array( 'id' => 'exclude_sale_items', 'label' => __( 'Exclude sale items', 'woocommerce' ), 'description' => __( 'Check this box if the coupon should not apply to items on sale. Per-item coupons will only work if the item is not on sale. Per-cart coupons will only work if there are no sale items in the cart.', 'woocommerce' ) ) );
98
99
				echo '</div><div class="options_group">';
100
101
				// Product ids
102
				?>
103
				<p class="form-field"><label><?php _e( 'Products', 'woocommerce' ); ?></label>
104
				<input type="hidden" class="wc-product-search" data-multiple="true" style="width: 50%;" name="product_ids" data-placeholder="<?php esc_attr_e( 'Search for a product&hellip;', 'woocommerce' ); ?>" data-action="woocommerce_json_search_products_and_variations" data-selected="<?php
105
					$product_ids = $coupon->get_product_ids();
106
					$json_ids    = array();
107
108 View Code Duplication
					foreach ( $product_ids as $product_id ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
109
						$product = wc_get_product( $product_id );
110
						if ( is_object( $product ) ) {
111
							$json_ids[ $product_id ] = wp_kses_post( $product->get_formatted_name() );
112
						}
113
					}
114
115
					echo esc_attr( json_encode( $json_ids ) );
116
					?>" value="<?php echo implode( ',', array_keys( $json_ids ) ); ?>" /> <?php echo wc_help_tip( __( 'Products which need to be in the cart to use this coupon or, for "Product Discounts", which products are discounted.', 'woocommerce' ) ); ?></p>
117
				<?php
118
119
				// Exclude Product ids
120
				?>
121
				<p class="form-field"><label><?php _e( 'Exclude products', 'woocommerce' ); ?></label>
122
				<input type="hidden" class="wc-product-search" data-multiple="true" style="width: 50%;" name="exclude_product_ids" data-placeholder="<?php esc_attr_e( 'Search for a product&hellip;', 'woocommerce' ); ?>" data-action="woocommerce_json_search_products_and_variations" data-selected="<?php
123
					$product_ids = $coupon->get_excluded_product_ids();
124
					$json_ids    = array();
125
126 View Code Duplication
					foreach ( $product_ids as $product_id ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
127
						$product = wc_get_product( $product_id );
128
						if ( is_object( $product ) ) {
129
							$json_ids[ $product_id ] = wp_kses_post( $product->get_formatted_name() );
130
						}
131
					}
132
133
					echo esc_attr( json_encode( $json_ids ) );
134
				?>" value="<?php echo implode( ',', array_keys( $json_ids ) ); ?>" /> <?php echo wc_help_tip( __( 'Products which must not be in the cart to use this coupon or, for "Product Discounts", which products are not discounted.', 'woocommerce' ) ); ?></p>
135
				<?php
136
137
				echo '</div><div class="options_group">';
138
139
				// Categories
140
				?>
141
				<p class="form-field"><label for="product_categories"><?php _e( 'Product categories', 'woocommerce' ); ?></label>
142
				<select id="product_categories" name="product_categories[]" style="width: 50%;"  class="wc-enhanced-select" multiple="multiple" data-placeholder="<?php esc_attr_e( 'Any category', 'woocommerce' ); ?>">
143
					<?php
144
						$category_ids = $coupon->get_product_categories();
145
						$categories   = get_terms( 'product_cat', 'orderby=name&hide_empty=0' );
146
147 View Code Duplication
						if ( $categories ) foreach ( $categories as $cat ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
148
							echo '<option value="' . esc_attr( $cat->term_id ) . '"' . selected( in_array( $cat->term_id, $category_ids ), true, false ) . '>' . esc_html( $cat->name ) . '</option>';
149
						}
150
					?>
151
				</select> <?php echo wc_help_tip( __( 'A product must be in this category for the coupon to remain valid or, for "Product Discounts", products in these categories will be discounted.', 'woocommerce' ) ); ?></p>
152
				<?php
153
154
				// Exclude Categories
155
				?>
156
				<p class="form-field"><label for="exclude_product_categories"><?php _e( 'Exclude categories', 'woocommerce' ); ?></label>
157
				<select id="exclude_product_categories" name="exclude_product_categories[]" style="width: 50%;"  class="wc-enhanced-select" multiple="multiple" data-placeholder="<?php esc_attr_e( 'No categories', 'woocommerce' ); ?>">
158
					<?php
159
						$category_ids = $coupon->get_excluded_product_categories();
160
						$categories   = get_terms( 'product_cat', 'orderby=name&hide_empty=0' );
161
162 View Code Duplication
						if ( $categories ) foreach ( $categories as $cat ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
163
							echo '<option value="' . esc_attr( $cat->term_id ) . '"' . selected( in_array( $cat->term_id, $category_ids ), true, false ) . '>' . esc_html( $cat->name ) . '</option>';
164
						}
165
					?>
166
				</select> <?php echo wc_help_tip( __( 'Product must not be in this category for the coupon to remain valid or, for "Product Discounts", products in these categories will not be discounted.', 'woocommerce' ) ); ?></p>
167
				<?php
168
169
				echo '</div><div class="options_group">';
170
171
				// Customers
172
				woocommerce_wp_text_input( array( 'id' => 'customer_email', 'label' => __( 'Email restrictions', 'woocommerce' ), 'placeholder' => __( 'No restrictions', 'woocommerce' ), 'description' => __( 'List of allowed emails to check against the customer\'s billing email when an order is placed. Separate email addresses with commas.', 'woocommerce' ), 'value' => implode(', ', (array) get_post_meta( $post->ID, 'customer_email', true ) ), 'desc_tip' => true, 'type' => 'email', 'class' => '', 'custom_attributes' => array(
173
						'multiple' 	=> 'multiple'
174
				) ) );
175
176
				echo '</div>';
177
178
				do_action( 'woocommerce_coupon_options_usage_restriction' );
179
180
			?></div>
181
			<div id="usage_limit_coupon_data" class="panel woocommerce_options_panel"><?php
182
183
				echo '<div class="options_group">';
184
185
				// Usage limit per coupons
186
				woocommerce_wp_text_input(
187
					array(
188
						'id'                => 'usage_limit',
189
						'label'             => __( 'Usage limit per coupon', 'woocommerce' ),
190
						'placeholder'       => _x( 'Unlimited usage', 'placeholder', 'woocommerce' ),
191
						'description'       => __( 'How many times this coupon can be used before it is void.', 'woocommerce' ),
192
						'type'              => 'number',
193
						'desc_tip'          => true,
194
						'class'             => 'short',
195
						'custom_attributes' => array(
196
							'step' 	=> 1,
197
							'min'	=> 0,
198
						),
199
						'value' => $coupon->get_usage_limit() ? $coupon->get_usage_limit() : '',
200
					)
201
				);
202
203
				// Usage limit per product
204
				woocommerce_wp_text_input(
205
					array(
206
						'id'                => 'limit_usage_to_x_items',
207
						'label'             => __( 'Limit usage to X items', 'woocommerce' ),
208
						'placeholder'       => _x( 'Apply to all qualifying items in cart', 'placeholder', 'woocommerce' ),
209
						'description'       => __( 'The maximum number of individual items this coupon can apply to when using product discounts. Leave blank to apply to all qualifying items in cart.', 'woocommerce' ),
210
						'desc_tip'          => true,
211
						'class'             => 'short',
212
						'type'              => 'number',
213
						'custom_attributes' => array(
214
							'step' 	=> 1,
215
							'min'	=> 0,
216
						),
217
						'value' => $coupon->get_limit_usage_to_x_items() ? $coupon->get_limit_usage_to_x_items() : '',
218
					)
219
				);
220
221
				// Usage limit per users
222
				woocommerce_wp_text_input(
223
					array(
224
						'id'                => 'usage_limit_per_user',
225
						'label'             => __( 'Usage limit per user', 'woocommerce' ),
226
						'placeholder'       => _x( 'Unlimited usage', 'placeholder', 'woocommerce' ),
227
						'description'       => __( 'How many times this coupon can be used by an invidual user. Uses billing email for guests, and user ID for logged in users.', 'woocommerce' ),
228
						'desc_tip'          => true,
229
						'class'             => 'short',
230
						'type'              => 'number',
231
						'custom_attributes' => array(
232
							'step' 	=> 1,
233
							'min'	=> 0,
234
						),
235
						'value' => $coupon->get_usage_limit_per_user() ? $coupon->get_usage_limit_per_user() : '',
236
					)
237
				);
238
239
				echo '</div>';
240
241
				do_action( 'woocommerce_coupon_options_usage_limit' );
242
243
			?></div>
244
			<?php do_action( 'woocommerce_coupon_data_panels' ); ?>
245
			<div class="clear"></div>
246
		</div>
247
		<?php
248
	}
249
250
	/**
251
	 * Save meta box data.
252
	 *
253
	 * @param int $post_id
254
	 * @param WP_Post $post
255
	 */
256
	public static function save( $post_id, $post ) {
257
		global $wpdb;
258
259
		// Check for dupe coupons
260
		$coupon_code  = apply_filters( 'woocommerce_coupon_code', $post->post_title );
261
		$coupon_found = $wpdb->get_var( $wpdb->prepare( "
262
			SELECT $wpdb->posts.ID
263
			FROM $wpdb->posts
264
			WHERE $wpdb->posts.post_type = 'shop_coupon'
265
			AND $wpdb->posts.post_status = 'publish'
266
			AND $wpdb->posts.post_title = %s
267
			AND $wpdb->posts.ID != %d
268
		 ", $coupon_code, $post_id ) );
269
270
		if ( $coupon_found ) {
271
			WC_Admin_Meta_Boxes::add_error( __( 'Coupon code already exists - customers will use the latest coupon with this code.', 'woocommerce' ) );
272
		}
273
274
		$coupon = new WC_Coupon( $post_id );
275
		$coupon->set_props( array(
276
			'code'                        => $post->post_title,
277
			'discount_type'               => wc_clean( $_POST['discount_type'] ),
278
			'amount'                      => wc_format_decimal( $_POST['coupon_amount'] ),
279
			'date_expires'                => wc_clean( $_POST['expiry_date'] ),
280
			'individual_use'              => isset( $_POST['individual_use'] ),
281
			'product_ids'                 => array_filter( array_map( 'intval', explode( ',', $_POST['product_ids'] ) ) ),
282
			'excluded_product_ids'        => array_filter( array_map( 'intval', explode( ',', $_POST['exclude_product_ids'] ) ) ),
283
			'usage_limit'                 => absint( $_POST['usage_limit'] ),
284
			'usage_limit_per_user'        => absint( $_POST['usage_limit_per_user'] ),
285
			'limit_usage_to_x_items'      => absint( $_POST['limit_usage_to_x_items'] ),
286
			'free_shipping'               => isset( $_POST['free_shipping'] ),
287
			'product_categories'          => array_filter( array_map( 'intval', (array) $_POST['product_categories'] ) ),
288
			'excluded_product_categories' => array_filter( array_map( 'intval', (array) $_POST['exclude_product_categories'] ) ),
289
			'exclude_sale_items'          => isset( $_POST['exclude_sale_items'] ),
290
			'minimum_amount'              => wc_format_decimal( $_POST['minimum_amount'] ),
291
			'maximum_amount'              => wc_format_decimal( $_POST['maximum_amount'] ),
292
			'email_restrictions'          => array_filter( array_map( 'trim', explode( ',', wc_clean( $_POST['customer_email'] ) ) ) ),
293
		) );
294
		$coupon->save();
295
		do_action( 'woocommerce_coupon_options_save', $post_id );
296
	}
297
}
298