Completed
Push — master ( 07eadf...5397e4 )
by Mike
20:38 queued 11s
created

WC_AJAX::remove_order_item()   F

Complexity

Conditions 13
Paths 586

Size

Total Lines 91

Duplication

Lines 5
Ratio 5.49 %

Code Coverage

Tests 0
CRAP Score 182

Importance

Changes 0
Metric Value
cc 13
nc 586
nop 0
dl 5
loc 91
ccs 0
cts 44
cp 0
crap 182
rs 2.6163
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * WooCommerce WC_AJAX. AJAX Event Handlers.
4
 *
5
 * @class   WC_AJAX
6
 * @package WooCommerce/Classes
7
 */
8
9
defined( 'ABSPATH' ) || exit;
10
11
/**
12
 * WC_Ajax class.
13
 */
14
class WC_AJAX {
15
16
	/**
17
	 * Hook in ajax handlers.
18
	 */
19
	public static function init() {
20
		add_action( 'init', array( __CLASS__, 'define_ajax' ), 0 );
21
		add_action( 'template_redirect', array( __CLASS__, 'do_wc_ajax' ), 0 );
22
		self::add_ajax_events();
23
	}
24
25
	/**
26
	 * Get WC Ajax Endpoint.
27
	 *
28
	 * @param string $request Optional.
29
	 *
30
	 * @return string
31
	 */
32
	public static function get_endpoint( $request = '' ) {
33
		return esc_url_raw( apply_filters( 'woocommerce_ajax_get_endpoint', add_query_arg( 'wc-ajax', $request, remove_query_arg( array( 'remove_item', 'add-to-cart', 'added-to-cart', 'order_again', '_wpnonce' ), home_url( '/', 'relative' ) ) ), $request ) );
34
	}
35
36
	/**
37
	 * Set WC AJAX constant and headers.
38
	 */
39
	public static function define_ajax() {
40
		if ( ! empty( $_GET['wc-ajax'] ) ) {
41
			wc_maybe_define_constant( 'DOING_AJAX', true );
42
			wc_maybe_define_constant( 'WC_DOING_AJAX', true );
43
			if ( ! WP_DEBUG || ( WP_DEBUG && ! WP_DEBUG_DISPLAY ) ) {
44
				@ini_set( 'display_errors', 0 ); // Turn off display_errors during AJAX events to prevent malformed JSON.
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Coding Style introduced by
Silencing errors is discouraged
Loading history...
45
			}
46
			$GLOBALS['wpdb']->hide_errors();
47
		}
48
	}
49
50
	/**
51
	 * Send headers for WC Ajax Requests.
52
	 *
53
	 * @since 2.5.0
54
	 */
55
	private static function wc_ajax_headers() {
56
		send_origin_headers();
57
		@header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Coding Style introduced by
Silencing errors is discouraged
Loading history...
58
		@header( 'X-Robots-Tag: noindex' );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Coding Style introduced by
Silencing errors is discouraged
Loading history...
59
		send_nosniff_header();
60
		wc_nocache_headers();
61
		status_header( 200 );
62
	}
63
64
	/**
65
	 * Check for WC Ajax request and fire action.
66
	 */
67
	public static function do_wc_ajax() {
68
		global $wp_query;
69
70
		if ( ! empty( $_GET['wc-ajax'] ) ) {
71
			$wp_query->set( 'wc-ajax', sanitize_text_field( wp_unslash( $_GET['wc-ajax'] ) ) );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
72
		}
73
74
		$action = $wp_query->get( 'wc-ajax' );
75
76
		if ( $action ) {
77
			self::wc_ajax_headers();
78
			$action = sanitize_text_field( $action );
79
			do_action( 'wc_ajax_' . $action );
80
			wp_die();
81
		}
82
	}
83
84
	/**
85
	 * Hook in methods - uses WordPress ajax handlers (admin-ajax).
86
	 */
87
	public static function add_ajax_events() {
88
		// woocommerce_EVENT => nopriv.
89
		$ajax_events = array(
90
			'get_refreshed_fragments'                          => true,
91
			'apply_coupon'                                     => true,
92
			'remove_coupon'                                    => true,
93
			'update_shipping_method'                           => true,
94
			'get_cart_totals'                                  => true,
95
			'update_order_review'                              => true,
96
			'add_to_cart'                                      => true,
97
			'remove_from_cart'                                 => true,
98
			'checkout'                                         => true,
99
			'get_variation'                                    => true,
100
			'get_customer_location'                            => true,
101
			'feature_product'                                  => false,
102
			'mark_order_status'                                => false,
103
			'get_order_details'                                => false,
104
			'add_attribute'                                    => false,
105
			'add_new_attribute'                                => false,
106
			'remove_variation'                                 => false,
107
			'remove_variations'                                => false,
108
			'save_attributes'                                  => false,
109
			'add_variation'                                    => false,
110
			'link_all_variations'                              => false,
111
			'revoke_access_to_download'                        => false,
112
			'grant_access_to_download'                         => false,
113
			'get_customer_details'                             => false,
114
			'add_order_item'                                   => false,
115
			'add_order_fee'                                    => false,
116
			'add_order_shipping'                               => false,
117
			'add_order_tax'                                    => false,
118
			'add_coupon_discount'                              => false,
119
			'remove_order_coupon'                              => false,
120
			'remove_order_item'                                => false,
121
			'remove_order_tax'                                 => false,
122
			'reduce_order_item_stock'                          => false,
123
			'increase_order_item_stock'                        => false,
124
			'add_order_item_meta'                              => false,
125
			'remove_order_item_meta'                           => false,
126
			'calc_line_taxes'                                  => false,
127
			'save_order_items'                                 => false,
128
			'load_order_items'                                 => false,
129
			'add_order_note'                                   => false,
130
			'delete_order_note'                                => false,
131
			'json_search_products'                             => false,
132
			'json_search_products_and_variations'              => false,
133
			'json_search_downloadable_products_and_variations' => false,
134
			'json_search_customers'                            => false,
135
			'json_search_categories'                           => false,
136
			'term_ordering'                                    => false,
137
			'product_ordering'                                 => false,
138
			'refund_line_items'                                => false,
139
			'delete_refund'                                    => false,
140
			'rated'                                            => false,
141
			'update_api_key'                                   => false,
142
			'load_variations'                                  => false,
143
			'save_variations'                                  => false,
144
			'bulk_edit_variations'                             => false,
145
			'tax_rates_save_changes'                           => false,
146
			'shipping_zones_save_changes'                      => false,
147
			'shipping_zone_add_method'                         => false,
148
			'shipping_zone_methods_save_changes'               => false,
149
			'shipping_zone_methods_save_settings'              => false,
150
			'shipping_classes_save_changes'                    => false,
151
			'toggle_gateway_enabled'                           => false,
152
		);
153
154
		foreach ( $ajax_events as $ajax_event => $nopriv ) {
155
			add_action( 'wp_ajax_woocommerce_' . $ajax_event, array( __CLASS__, $ajax_event ) );
156
157
			if ( $nopriv ) {
158
				add_action( 'wp_ajax_nopriv_woocommerce_' . $ajax_event, array( __CLASS__, $ajax_event ) );
159
160
				// WC AJAX can be used for frontend ajax requests.
161
				add_action( 'wc_ajax_' . $ajax_event, array( __CLASS__, $ajax_event ) );
162
			}
163
		}
164
	}
165
166
	/**
167
	 * Get a refreshed cart fragment, including the mini cart HTML.
168
	 */
169
	public static function get_refreshed_fragments() {
170
		ob_start();
171
172
		woocommerce_mini_cart();
173
174
		$mini_cart = ob_get_clean();
175
176
		$data = array(
177
			'fragments' => apply_filters(
178
				'woocommerce_add_to_cart_fragments', array(
179
					'div.widget_shopping_cart_content' => '<div class="widget_shopping_cart_content">' . $mini_cart . '</div>',
180
				)
181
			),
182
			'cart_hash' => WC()->cart->get_cart_hash(),
183
		);
184
185
		wp_send_json( $data );
186
	}
187
188
	/**
189
	 * AJAX apply coupon on checkout page.
190
	 */
191
	public static function apply_coupon() {
192
193
		check_ajax_referer( 'apply-coupon', 'security' );
194
195
		if ( ! empty( $_POST['coupon_code'] ) ) {
196
			WC()->cart->add_discount( sanitize_text_field( wp_unslash( $_POST['coupon_code'] ) ) );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
197
		} else {
198
			wc_add_notice( WC_Coupon::get_generic_coupon_error( WC_Coupon::E_WC_COUPON_PLEASE_ENTER ), 'error' );
199
		}
200
201
		wc_print_notices();
202
		wp_die();
203
	}
204
205
	/**
206
	 * AJAX remove coupon on cart and checkout page.
207
	 */
208
	public static function remove_coupon() {
209
		check_ajax_referer( 'remove-coupon', 'security' );
210
211
		$coupon = isset( $_POST['coupon'] ) ? wc_clean( $_POST['coupon'] ) : false;
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
212
213
		if ( empty( $coupon ) ) {
214
			wc_add_notice( __( 'Sorry there was a problem removing this coupon.', 'woocommerce' ), 'error' );
215
		} else {
216
			WC()->cart->remove_coupon( $coupon );
217
			wc_add_notice( __( 'Coupon has been removed.', 'woocommerce' ) );
218
		}
219
220
		wc_print_notices();
221
		wp_die();
222
	}
223
224
	/**
225
	 * AJAX update shipping method on cart page.
226
	 */
227
	public static function update_shipping_method() {
228
		check_ajax_referer( 'update-shipping-method', 'security' );
229
230
		wc_maybe_define_constant( 'WOOCOMMERCE_CART', true );
231
232
		$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
233
234 View Code Duplication
		if ( isset( $_POST['shipping_method'] ) && is_array( $_POST['shipping_method'] ) ) {
235
			foreach ( $_POST['shipping_method'] as $i => $value ) {
236
				$chosen_shipping_methods[ $i ] = wc_clean( $value );
237
			}
238
		}
239
240
		WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods );
241
242
		self::get_cart_totals();
243
	}
244
245
	/**
246
	 * AJAX receive updated cart_totals div.
247
	 */
248
	public static function get_cart_totals() {
249
		wc_maybe_define_constant( 'WOOCOMMERCE_CART', true );
250
		WC()->cart->calculate_totals();
251
		woocommerce_cart_totals();
252
		wp_die();
253
	}
254
255
	/**
256
	 * Session has expired.
257
	 */
258
	private static function update_order_review_expired() {
259
		wp_send_json(
260
			array(
261
				'fragments' => apply_filters(
262
					'woocommerce_update_order_review_fragments', array(
263
						'form.woocommerce-checkout' => '<div class="woocommerce-error">' . __( 'Sorry, your session has expired.', 'woocommerce' ) . ' <a href="' . esc_url( wc_get_page_permalink( 'shop' ) ) . '" class="wc-backward">' . __( 'Return to shop', 'woocommerce' ) . '</a></div>',
264
					)
265
				),
266
			)
267
		);
268
	}
269
270
	/**
271
	 * AJAX update order review on checkout.
272
	 */
273
	public static function update_order_review() {
274
		check_ajax_referer( 'update-order-review', 'security' );
275
276
		wc_maybe_define_constant( 'WOOCOMMERCE_CHECKOUT', true );
277
278 View Code Duplication
		if ( WC()->cart->is_empty() && ! is_customize_preview() && apply_filters( 'woocommerce_checkout_update_order_review_expired', true ) ) {
279
			self::update_order_review_expired();
280
		}
281
282
		do_action( 'woocommerce_checkout_update_order_review', $_POST['post_data'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
283
284
		$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
285
286 View Code Duplication
		if ( isset( $_POST['shipping_method'] ) && is_array( $_POST['shipping_method'] ) ) {
287
			foreach ( $_POST['shipping_method'] as $i => $value ) {
288
				$chosen_shipping_methods[ $i ] = wc_clean( $value );
289
			}
290
		}
291
292
		WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods );
293
		WC()->session->set( 'chosen_payment_method', empty( $_POST['payment_method'] ) ? '' : $_POST['payment_method'] );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
294
		WC()->customer->set_props(
295
			array(
296
				'billing_country'   => isset( $_POST['country'] ) ? wp_unslash( $_POST['country'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
297
				'billing_state'     => isset( $_POST['state'] ) ? wp_unslash( $_POST['state'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
298
				'billing_postcode'  => isset( $_POST['postcode'] ) ? wp_unslash( $_POST['postcode'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
299
				'billing_city'      => isset( $_POST['city'] ) ? wp_unslash( $_POST['city'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
300
				'billing_address_1' => isset( $_POST['address'] ) ? wp_unslash( $_POST['address'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
301
				'billing_address_2' => isset( $_POST['address_2'] ) ? wp_unslash( $_POST['address_2'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
302
			)
303
		);
304
305
		if ( wc_ship_to_billing_address_only() ) {
306
			WC()->customer->set_props(
307
				array(
308
					'shipping_country'   => isset( $_POST['country'] ) ? wp_unslash( $_POST['country'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
309
					'shipping_state'     => isset( $_POST['state'] ) ? wp_unslash( $_POST['state'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
310
					'shipping_postcode'  => isset( $_POST['postcode'] ) ? wp_unslash( $_POST['postcode'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
311
					'shipping_city'      => isset( $_POST['city'] ) ? wp_unslash( $_POST['city'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
312
					'shipping_address_1' => isset( $_POST['address'] ) ? wp_unslash( $_POST['address'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
313
					'shipping_address_2' => isset( $_POST['address_2'] ) ? wp_unslash( $_POST['address_2'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
314
				)
315
			);
316
		} else {
317
			WC()->customer->set_props(
318
				array(
319
					'shipping_country'   => isset( $_POST['s_country'] ) ? wp_unslash( $_POST['s_country'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
320
					'shipping_state'     => isset( $_POST['s_state'] ) ? wp_unslash( $_POST['s_state'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
321
					'shipping_postcode'  => isset( $_POST['s_postcode'] ) ? wp_unslash( $_POST['s_postcode'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
322
					'shipping_city'      => isset( $_POST['s_city'] ) ? wp_unslash( $_POST['s_city'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
323
					'shipping_address_1' => isset( $_POST['s_address'] ) ? wp_unslash( $_POST['s_address'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
324
					'shipping_address_2' => isset( $_POST['s_address_2'] ) ? wp_unslash( $_POST['s_address_2'] ) : null,
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
325
				)
326
			);
327
		}
328
329
		if ( wc_string_to_bool( $_POST['has_full_address'] ) ) {
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
330
			WC()->customer->set_calculated_shipping( true );
331
		} else {
332
			WC()->customer->set_calculated_shipping( false );
333
		}
334
335
		WC()->customer->save();
336
		WC()->cart->calculate_totals();
337
338
		// Get order review fragment.
339
		ob_start();
340
		woocommerce_order_review();
341
		$woocommerce_order_review = ob_get_clean();
342
343
		// Get checkout payment fragment.
344
		ob_start();
345
		woocommerce_checkout_payment();
346
		$woocommerce_checkout_payment = ob_get_clean();
347
348
		// Get messages if reload checkout is not true.
349
		$reload_checkout = isset( WC()->session->reload_checkout ) ? true : false;
350
		if ( ! $reload_checkout ) {
351
			$messages = wc_print_notices( true );
352
		} else {
353
			$messages = '';
354
		}
355
356
		unset( WC()->session->refresh_totals, WC()->session->reload_checkout );
357
358
		wp_send_json(
359
			array(
360
				'result'    => empty( $messages ) ? 'success' : 'failure',
361
				'messages'  => $messages,
362
				'reload'    => $reload_checkout ? 'true' : 'false',
363
				'fragments' => apply_filters(
364
					'woocommerce_update_order_review_fragments',
365
					array(
366
						'.woocommerce-checkout-review-order-table' => $woocommerce_order_review,
367
						'.woocommerce-checkout-payment' => $woocommerce_checkout_payment,
368
					)
369
				),
370
			)
371
		);
372
	}
373
374
	/**
375
	 * AJAX add to cart.
376
	 */
377
	public static function add_to_cart() {
378
		ob_start();
379
380
		$product_id        = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_POST['product_id'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
381
		$product           = wc_get_product( $product_id );
382
		$quantity          = empty( $_POST['quantity'] ) ? 1 : wc_stock_amount( $_POST['quantity'] );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
383
		$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
384
		$product_status    = get_post_status( $product_id );
385
		$variation_id      = 0;
386
		$variation         = array();
387
388
		if ( $product && 'variation' === $product->get_type() ) {
389
			$variation_id = $product_id;
390
			$product_id   = $product->get_parent_id();
391
			$variation    = $product->get_variation_attributes();
392
		}
393
394
		if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation ) && 'publish' === $product_status ) {
395
396
			do_action( 'woocommerce_ajax_added_to_cart', $product_id );
397
398
			if ( 'yes' === get_option( 'woocommerce_cart_redirect_after_add' ) ) {
399
				wc_add_to_cart_message( array( $product_id => $quantity ), true );
400
			}
401
402
			// Return fragments
403
			self::get_refreshed_fragments();
404
405
		} else {
406
407
			// If there was an error adding to the cart, redirect to the product page to show any errors
408
			$data = array(
409
				'error'       => true,
410
				'product_url' => apply_filters( 'woocommerce_cart_redirect_after_error', get_permalink( $product_id ), $product_id ),
411
			);
412
413
			wp_send_json( $data );
414
		}
415
	}
416
417
	/**
418
	 * AJAX remove from cart.
419
	 */
420
	public static function remove_from_cart() {
421
		ob_start();
422
423
		$cart_item_key = wc_clean( $_POST['cart_item_key'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
424
425
		if ( $cart_item_key && false !== WC()->cart->remove_cart_item( $cart_item_key ) ) {
426
			self::get_refreshed_fragments();
427
		} else {
428
			wp_send_json_error();
429
		}
430
	}
431
432
	/**
433
	 * Process ajax checkout form.
434
	 */
435
	public static function checkout() {
436
		wc_maybe_define_constant( 'WOOCOMMERCE_CHECKOUT', true );
437
		WC()->checkout()->process_checkout();
438
		wp_die( 0 );
439
	}
440
441
	/**
442
	 * Get a matching variation based on posted attributes.
443
	 */
444
	public static function get_variation() {
445
		ob_start();
446
447
		if ( empty( $_POST['product_id'] ) || ! ( $variable_product = wc_get_product( absint( $_POST['product_id'] ) ) ) ) {
448
			wp_die();
449
		}
450
451
		$data_store   = WC_Data_Store::load( 'product' );
452
		$variation_id = $data_store->find_matching_product_variation( $variable_product, wp_unslash( $_POST ) );
0 ignored issues
show
Documentation Bug introduced by
The method find_matching_product_variation does not exist on object<WC_Data_Store>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
453
		$variation    = $variation_id ? $variable_product->get_available_variation( $variation_id ) : false;
454
		wp_send_json( $variation );
455
	}
456
457
	/**
458
	 * Locate user via AJAX.
459
	 */
460
	public static function get_customer_location() {
461
		$location_hash = WC_Cache_Helper::geolocation_ajax_get_location_hash();
462
		wp_send_json_success( array( 'hash' => $location_hash ) );
463
	}
464
465
	/**
466
	 * Toggle Featured status of a product from admin.
467
	 */
468
	public static function feature_product() {
469
		if ( current_user_can( 'edit_products' ) && check_admin_referer( 'woocommerce-feature-product' ) ) {
470
			$product = wc_get_product( absint( $_GET['product_id'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_GET
Loading history...
471
472
			if ( $product ) {
473
				$product->set_featured( ! $product->get_featured() );
474
				$product->save();
475
			}
476
		}
477
478
		wp_safe_redirect( wp_get_referer() ? remove_query_arg( array( 'trashed', 'untrashed', 'deleted', 'ids' ), wp_get_referer() ) : admin_url( 'edit.php?post_type=product' ) );
479
		exit;
480
	}
481
482
	/**
483
	 * Mark an order with a status.
484
	 */
485
	public static function mark_order_status() {
486
		if ( current_user_can( 'edit_shop_orders' ) && check_admin_referer( 'woocommerce-mark-order-status' ) ) {
487
			$status = sanitize_text_field( $_GET['status'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_GET
Loading history...
488
			$order  = wc_get_order( absint( $_GET['order_id'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_GET
Loading history...
489
490
			if ( wc_is_order_status( 'wc-' . $status ) && $order ) {
491
				// Initialize payment gateways in case order has hooked status transition actions.
492
				WC()->payment_gateways();
493
494
				$order->update_status( $status, '', true );
495
				do_action( 'woocommerce_order_edit_status', $order->get_id(), $status );
496
			}
497
		}
498
499
		wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url( 'edit.php?post_type=shop_order' ) );
500
		exit;
501
	}
502
503
	/**
504
	 * Get order details.
505
	 */
506 View Code Duplication
	public static function get_order_details() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
507
		check_admin_referer( 'woocommerce-preview-order', 'security' );
508
509
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
510
			wp_die( -1 );
511
		}
512
513
		$order = wc_get_order( absint( $_GET['order_id'] ) ); // WPCS: sanitization ok.
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_GET
Loading history...
514
515
		if ( $order ) {
516
			include_once 'admin/list-tables/class-wc-admin-list-table-orders.php';
517
518
			wp_send_json_success( WC_Admin_List_Table_Orders::order_preview_get_order_details( $order ) );
519
		}
520
		wp_die();
521
	}
522
523
	/**
524
	 * Add an attribute row.
525
	 */
526
	public static function add_attribute() {
527
		ob_start();
528
529
		check_ajax_referer( 'add-attribute', 'security' );
530
531
		if ( ! current_user_can( 'edit_products' ) ) {
532
			wp_die( -1 );
533
		}
534
535
		$i             = absint( $_POST['i'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
536
		$metabox_class = array();
537
		$attribute     = new WC_Product_Attribute();
538
539
		$attribute->set_id( wc_attribute_taxonomy_id_by_name( sanitize_text_field( $_POST['taxonomy'] ) ) );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
540
		$attribute->set_name( sanitize_text_field( $_POST['taxonomy'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
541
		$attribute->set_visible( apply_filters( 'woocommerce_attribute_default_visibility', 1 ) );
542
		$attribute->set_variation( apply_filters( 'woocommerce_attribute_default_is_variation', 0 ) );
543
544
		if ( $attribute->is_taxonomy() ) {
545
			$metabox_class[] = 'taxonomy';
546
			$metabox_class[] = $attribute->get_name();
547
		}
548
549
		include 'admin/meta-boxes/views/html-product-attribute.php';
550
		wp_die();
551
	}
552
553
	/**
554
	 * Add a new attribute via ajax function.
555
	 */
556
	public static function add_new_attribute() {
557
		check_ajax_referer( 'add-attribute', 'security' );
558
559
		if ( current_user_can( 'manage_product_terms' ) ) {
560
			$taxonomy = esc_attr( $_POST['taxonomy'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
561
			$term     = wc_clean( $_POST['term'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
562
563
			if ( taxonomy_exists( $taxonomy ) ) {
564
565
				$result = wp_insert_term( $term, $taxonomy );
566
567
				if ( is_wp_error( $result ) ) {
568
					wp_send_json(
569
						array(
570
							'error' => $result->get_error_message(),
571
						)
572
					);
573
				} else {
574
					$term = get_term_by( 'id', $result['term_id'], $taxonomy );
575
					wp_send_json(
576
						array(
577
							'term_id' => $term->term_id,
578
							'name'    => $term->name,
579
							'slug'    => $term->slug,
580
						)
581
					);
582
				}
583
			}
584
		}
585
		wp_die( -1 );
586
	}
587
588
	/**
589
	 * Delete variations via ajax function.
590
	 */
591
	public static function remove_variations() {
592
		check_ajax_referer( 'delete-variations', 'security' );
593
594
		if ( current_user_can( 'edit_products' ) ) {
595
			$variation_ids = (array) $_POST['variation_ids'];
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
596
597
			foreach ( $variation_ids as $variation_id ) {
598
				if ( 'product_variation' === get_post_type( $variation_id ) ) {
599
					$variation = wc_get_product( $variation_id );
600
					$variation->delete( true );
601
				}
602
			}
603
		}
604
605
		wp_die( -1 );
606
	}
607
608
	/**
609
	 * Save attributes via ajax.
610
	 */
611
	public static function save_attributes() {
612
		check_ajax_referer( 'save-attributes', 'security' );
613
614
		if ( ! current_user_can( 'edit_products' ) ) {
615
			wp_die( -1 );
616
		}
617
618
		$response = array();
619
620
		try {
621
			parse_str( wp_unslash( $_POST['data'] ), $data );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
622
623
			$attributes   = WC_Meta_Box_Product_Data::prepare_attributes( $data );
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type null; however, WC_Meta_Box_Product_Data::prepare_attributes() does only seem to accept false|array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
624
			$product_id   = absint( $_POST['post_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
625
			$product_type = ! empty( $_POST['product_type'] ) ? wc_clean( $_POST['product_type'] ) : 'simple';
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
626
			$classname    = WC_Product_Factory::get_product_classname( $product_id, $product_type );
0 ignored issues
show
Bug introduced by
It seems like $product_type defined by !empty($_POST['product_t...duct_type']) : 'simple' on line 625 can also be of type array; however, WC_Product_Factory::get_product_classname() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
627
			$product      = new $classname( $product_id );
628
629
			$product->set_attributes( $attributes );
630
			$product->save();
631
632
			ob_start();
633
			$attributes = $product->get_attributes( 'edit' );
634
			$i          = -1;
635
636
			foreach ( $data['attribute_names'] as $attribute_name ) {
637
				$attribute = isset( $attributes[ sanitize_title( $attribute_name ) ] ) ? $attributes[ sanitize_title( $attribute_name ) ] : false;
638
				if ( ! $attribute ) {
639
					continue;
640
				}
641
				$i++;
642
				$metabox_class = array();
643
644
				if ( $attribute->is_taxonomy() ) {
645
					$metabox_class[] = 'taxonomy';
646
					$metabox_class[] = $attribute->get_name();
647
				}
648
649
				include( 'admin/meta-boxes/views/html-product-attribute.php' );
650
			}
651
652
			$response['html'] = ob_get_clean();
653
		} catch ( Exception $e ) {
654
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
655
		}
656
657
		// wp_send_json_success must be outside the try block not to break phpunit tests.
658
		wp_send_json_success( $response );
659
	}
660
661
	/**
662
	 * Add variation via ajax function.
663
	 */
664
	public static function add_variation() {
665
		check_ajax_referer( 'add-variation', 'security' );
666
667
		if ( ! current_user_can( 'edit_products' ) ) {
668
			wp_die( -1 );
669
		}
670
671
		global $post; // Set $post global so its available, like within the admin screens.
672
673
		$product_id       = intval( $_POST['post_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
674
		$post             = get_post( $product_id );
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
675
		$loop             = intval( $_POST['loop'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
676
		$product_object   = wc_get_product( $product_id );
677
		$variation_object = new WC_Product_Variation();
678
		$variation_object->set_parent_id( $product_id );
679
		$variation_object->set_attributes( array_fill_keys( array_map( 'sanitize_title', array_keys( $product_object->get_variation_attributes() ) ), '' ) );
680
		$variation_id   = $variation_object->save();
681
		$variation      = get_post( $variation_id );
682
		$variation_data = array_merge( get_post_custom( $variation_id ), wc_get_product_variation_attributes( $variation_id ) ); // kept for BW compatibility.
683
		include 'admin/meta-boxes/views/html-variation-admin.php';
684
		wp_die();
685
	}
686
687
	/**
688
	 * Link all variations via ajax function.
689
	 */
690
	public static function link_all_variations() {
691
		check_ajax_referer( 'link-variations', 'security' );
692
693
		if ( ! current_user_can( 'edit_products' ) ) {
694
			wp_die( -1 );
695
		}
696
697
		wc_maybe_define_constant( 'WC_MAX_LINKED_VARIATIONS', 49 );
698
		wc_set_time_limit( 0 );
699
700
		$post_id = intval( $_POST['post_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
701
702
		if ( ! $post_id ) {
703
			wp_die();
704
		}
705
706
		$product    = wc_get_product( $post_id );
707
		$attributes = wc_list_pluck( array_filter( $product->get_attributes(), 'wc_attributes_array_filter_variation' ), 'get_slugs' );
708
709
		if ( ! empty( $attributes ) ) {
710
			// Get existing variations so we don't create duplicates.
711
			$existing_variations = array_map( 'wc_get_product', $product->get_children() );
712
			$existing_attributes = array();
713
714
			foreach ( $existing_variations as $existing_variation ) {
715
				$existing_attributes[] = $existing_variation->get_attributes();
716
			}
717
718
			$added               = 0;
719
			$possible_attributes = array_reverse( wc_array_cartesian( $attributes ) );
720
721
			foreach ( $possible_attributes as $possible_attribute ) {
722
				if ( in_array( $possible_attribute, $existing_attributes ) ) {
723
					continue;
724
				}
725
				$variation = new WC_Product_Variation();
726
				$variation->set_parent_id( $post_id );
727
				$variation->set_attributes( $possible_attribute );
728
729
				do_action( 'product_variation_linked', $variation->save() );
730
731
				if ( ( $added ++ ) > WC_MAX_LINKED_VARIATIONS ) {
732
					break;
733
				}
734
			}
735
736
			echo $added;
737
		}
738
739
		$data_store = $product->get_data_store();
740
		$data_store->sort_all_product_variations( $product->get_id() );
741
		wp_die();
742
	}
743
744
	/**
745
	 * Delete download permissions via ajax function.
746
	 */
747
	public static function revoke_access_to_download() {
748
		check_ajax_referer( 'revoke-access', 'security' );
749
750
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
751
			wp_die( -1 );
752
		}
753
		$download_id   = $_POST['download_id'];
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
754
		$product_id    = intval( $_POST['product_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
755
		$order_id      = intval( $_POST['order_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
756
		$permission_id = absint( $_POST['permission_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
757
		$data_store    = WC_Data_Store::load( 'customer-download' );
758
		$data_store->delete_by_id( $permission_id );
0 ignored issues
show
Documentation Bug introduced by
The method delete_by_id does not exist on object<WC_Data_Store>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
759
760
		do_action( 'woocommerce_ajax_revoke_access_to_product_download', $download_id, $product_id, $order_id, $permission_id );
761
762
		wp_die();
763
	}
764
765
	/**
766
	 * Grant download permissions via ajax function.
767
	 */
768
	public static function grant_access_to_download() {
769
770
		check_ajax_referer( 'grant-access', 'security' );
771
772
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
773
			wp_die( -1 );
774
		}
775
776
		global $wpdb;
777
778
		$wpdb->hide_errors();
779
780
		$order_id     = intval( $_POST['order_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
781
		$product_ids  = $_POST['product_ids'];
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
782
		$loop         = intval( $_POST['loop'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
783
		$file_counter = 0;
784
		$order        = wc_get_order( $order_id );
785
786
		if ( ! is_array( $product_ids ) ) {
787
			$product_ids = array( $product_ids );
788
		}
789
790
		foreach ( $product_ids as $product_id ) {
791
			$product = wc_get_product( $product_id );
792
			$files   = $product->get_downloads();
793
794
			if ( ! $order->get_billing_email() ) {
795
				wp_die();
796
			}
797
798
			if ( ! empty( $files ) ) {
799
				foreach ( $files as $download_id => $file ) {
800
					if ( $inserted_id = wc_downloadable_file_permission( $download_id, $product_id, $order ) ) {
0 ignored issues
show
Documentation introduced by
$order is of type false|object, but the function expects a object<WC_Order>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
801
						$download = new WC_Customer_Download( $inserted_id );
0 ignored issues
show
Bug introduced by
It seems like $inserted_id defined by wc_downloadable_file_per...d, $product_id, $order) on line 800 can also be of type boolean; however, WC_Customer_Download::__construct() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
802
						$loop ++;
803
						$file_counter ++;
804
805
						if ( $file->get_name() ) {
806
							$file_count = $file->get_name();
807
						} else {
808
							/* translators: %d file count */
809
							$file_count = sprintf( __( 'File %d', 'woocommerce' ), $file_counter );
810
						}
811
						include 'admin/meta-boxes/views/html-order-download-permission.php';
812
					}
813
				}
814
			}
815
		}
816
		wp_die();
817
	}
818
819
	/**
820
	 * Get customer details via ajax.
821
	 */
822
	public static function get_customer_details() {
823
		check_ajax_referer( 'get-customer-details', 'security' );
824
825
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
826
			wp_die( -1 );
827
		}
828
829
		$user_id  = absint( $_POST['user_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
830
		$customer = new WC_Customer( $user_id );
831
832
		if ( has_filter( 'woocommerce_found_customer_details' ) ) {
833
			wc_deprecated_function( 'The woocommerce_found_customer_details filter', '3.0', 'woocommerce_ajax_get_customer_details' );
834
		}
835
836
		$data                  = $customer->get_data();
837
		$data['date_created']  = $data['date_created'] ? $data['date_created']->getTimestamp() : null;
838
		$data['date_modified'] = $data['date_modified'] ? $data['date_modified']->getTimestamp() : null;
839
840
		$customer_data = apply_filters( 'woocommerce_ajax_get_customer_details', $data, $customer, $user_id );
841
		wp_send_json( $customer_data );
842
	}
843
844
	/**
845
	 * Add order item via ajax. Used on the edit order screen in WP Admim.
846
	 */
847
	public static function add_order_item() {
848
		check_ajax_referer( 'order-item', 'security' );
849
850
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
851
			wp_die( -1 );
852
		}
853
854
		$response = array();
855
856
		try {
857
			if ( ! isset( $_POST['order_id'] ) ) {
858
				throw new Exception( __( 'Invalid order', 'woocommerce' ) );
859
			}
860
861
			$order_id = absint( wp_unslash( $_POST['order_id'] ) ); // WPCS: input var ok.
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
862
			$order    = wc_get_order( $order_id );
863
864
			if ( ! $order ) {
865
				throw new Exception( __( 'Invalid order', 'woocommerce' ) );
866
			}
867
868
			// If we passed through items it means we need to save first before adding a new one.
869 View Code Duplication
			if ( ! empty( $_POST['items'] ) ) {
870
				$save_items = array();
871
				parse_str( wp_unslash( $_POST['items'] ), $save_items );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
872
				wc_save_order_items( $order->get_id(), $save_items );
0 ignored issues
show
Bug introduced by
It seems like $save_items can also be of type null; however, wc_save_order_items() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
873
			}
874
875
			$items_to_add = array_filter( wp_unslash( (array) $_POST['data'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
876
877
			// Add items to order.
878
			$order_notes = array();
879
880
			foreach ( $items_to_add as $item ) {
881
				if ( ! isset( $item['id'], $item['qty'] ) || empty( $item['id'] ) ) {
882
					continue;
883
				}
884
				$product_id = absint( $item['id'] );
885
				$qty        = wc_stock_amount( $item['qty'] );
886
				$product    = wc_get_product( $product_id );
887
888
				if ( ! $product ) {
889
					throw new Exception( __( 'Invalid product ID', 'woocommerce' ) . ' ' . $product_id );
890
				}
891
892
				$item_id                 = $order->add_product( $product, $qty );
893
				$item                    = apply_filters( 'woocommerce_ajax_order_item', $order->get_item( $item_id ), $item_id );
894
				$added_items[ $item_id ] = $item;
895
				$order_notes[ $item_id ] = $product->get_formatted_name();
896
897
				if ( $product->managing_stock() ) {
898
					$new_stock               = wc_update_product_stock( $product, $qty, 'decrease' );
899
					$order_notes[ $item_id ] = $product->get_formatted_name() . ' &ndash; ' . ( $new_stock + $qty ) . '&rarr;' . $new_stock;
900
					$item->add_meta_data( '_reduced_stock', $qty, true );
901
					$item->save();
902
				}
903
904
				do_action( 'woocommerce_ajax_add_order_item_meta', $item_id, $item, $order );
905
			}
906
907
			/* translators: %s item name. */
908
			$order->add_order_note( sprintf( __( 'Added line items: %s', 'woocommerce' ), implode( ', ', $order_notes ) ), false, true );
909
910
			do_action( 'woocommerce_ajax_order_items_added', $added_items, $order );
911
912
			$data = get_post_meta( $order_id );
913
914
			// Get HTML to return.
915
			ob_start();
916
			include 'admin/meta-boxes/views/html-order-items.php';
917
			$items_html = ob_get_clean();
918
919
			ob_start();
920
			$notes = wc_get_order_notes( array( 'order_id' => $order_id ) );
921
			include 'admin/meta-boxes/views/html-order-notes.php';
922
			$notes_html = ob_get_clean();
923
924
			wp_send_json_success(
925
				array(
926
					'html'       => $items_html,
927
					'notes_html' => $notes_html,
928
				)
929
			);
930
		} catch ( Exception $e ) {
931
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
932
		}
933
934
		// wp_send_json_success must be outside the try block not to break phpunit tests.
935
		wp_send_json_success( $response );
936
	}
937
938
	/**
939
	 * Add order fee via ajax.
940
	 */
941
	public static function add_order_fee() {
942
		check_ajax_referer( 'order-item', 'security' );
943
944
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
945
			wp_die( -1 );
946
		}
947
948
		$response = array();
949
950
		try {
951
			$order_id           = absint( $_POST['order_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
952
			$amount             = wc_clean( $_POST['amount'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
953
			$order              = wc_get_order( $order_id );
954
			$calculate_tax_args = array(
955
				'country'  => strtoupper( wc_clean( $_POST['country'] ) ),
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
956
				'state'    => strtoupper( wc_clean( $_POST['state'] ) ),
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
957
				'postcode' => strtoupper( wc_clean( $_POST['postcode'] ) ),
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
958
				'city'     => strtoupper( wc_clean( $_POST['city'] ) ),
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
959
			);
960
961
			if ( ! $order ) {
962
				throw new exception( __( 'Invalid order', 'woocommerce' ) );
963
			}
964
965
			if ( strstr( $amount, '%' ) ) {
966
				$formatted_amount = $amount;
967
				$percent          = floatval( trim( $amount, '%' ) );
968
				$amount           = $order->get_total() * ( $percent / 100 );
969
			} else {
970
				$amount           = floatval( $amount );
971
				$formatted_amount = wc_price( $amount, array( 'currency' => $order->get_currency() ) );
972
			}
973
974
			$fee = new WC_Order_Item_Fee();
975
			$fee->set_amount( $amount );
976
			$fee->set_total( $amount );
977
			/* translators: %s fee amount */
978
			$fee->set_name( sprintf( __( '%s fee', 'woocommerce' ), wc_clean( $formatted_amount ) ) );
979
980
			$order->add_item( $fee );
981
			$order->calculate_taxes( $calculate_tax_args );
982
			$order->calculate_totals( false );
983
			$order->save();
984
985
			ob_start();
986
			include 'admin/meta-boxes/views/html-order-items.php';
987
			$response['html'] = ob_get_clean();
988
		} catch ( Exception $e ) {
989
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
990
		}
991
992
		// wp_send_json_success must be outside the try block not to break phpunit tests.
993
		wp_send_json_success( $response );
994
	}
995
996
	/**
997
	 * Add order shipping cost via ajax.
998
	 */
999
	public static function add_order_shipping() {
1000
		check_ajax_referer( 'order-item', 'security' );
1001
1002
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
1003
			wp_die( -1 );
1004
		}
1005
1006
		$response = array();
1007
1008
		try {
1009
			$order_id         = absint( $_POST['order_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1010
			$order            = wc_get_order( $order_id );
1011
			$order_taxes      = $order->get_taxes();
1012
			$shipping_methods = WC()->shipping() ? WC()->shipping()->load_shipping_methods() : array();
1013
1014
			// Add new shipping
1015
			$item = new WC_Order_Item_Shipping();
1016
			$item->set_shipping_rate( new WC_Shipping_Rate() );
1017
			$item->set_order_id( $order_id );
1018
			$item_id = $item->save();
1019
1020
			ob_start();
1021
			include 'admin/meta-boxes/views/html-order-shipping.php';
1022
			$response['html'] = ob_get_clean();
1023
		} catch ( Exception $e ) {
1024
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
1025
		}
1026
1027
		// wp_send_json_success must be outside the try block not to break phpunit tests.
1028
		wp_send_json_success( $response );
1029
	}
1030
1031
	/**
1032
	 * Add order tax column via ajax.
1033
	 */
1034
	public static function add_order_tax() {
1035
		check_ajax_referer( 'order-item', 'security' );
1036
1037
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
1038
			wp_die( -1 );
1039
		}
1040
1041
		$response = array();
1042
1043
		try {
1044
			$order_id = absint( $_POST['order_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1045
			$rate_id  = absint( $_POST['rate_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1046
			$order    = wc_get_order( $order_id );
1047
			$data     = get_post_meta( $order_id );
1048
1049
			// Add new tax
1050
			$item = new WC_Order_Item_Tax();
1051
			$item->set_rate( $rate_id );
1052
			$item->set_order_id( $order_id );
1053
			$item->save();
1054
1055
			ob_start();
1056
			include 'admin/meta-boxes/views/html-order-items.php';
1057
			$response['html'] = ob_get_clean();
1058
		} catch ( Exception $e ) {
1059
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
1060
		}
1061
1062
		// wp_send_json_success must be outside the try block not to break phpunit tests.
1063
		wp_send_json_success( $response );
1064
	}
1065
1066
	/**
1067
	 * Add order discount via ajax.
1068
	 */
1069
	public static function add_coupon_discount() {
1070
		check_ajax_referer( 'order-item', 'security' );
1071
1072
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
1073
			wp_die( -1 );
1074
		}
1075
1076
		$response = array();
1077
1078
		try {
1079
			$order_id = absint( $_POST['order_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1080
			$order    = wc_get_order( $order_id );
1081
			$result   = $order->apply_coupon( wc_clean( $_POST['coupon'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1082
1083
			if ( is_wp_error( $result ) ) {
1084
				throw new Exception( html_entity_decode( wp_strip_all_tags( $result->get_error_message() ) ) );
1085
			}
1086
1087
			ob_start();
1088
			include 'admin/meta-boxes/views/html-order-items.php';
1089
			$response['html'] = ob_get_clean();
1090
		} catch ( Exception $e ) {
1091
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
1092
		}
1093
1094
		// wp_send_json_success must be outside the try block not to break phpunit tests.
1095
		wp_send_json_success( $response );
1096
	}
1097
1098
	/**
1099
	 * Remove coupon from an order via ajax.
1100
	 */
1101
	public static function remove_order_coupon() {
1102
		check_ajax_referer( 'order-item', 'security' );
1103
1104
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
1105
			wp_die( -1 );
1106
		}
1107
1108
		$response = array();
1109
1110
		try {
1111
			$order_id = absint( $_POST['order_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1112
			$order    = wc_get_order( $order_id );
1113
1114
			$order->remove_coupon( wc_clean( $_POST['coupon'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1115
1116
			ob_start();
1117
			include 'admin/meta-boxes/views/html-order-items.php';
1118
			$response['html'] = ob_get_clean();
1119
		} catch ( Exception $e ) {
1120
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
1121
		}
1122
1123
		// wp_send_json_success must be outside the try block not to break phpunit tests.
1124
		wp_send_json_success( $response );
1125
	}
1126
1127
	/**
1128
	 * Remove an order item.
1129
	 */
1130
	public static function remove_order_item() {
1131
		check_ajax_referer( 'order-item', 'security' );
1132
1133
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
1134
			wp_die( -1 );
1135
		}
1136
1137
		$response = array();
1138
1139
		try {
1140
			$order_id = absint( $_POST['order_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1141
			$order    = wc_get_order( $order_id );
1142
1143
			if ( ! $order ) {
1144
				throw new Exception( __( 'Invalid order', 'woocommerce' ) );
1145
			}
1146
1147
			if ( ! isset( $_POST['order_item_ids'] ) ) {
1148
				throw new Exception( __( 'Invalid items', 'woocommerce' ) );
1149
			}
1150
1151
			$order_item_ids     = wp_unslash( $_POST['order_item_ids'] );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1152
			$calculate_tax_args = array(
1153
				'country'  => strtoupper( wc_clean( wp_unslash( $_POST['country'] ) ) ),
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1154
				'state'    => strtoupper( wc_clean( wp_unslash( $_POST['state'] ) ) ),
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1155
				'postcode' => strtoupper( wc_clean( wp_unslash( $_POST['postcode'] ) ) ),
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1156
				'city'     => strtoupper( wc_clean( wp_unslash( $_POST['city'] ) ) ),
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1157
			);
1158
1159
			if ( ! is_array( $order_item_ids ) && is_numeric( $order_item_ids ) ) {
1160
				$order_item_ids = array( $order_item_ids );
1161
			}
1162
1163
			// If we passed through items it means we need to save first before deleting.
1164 View Code Duplication
			if ( ! empty( $_POST['items'] ) ) {
1165
				$save_items = array();
1166
				parse_str( wp_unslash( $_POST['items'] ), $save_items );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1167
				wc_save_order_items( $order->get_id(), $save_items );
0 ignored issues
show
Bug introduced by
It seems like $save_items can also be of type null; however, wc_save_order_items() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1168
			}
1169
1170
			if ( ! empty( $order_item_ids ) ) {
1171
				$order_notes = array();
1172
1173
				foreach ( $order_item_ids as $item_id ) {
1174
					$item_id                 = absint( $item_id );
1175
					$item                    = $order->get_item( $item_id );
1176
1177
					// Before deleting the item, adjust any stock values already reduced.
1178
					if ( $item->is_type( 'line_item' ) ) {
1179
						$changed_stock = wc_maybe_adjust_line_item_product_stock( $item, 0 );
1180
1181
						if ( $changed_stock && ! is_wp_error( $changed_stock ) ) {
1182
							/* translators: %1$s: item name %2$s: stock change */
1183
							$order->add_order_note( sprintf( __( 'Deleted %1$s and adjusted stock (%2$s)', 'woocommerce' ), $item->get_name(), $changed_stock['from'] . '&rarr;' . $changed_stock['to'] ), false, true );
1184
						} else {
1185
							/* translators: %s item name. */
1186
							$order->add_order_note( sprintf( __( 'Deleted %s', 'woocommerce' ), $item->get_name() ), false, true );
1187
						}
1188
					}
1189
1190
					wc_delete_order_item( $item_id );
1191
				}
1192
			}
1193
1194
			$order = wc_get_order( $order_id );
1195
			$order->calculate_taxes( $calculate_tax_args );
1196
			$order->calculate_totals( false );
1197
1198
			// Get HTML to return.
1199
			ob_start();
1200
			include 'admin/meta-boxes/views/html-order-items.php';
1201
			$items_html = ob_get_clean();
1202
1203
			ob_start();
1204
			$notes = wc_get_order_notes( array( 'order_id' => $order_id ) );
1205
			include 'admin/meta-boxes/views/html-order-notes.php';
1206
			$notes_html = ob_get_clean();
1207
1208
			wp_send_json_success(
1209
				array(
1210
					'html'       => $items_html,
1211
					'notes_html' => $notes_html,
1212
				)
1213
			);
1214
		} catch ( Exception $e ) {
1215
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
1216
		}
1217
1218
		// wp_send_json_success must be outside the try block not to break phpunit tests.
1219
		wp_send_json_success( $response );
1220
	}
1221
1222
	/**
1223
	 * Remove an order tax.
1224
	 */
1225
	public static function remove_order_tax() {
1226
		check_ajax_referer( 'order-item', 'security' );
1227
1228
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
1229
			wp_die( -1 );
1230
		}
1231
1232
		$response = array();
1233
1234
		try {
1235
			$order_id = absint( $_POST['order_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1236
			$rate_id  = absint( $_POST['rate_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1237
1238
			wc_delete_order_item( $rate_id );
1239
1240
			$order = wc_get_order( $order_id );
1241
			$order->calculate_totals( false );
1242
1243
			ob_start();
1244
			include 'admin/meta-boxes/views/html-order-items.php';
1245
			$response['html'] = ob_get_clean();
1246
		} catch ( Exception $e ) {
1247
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
1248
		}
1249
1250
		// wp_send_json_success must be outside the try block not to break phpunit tests.
1251
		wp_send_json_success( $response );
1252
	}
1253
1254
	/**
1255
	 * Calc line tax.
1256
	 */
1257
	public static function calc_line_taxes() {
1258
		check_ajax_referer( 'calc-totals', 'security' );
1259
1260
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
1261
			wp_die( -1 );
1262
		}
1263
1264
		$order_id           = absint( $_POST['order_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1265
		$calculate_tax_args = array(
1266
			'country'  => strtoupper( wc_clean( $_POST['country'] ) ),
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1267
			'state'    => strtoupper( wc_clean( $_POST['state'] ) ),
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1268
			'postcode' => strtoupper( wc_clean( $_POST['postcode'] ) ),
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1269
			'city'     => strtoupper( wc_clean( $_POST['city'] ) ),
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1270
		);
1271
1272
		// Parse the jQuery serialized items
1273
		$items = array();
1274
		parse_str( $_POST['items'], $items );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1275
1276
		// Save order items first
1277
		wc_save_order_items( $order_id, $items );
0 ignored issues
show
Bug introduced by
It seems like $items can also be of type null; however, wc_save_order_items() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1278
1279
		// Grab the order and recalculate taxes
1280
		$order = wc_get_order( $order_id );
1281
		$order->calculate_taxes( $calculate_tax_args );
1282
		$order->calculate_totals( false );
1283
		include 'admin/meta-boxes/views/html-order-items.php';
1284
		wp_die();
1285
	}
1286
1287
	/**
1288
	 * Save order items via ajax.
1289
	 */
1290
	public static function save_order_items() {
1291
		check_ajax_referer( 'order-item', 'security' );
1292
1293
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
1294
			wp_die( -1 );
1295
		}
1296
1297
		if ( isset( $_POST['order_id'], $_POST['items'] ) ) {
1298
			$order_id = absint( $_POST['order_id'] );
1299
1300
			// Parse the jQuery serialized items
1301
			$items = array();
1302
			parse_str( $_POST['items'], $items );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1303
1304
			// Save order items
1305
			wc_save_order_items( $order_id, $items );
0 ignored issues
show
Bug introduced by
It seems like $items can also be of type null; however, wc_save_order_items() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1306
1307
			// Return HTML items
1308
			$order = wc_get_order( $order_id );
1309
1310
			// Get HTML to return.
1311
			ob_start();
1312
			include 'admin/meta-boxes/views/html-order-items.php';
1313
			$items_html = ob_get_clean();
1314
1315
			ob_start();
1316
			$notes = wc_get_order_notes( array( 'order_id' => $order_id ) );
1317
			include 'admin/meta-boxes/views/html-order-notes.php';
1318
			$notes_html = ob_get_clean();
1319
1320
			wp_send_json_success(
1321
				array(
1322
					'html'       => $items_html,
1323
					'notes_html' => $notes_html,
1324
				)
1325
			);
1326
		}
1327
		wp_die();
1328
	}
1329
1330
	/**
1331
	 * Load order items via ajax.
1332
	 */
1333 View Code Duplication
	public static function load_order_items() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1334
		check_ajax_referer( 'order-item', 'security' );
1335
1336
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
1337
			wp_die( -1 );
1338
		}
1339
1340
		// Return HTML items
1341
		$order_id = absint( $_POST['order_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1342
		$order    = wc_get_order( $order_id );
1343
		include 'admin/meta-boxes/views/html-order-items.php';
1344
		wp_die();
1345
	}
1346
1347
	/**
1348
	 * Add order note via ajax.
1349
	 */
1350
	public static function add_order_note() {
1351
		check_ajax_referer( 'add-order-note', 'security' );
1352
1353
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
1354
			wp_die( -1 );
1355
		}
1356
1357
		$post_id   = absint( $_POST['post_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1358
		$note      = wp_kses_post( trim( wp_unslash( $_POST['note'] ) ) );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1359
		$note_type = $_POST['note_type'];
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1360
1361
		$is_customer_note = ( 'customer' === $note_type ) ? 1 : 0;
1362
1363
		if ( $post_id > 0 ) {
1364
			$order      = wc_get_order( $post_id );
1365
			$comment_id = $order->add_order_note( $note, $is_customer_note, true );
1366
			$note       = wc_get_order_note( $comment_id );
1367
1368
			$note_classes   = array( 'note' );
1369
			$note_classes[] = $is_customer_note ? 'customer-note' : '';
1370
			$note_classes   = apply_filters( 'woocommerce_order_note_class', array_filter( $note_classes ), $note );
1371
			?>
1372
			<li rel="<?php echo absint( $note->id ); ?>" class="<?php echo esc_attr( implode( ' ', $note_classes ) ); ?>">
1373
				<div class="note_content">
1374
					<?php echo wpautop( wptexturize( wp_kses_post( make_clickable( $note->content ) ) ) ); ?>
1375
				</div>
1376
				<p class="meta">
1377
					<abbr class="exact-date" title="<?php echo $note->date_created->date( 'y-m-d h:i:s' ); ?>">
1378
						<?php
1379
						/* translators: $1: Date created, $2 Time created */
1380
						printf( __( 'added on %1$s at %2$s', 'woocommerce' ), $note->date_created->date_i18n( wc_date_format() ), $note->date_created->date_i18n( wc_time_format() ) );
1381
						?>
1382
					</abbr>
1383
					<?php
1384
					if ( 'system' !== $note->added_by ) :
1385
						/* translators: %s: note author */
1386
						printf( ' ' . __( 'by %s', 'woocommerce' ), $note->added_by );
1387
					endif;
1388
					?>
1389
					<a href="#" class="delete_note" role="button"><?php _e( 'Delete note', 'woocommerce' ); ?></a>
1390
				</p>
1391
			</li>
1392
			<?php
1393
		}
1394
		wp_die();
1395
	}
1396
1397
	/**
1398
	 * Delete order note via ajax.
1399
	 */
1400
	public static function delete_order_note() {
1401
		check_ajax_referer( 'delete-order-note', 'security' );
1402
1403
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
1404
			wp_die( -1 );
1405
		}
1406
1407
		$note_id = (int) $_POST['note_id'];
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1408
1409
		if ( $note_id > 0 ) {
1410
			wc_delete_order_note( $note_id );
1411
		}
1412
		wp_die();
1413
	}
1414
1415
	/**
1416
	 * Search for products and echo json.
1417
	 *
1418
	 * @param string $term (default: '')
1419
	 * @param bool   $include_variations in search or not
1420
	 */
1421
	public static function json_search_products( $term = '', $include_variations = false ) {
1422
		check_ajax_referer( 'search-products', 'security' );
1423
1424
		$term = wc_clean( empty( $term ) ? wp_unslash( $_GET['term'] ) : $term );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_GET
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
1425
1426
		if ( empty( $term ) ) {
1427
			wp_die();
1428
		}
1429
1430
		if ( ! empty( $_GET['limit'] ) ) {
1431
			$limit = absint( $_GET['limit'] );
1432
		} else {
1433
			$limit = absint( apply_filters( 'woocommerce_json_search_limit', 30 ) );
1434
		}
1435
1436
		$data_store = WC_Data_Store::load( 'product' );
1437
		$ids        = $data_store->search_products( $term, '', (bool) $include_variations, false, $limit );
0 ignored issues
show
Documentation Bug introduced by
The method search_products does not exist on object<WC_Data_Store>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
1438
1439
		if ( ! empty( $_GET['exclude'] ) ) {
1440
			$ids = array_diff( $ids, (array) $_GET['exclude'] );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
1441
		}
1442
1443
		if ( ! empty( $_GET['include'] ) ) {
1444
			$ids = array_intersect( $ids, (array) $_GET['include'] );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
1445
		}
1446
1447
		$product_objects = array_filter( array_map( 'wc_get_product', $ids ), 'wc_products_array_filter_readable' );
1448
		$products        = array();
1449
1450
		foreach ( $product_objects as $product_object ) {
1451
			$formatted_name = $product_object->get_formatted_name();
1452
			$managing_stock = $product_object->managing_stock();
1453
1454
			if ( $managing_stock && ! empty( $_GET['display_stock'] ) ) {
1455
				$formatted_name .= ' &ndash; ' . wc_format_stock_for_display( $product_object );
1456
			}
1457
1458
			$products[ $product_object->get_id() ] = rawurldecode( $formatted_name );
1459
		}
1460
1461
		wp_send_json( apply_filters( 'woocommerce_json_search_found_products', $products ) );
1462
	}
1463
1464
	/**
1465
	 * Search for product variations and return json.
1466
	 *
1467
	 * @see WC_AJAX::json_search_products()
1468
	 */
1469
	public static function json_search_products_and_variations() {
1470
		self::json_search_products( '', true );
1471
	}
1472
1473
	/**
1474
	 * Search for downloadable product variations and return json.
1475
	 *
1476
	 * @see WC_AJAX::json_search_products()
1477
	 */
1478
	public static function json_search_downloadable_products_and_variations() {
1479
		check_ajax_referer( 'search-products', 'security' );
1480
1481
		$term       = (string) wc_clean( wp_unslash( $_GET['term'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_GET
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
1482
		$data_store = WC_Data_Store::load( 'product' );
1483
		$ids        = $data_store->search_products( $term, 'downloadable', true );
0 ignored issues
show
Documentation Bug introduced by
The method search_products does not exist on object<WC_Data_Store>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
1484
1485
		if ( ! empty( $_GET['exclude'] ) ) {
1486
			$ids = array_diff( $ids, (array) $_GET['exclude'] );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
1487
		}
1488
1489
		if ( ! empty( $_GET['include'] ) ) {
1490
			$ids = array_intersect( $ids, (array) $_GET['include'] );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
1491
		}
1492
1493
		if ( ! empty( $_GET['limit'] ) ) {
1494
			$ids = array_slice( $ids, 0, absint( $_GET['limit'] ) );
1495
		}
1496
1497
		$product_objects = array_filter( array_map( 'wc_get_product', $ids ), 'wc_products_array_filter_readable' );
1498
		$products        = array();
1499
1500
		foreach ( $product_objects as $product_object ) {
1501
			$products[ $product_object->get_id() ] = rawurldecode( $product_object->get_formatted_name() );
1502
		}
1503
1504
		wp_send_json( $products );
1505
	}
1506
1507
	/**
1508
	 * Search for customers and return json.
1509
	 */
1510
	public static function json_search_customers() {
1511
		ob_start();
1512
1513
		check_ajax_referer( 'search-customers', 'security' );
1514
1515
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
1516
			wp_die( -1 );
1517
		}
1518
1519
		$term  = wc_clean( wp_unslash( $_GET['term'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_GET
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
1520
		$limit = 0;
1521
1522
		if ( empty( $term ) ) {
1523
			wp_die();
1524
		}
1525
1526
		$ids = array();
1527
		// Search by ID.
1528
		if ( is_numeric( $term ) ) {
1529
			$customer = new WC_Customer( intval( $term ) );
1530
1531
			// Customer does not exists.
1532
			if ( 0 !== $customer->get_id() ) {
1533
				$ids = array( $customer->get_id() );
1534
			}
1535
		}
1536
1537
		// Usernames can be numeric so we first check that no users was found by ID before searching for numeric username, this prevents performance issues with ID lookups.
1538
		if ( empty( $ids ) ) {
1539
			$data_store = WC_Data_Store::load( 'customer' );
1540
1541
			// If search is smaller than 3 characters, limit result set to avoid
1542
			// too many rows being returned.
1543
			if ( 3 > strlen( $term ) ) {
1544
				$limit = 20;
1545
			}
1546
			$ids = $data_store->search_customers( $term, $limit );
0 ignored issues
show
Documentation Bug introduced by
The method search_customers does not exist on object<WC_Data_Store>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
1547
		}
1548
1549
		$found_customers = array();
1550
1551
		if ( ! empty( $_GET['exclude'] ) ) {
1552
			$ids = array_diff( $ids, (array) $_GET['exclude'] );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
1553
		}
1554
1555
		foreach ( $ids as $id ) {
1556
			$customer = new WC_Customer( $id );
1557
			/* translators: 1: user display name 2: user ID 3: user email */
1558
			$found_customers[ $id ] = sprintf(
1559
				/* translators: $1: customer name, $2 customer id, $3: customer email */
1560
				esc_html__( '%1$s (#%2$s &ndash; %3$s)', 'woocommerce' ),
1561
				$customer->get_first_name() . ' ' . $customer->get_last_name(),
1562
				$customer->get_id(),
1563
				$customer->get_email()
1564
			);
1565
		}
1566
1567
		wp_send_json( apply_filters( 'woocommerce_json_search_found_customers', $found_customers ) );
1568
	}
1569
1570
	/**
1571
	 * Search for categories and return json.
1572
	 */
1573
	public static function json_search_categories() {
1574
		ob_start();
1575
1576
		check_ajax_referer( 'search-categories', 'security' );
1577
1578
		if ( ! current_user_can( 'edit_products' ) ) {
1579
			wp_die( -1 );
1580
		}
1581
1582
		if ( ! $search_text = wc_clean( wp_unslash( $_GET['term'] ) ) ) {
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_GET
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
1583
			wp_die();
1584
		}
1585
1586
		$found_categories = array();
1587
		$args             = array(
1588
			'taxonomy'   => array( 'product_cat' ),
1589
			'orderby'    => 'id',
1590
			'order'      => 'ASC',
1591
			'hide_empty' => true,
1592
			'fields'     => 'all',
1593
			'name__like' => $search_text,
1594
		);
1595
1596
		if ( $terms = get_terms( $args ) ) {
1597
			foreach ( $terms as $term ) {
1598
				$term->formatted_name = '';
1599
1600 View Code Duplication
				if ( $term->parent ) {
1601
					$ancestors = array_reverse( get_ancestors( $term->term_id, 'product_cat' ) );
1602
					foreach ( $ancestors as $ancestor ) {
1603
						if ( $ancestor_term = get_term( $ancestor, 'product_cat' ) ) {
1604
							$term->formatted_name .= $ancestor_term->name . ' > ';
1605
						}
1606
					}
1607
				}
1608
1609
				$term->formatted_name              .= $term->name . ' (' . $term->count . ')';
1610
				$found_categories[ $term->term_id ] = $term;
1611
			}
1612
		}
1613
1614
		wp_send_json( apply_filters( 'woocommerce_json_search_found_categories', $found_categories ) );
1615
	}
1616
1617
	/**
1618
	 * Ajax request handling for categories ordering.
1619
	 */
1620
	public static function term_ordering() {
1621
1622
		// check permissions again and make sure we have what we need
1623
		if ( ! current_user_can( 'edit_products' ) || empty( $_POST['id'] ) ) {
1624
			wp_die( -1 );
1625
		}
1626
1627
		$id       = (int) $_POST['id'];
1628
		$next_id  = isset( $_POST['nextid'] ) && (int) $_POST['nextid'] ? (int) $_POST['nextid'] : null;
1629
		$taxonomy = isset( $_POST['thetaxonomy'] ) ? esc_attr( $_POST['thetaxonomy'] ) : null;
1630
		$term     = get_term_by( 'id', $id, $taxonomy );
1631
1632
		if ( ! $id || ! $term || ! $taxonomy ) {
1633
			wp_die( 0 );
1634
		}
1635
1636
		wc_reorder_terms( $term, $next_id, $taxonomy );
1637
1638
		$children = get_terms( $taxonomy, "child_of=$id&menu_order=ASC&hide_empty=0" );
1639
1640
		if ( $term && sizeof( $children ) ) {
1641
			echo 'children';
1642
			wp_die();
1643
		}
1644
	}
1645
1646
	/**
1647
	 * Ajax request handling for product ordering.
1648
	 *
1649
	 * Based on Simple Page Ordering by 10up (https://wordpress.org/plugins/simple-page-ordering/).
1650
	 */
1651
	public static function product_ordering() {
1652
		global $wpdb;
1653
1654
		if ( ! current_user_can( 'edit_products' ) || empty( $_POST['id'] ) ) {
1655
			wp_die( -1 );
1656
		}
1657
1658
		$sorting_id  = absint( $_POST['id'] );
1659
		$previd      = absint( isset( $_POST['previd'] ) ? $_POST['previd'] : 0 );
1660
		$nextid      = absint( isset( $_POST['nextid'] ) ? $_POST['nextid'] : 0 );
1661
		$menu_orders = wp_list_pluck( $wpdb->get_results( "SELECT ID, menu_order FROM {$wpdb->posts} WHERE post_type = 'product' ORDER BY menu_order ASC, post_title ASC" ), 'menu_order', 'ID' );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
introduced by
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
1662
		$index       = 0;
1663
1664
		foreach ( $menu_orders as $id => $menu_order ) {
1665
			$id = absint( $id );
1666
1667
			if ( $sorting_id === $id ) {
1668
				continue;
1669
			}
1670
			if ( $nextid === $id ) {
1671
				$index ++;
1672
			}
1673
			$index ++;
1674
			$menu_orders[ $id ] = $index;
1675
			$wpdb->update( $wpdb->posts, array( 'menu_order' => $index ), array( 'ID' => $id ) );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
1676
1677
			/**
1678
			 * When a single product has gotten it's ordering updated.
1679
			 * $id The product ID
1680
			 * $index The new menu order
1681
			*/
1682
			do_action( 'woocommerce_after_single_product_ordering', $id, $index );
1683
		}
1684
1685
		if ( isset( $menu_orders[ $previd ] ) ) {
1686
			$menu_orders[ $sorting_id ] = $menu_orders[ $previd ] + 1;
1687
		} elseif ( isset( $menu_orders[ $nextid ] ) ) {
1688
			$menu_orders[ $sorting_id ] = $menu_orders[ $nextid ] - 1;
1689
		} else {
1690
			$menu_orders[ $sorting_id ] = 0;
1691
		}
1692
1693
		$wpdb->update( $wpdb->posts, array( 'menu_order' => $menu_orders[ $sorting_id ] ), array( 'ID' => $sorting_id ) );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
1694
1695
		do_action( 'woocommerce_after_product_ordering', $sorting_id, $menu_orders );
1696
		wp_send_json( $menu_orders );
1697
	}
1698
1699
	/**
1700
	 * Handle a refund via the edit order screen.
1701
	 *
1702
	 * @throws Exception To return errors.
1703
	 */
1704
	public static function refund_line_items() {
1705
		ob_start();
1706
1707
		check_ajax_referer( 'order-item', 'security' );
1708
1709
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
1710
			wp_die( -1 );
1711
		}
1712
1713
		$order_id               = absint( $_POST['order_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1714
		$refund_amount          = wc_format_decimal( sanitize_text_field( wp_unslash( $_POST['refund_amount'] ) ), wc_get_price_decimals() );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1715
		$refunded_amount        = wc_format_decimal( sanitize_text_field( wp_unslash( $_POST['refunded_amount'] ) ), wc_get_price_decimals() );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1716
		$refund_reason          = sanitize_text_field( $_POST['refund_reason'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1717
		$line_item_qtys         = json_decode( sanitize_text_field( wp_unslash( $_POST['line_item_qtys'] ) ), true );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1718
		$line_item_totals       = json_decode( sanitize_text_field( wp_unslash( $_POST['line_item_totals'] ) ), true );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1719
		$line_item_tax_totals   = json_decode( sanitize_text_field( wp_unslash( $_POST['line_item_tax_totals'] ) ), true );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1720
		$api_refund             = 'true' === $_POST['api_refund'];
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1721
		$restock_refunded_items = 'true' === $_POST['restock_refunded_items'];
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1722
		$refund                 = false;
1723
		$response               = array();
1724
1725
		try {
1726
			$order       = wc_get_order( $order_id );
1727
			$order_items = $order->get_items();
0 ignored issues
show
Unused Code introduced by
$order_items is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1728
			$max_refund  = wc_format_decimal( $order->get_total() - $order->get_total_refunded(), wc_get_price_decimals() );
1729
1730
			if ( ! $refund_amount || $max_refund < $refund_amount || 0 > $refund_amount ) {
1731
				throw new exception( __( 'Invalid refund amount', 'woocommerce' ) );
1732
			}
1733
1734
			if ( $refunded_amount !== wc_format_decimal( $order->get_total_refunded(), wc_get_price_decimals() ) ) {
1735
				throw new exception( __( 'Error processing refund. Please try again.', 'woocommerce' ) );
1736
			}
1737
1738
			// Prepare line items which we are refunding.
1739
			$line_items = array();
1740
			$item_ids   = array_unique( array_merge( array_keys( $line_item_qtys, $line_item_totals ) ) );
1741
1742
			foreach ( $item_ids as $item_id ) {
1743
				$line_items[ $item_id ] = array(
1744
					'qty'          => 0,
1745
					'refund_total' => 0,
1746
					'refund_tax'   => array(),
1747
				);
1748
			}
1749
			foreach ( $line_item_qtys as $item_id => $qty ) {
1750
				$line_items[ $item_id ]['qty'] = max( $qty, 0 );
1751
			}
1752
			foreach ( $line_item_totals as $item_id => $total ) {
1753
				$line_items[ $item_id ]['refund_total'] = wc_format_decimal( $total );
1754
			}
1755
			foreach ( $line_item_tax_totals as $item_id => $tax_totals ) {
1756
				$line_items[ $item_id ]['refund_tax'] = array_filter( array_map( 'wc_format_decimal', $tax_totals ) );
1757
			}
1758
1759
			// Create the refund object.
1760
			$refund = wc_create_refund(
1761
				array(
1762
					'amount'         => $refund_amount,
1763
					'reason'         => $refund_reason,
1764
					'order_id'       => $order_id,
1765
					'line_items'     => $line_items,
1766
					'refund_payment' => $api_refund,
1767
					'restock_items'  => $restock_refunded_items,
1768
				)
1769
			);
1770
1771
			if ( is_wp_error( $refund ) ) {
1772
				throw new Exception( $refund->get_error_message() );
1773
			}
1774
1775
			if ( did_action( 'woocommerce_order_fully_refunded' ) ) {
1776
				$response['status'] = 'fully_refunded';
1777
			}
1778
		} catch ( Exception $e ) {
1779
			wp_send_json_error( array( 'error' => $e->getMessage() ) );
1780
		}
1781
1782
		// wp_send_json_success must be outside the try block not to break phpunit tests.
1783
		wp_send_json_success( $response );
1784
	}
1785
1786
	/**
1787
	 * Delete a refund.
1788
	 */
1789
	public static function delete_refund() {
1790
		check_ajax_referer( 'order-item', 'security' );
1791
1792
		if ( ! current_user_can( 'edit_shop_orders' ) ) {
1793
			wp_die( -1 );
1794
		}
1795
1796
		$refund_ids = array_map( 'absint', is_array( $_POST['refund_id'] ) ? $_POST['refund_id'] : array( $_POST['refund_id'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1797
		foreach ( $refund_ids as $refund_id ) {
1798
			if ( $refund_id && 'shop_order_refund' === get_post_type( $refund_id ) ) {
1799
				$refund   = wc_get_order( $refund_id );
1800
				$order_id = $refund->get_parent_id();
1801
				$refund->delete( true );
1802
				do_action( 'woocommerce_refund_deleted', $refund_id, $order_id );
1803
			}
1804
		}
1805
		wp_die();
1806
	}
1807
1808
	/**
1809
	 * Triggered when clicking the rating footer.
1810
	 */
1811
	public static function rated() {
1812
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
1813
			wp_die( -1 );
1814
		}
1815
		update_option( 'woocommerce_admin_footer_text_rated', 1 );
1816
		wp_die();
1817
	}
1818
1819
	/**
1820
	 * Create/Update API key.
1821
	 */
1822
	public static function update_api_key() {
1823
		ob_start();
1824
1825
		global $wpdb;
1826
1827
		check_ajax_referer( 'update-api-key', 'security' );
1828
1829
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
1830
			wp_die( -1 );
1831
		}
1832
1833
		$response = array();
1834
1835
		try {
1836
			if ( empty( $_POST['description'] ) ) {
1837
				throw new Exception( __( 'Description is missing.', 'woocommerce' ) );
1838
			}
1839
			if ( empty( $_POST['user'] ) ) {
1840
				throw new Exception( __( 'User is missing.', 'woocommerce' ) );
1841
			}
1842
			if ( empty( $_POST['permissions'] ) ) {
1843
				throw new Exception( __( 'Permissions is missing.', 'woocommerce' ) );
1844
			}
1845
1846
			$key_id      = absint( $_POST['key_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
1847
			$description = sanitize_text_field( wp_unslash( $_POST['description'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1848
			$permissions = ( in_array( $_POST['permissions'], array( 'read', 'write', 'read_write' ) ) ) ? sanitize_text_field( $_POST['permissions'] ) : 'read';
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1849
			$user_id     = absint( $_POST['user'] );
1850
1851
			// Check if current user can edit other users.
1852
			if ( $user_id && ! current_user_can( 'edit_user', $user_id ) ) {
1853
				if ( get_current_user_id() !== $user_id ) {
1854
					throw new Exception( __( 'You do not have permission to assign API Keys to the selected user.', 'woocommerce' ) );
1855
				}
1856
			}
1857
1858
			if ( 0 < $key_id ) {
1859
				$data = array(
1860
					'user_id'     => $user_id,
1861
					'description' => $description,
1862
					'permissions' => $permissions,
1863
				);
1864
1865
				$wpdb->update(
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
1866
					$wpdb->prefix . 'woocommerce_api_keys',
1867
					$data,
1868
					array( 'key_id' => $key_id ),
1869
					array(
1870
						'%d',
1871
						'%s',
1872
						'%s',
1873
					),
1874
					array( '%d' )
1875
				);
1876
1877
				$response                    = $data;
1878
				$response['consumer_key']    = '';
1879
				$response['consumer_secret'] = '';
1880
				$response['message']         = __( 'API Key updated successfully.', 'woocommerce' );
1881
			} else {
1882
				$consumer_key    = 'ck_' . wc_rand_hash();
1883
				$consumer_secret = 'cs_' . wc_rand_hash();
1884
1885
				$data = array(
1886
					'user_id'         => $user_id,
1887
					'description'     => $description,
1888
					'permissions'     => $permissions,
1889
					'consumer_key'    => wc_api_hash( $consumer_key ),
1890
					'consumer_secret' => $consumer_secret,
1891
					'truncated_key'   => substr( $consumer_key, -7 ),
1892
				);
1893
1894
				$wpdb->insert(
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
1895
					$wpdb->prefix . 'woocommerce_api_keys',
1896
					$data,
1897
					array(
1898
						'%d',
1899
						'%s',
1900
						'%s',
1901
						'%s',
1902
						'%s',
1903
						'%s',
1904
					)
1905
				);
1906
1907
				$key_id                      = $wpdb->insert_id;
1908
				$response                    = $data;
1909
				$response['consumer_key']    = $consumer_key;
1910
				$response['consumer_secret'] = $consumer_secret;
1911
				$response['message']         = __( 'API Key generated successfully. Make sure to copy your new keys now as the secret key will be hidden once you leave this page.', 'woocommerce' );
1912
				$response['revoke_url']      = '<a style="color: #a00; text-decoration: none;" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'revoke-key' => $key_id ), admin_url( 'admin.php?page=wc-settings&tab=advanced&section=keys' ) ), 'revoke' ) ) . '">' . __( 'Revoke key', 'woocommerce' ) . '</a>';
1913
			}
1914
		} catch ( Exception $e ) {
1915
			wp_send_json_error( array( 'message' => $e->getMessage() ) );
1916
		}
1917
1918
		// wp_send_json_success must be outside the try block not to break phpunit tests.
1919
		wp_send_json_success( $response );
1920
	}
1921
1922
	/**
1923
	 * Load variations via AJAX.
1924
	 */
1925
	public static function load_variations() {
1926
		ob_start();
1927
1928
		check_ajax_referer( 'load-variations', 'security' );
1929
1930
		if ( ! current_user_can( 'edit_products' ) || empty( $_POST['product_id'] ) ) {
1931
			wp_die( -1 );
1932
		}
1933
1934
		// Set $post global so its available, like within the admin screens
1935
		global $post;
1936
1937
		$loop           = 0;
1938
		$product_id     = absint( $_POST['product_id'] );
1939
		$post           = get_post( $product_id );
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
1940
		$product_object = wc_get_product( $product_id );
1941
		$per_page       = ! empty( $_POST['per_page'] ) ? absint( $_POST['per_page'] ) : 10;
1942
		$page           = ! empty( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
1943
		$variations     = wc_get_products(
1944
			array(
1945
				'status'  => array( 'private', 'publish' ),
1946
				'type'    => 'variation',
1947
				'parent'  => $product_id,
1948
				'limit'   => $per_page,
1949
				'page'    => $page,
1950
				'orderby' => array(
1951
					'menu_order' => 'ASC',
1952
					'ID'         => 'DESC',
1953
				),
1954
				'return'  => 'objects',
1955
			)
1956
		);
1957
1958
		if ( $variations ) {
1959
			foreach ( $variations as $variation_object ) {
1960
				$variation_id   = $variation_object->get_id();
1961
				$variation      = get_post( $variation_id );
1962
				$variation_data = array_merge( get_post_custom( $variation_id ), wc_get_product_variation_attributes( $variation_id ) ); // kept for BW compatibility.
1963
				include 'admin/meta-boxes/views/html-variation-admin.php';
1964
				$loop++;
1965
			}
1966
		}
1967
		wp_die();
1968
	}
1969
1970
	/**
1971
	 * Save variations via AJAX.
1972
	 */
1973
	public static function save_variations() {
1974
		ob_start();
1975
1976
		check_ajax_referer( 'save-variations', 'security' );
1977
1978
		// Check permissions again and make sure we have what we need
1979 View Code Duplication
		if ( ! current_user_can( 'edit_products' ) || empty( $_POST ) || empty( $_POST['product_id'] ) ) {
1980
			wp_die( -1 );
1981
		}
1982
1983
		$product_id                           = absint( $_POST['product_id'] );
1984
		WC_Admin_Meta_Boxes::$meta_box_errors = array();
1985
		WC_Meta_Box_Product_Data::save_variations( $product_id, get_post( $product_id ) );
1986
1987
		do_action( 'woocommerce_ajax_save_product_variations', $product_id );
1988
1989
		if ( $errors = WC_Admin_Meta_Boxes::$meta_box_errors ) {
1990
			echo '<div class="error notice is-dismissible">';
1991
1992
			foreach ( $errors as $error ) {
1993
				echo '<p>' . wp_kses_post( $error ) . '</p>';
1994
			}
1995
1996
			echo '<button type="button" class="notice-dismiss"><span class="screen-reader-text">' . __( 'Dismiss this notice.', 'woocommerce' ) . '</span></button>';
1997
			echo '</div>';
1998
1999
			delete_option( 'woocommerce_meta_box_errors' );
2000
		}
2001
2002
		wp_die();
2003
	}
2004
2005
	/**
2006
	 * Bulk action - Toggle Enabled.
2007
	 *
2008
	 * @param array $variations
2009
	 * @param array $data
2010
	 *
2011
	 * @used-by bulk_edit_variations
2012
	 */
2013
	private static function variation_bulk_action_toggle_enabled( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2014
		foreach ( $variations as $variation_id ) {
2015
			$variation = wc_get_product( $variation_id );
2016
			$variation->set_status( 'private' === $variation->get_status( 'edit' ) ? 'publish' : 'private' );
2017
			$variation->save();
2018
		}
2019
	}
2020
2021
	/**
2022
	 * Bulk action - Toggle Downloadable Checkbox.
2023
	 *
2024
	 * @param array $variations
2025
	 * @param array $data
2026
	 *
2027
	 * @used-by bulk_edit_variations
2028
	 */
2029
	private static function variation_bulk_action_toggle_downloadable( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2030
		self::variation_bulk_toggle( $variations, 'downloadable' );
2031
	}
2032
2033
	/**
2034
	 * Bulk action - Toggle Virtual Checkbox.
2035
	 *
2036
	 * @param array $variations
2037
	 * @param array $data
2038
	 *
2039
	 * @used-by bulk_edit_variations
2040
	 */
2041
	private static function variation_bulk_action_toggle_virtual( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2042
		self::variation_bulk_toggle( $variations, 'virtual' );
2043
	}
2044
2045
	/**
2046
	 * Bulk action - Toggle Manage Stock Checkbox.
2047
	 *
2048
	 * @param array $variations
2049
	 * @param array $data
2050
	 *
2051
	 * @used-by bulk_edit_variations
2052
	 */
2053
	private static function variation_bulk_action_toggle_manage_stock( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2054
		self::variation_bulk_toggle( $variations, 'manage_stock' );
2055
	}
2056
2057
	/**
2058
	 * Bulk action - Set Regular Prices.
2059
	 *
2060
	 * @param array $variations
2061
	 * @param array $data
2062
	 *
2063
	 * @used-by bulk_edit_variations
2064
	 */
2065
	private static function variation_bulk_action_variable_regular_price( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2066
		self::variation_bulk_set( $variations, 'regular_price', $data['value'] );
2067
	}
2068
2069
	/**
2070
	 * Bulk action - Set Sale Prices.
2071
	 *
2072
	 * @param array $variations
2073
	 * @param array $data
2074
	 *
2075
	 * @used-by bulk_edit_variations
2076
	 */
2077
	private static function variation_bulk_action_variable_sale_price( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2078
		self::variation_bulk_set( $variations, 'sale_price', $data['value'] );
2079
	}
2080
2081
	/**
2082
	 * Bulk action - Set Stock Status as In Stock.
2083
	 *
2084
	 * @param array $variations
2085
	 * @param array $data
2086
	 *
2087
	 * @used-by bulk_edit_variations
2088
	 */
2089
	private static function variation_bulk_action_variable_stock_status_instock( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2090
		self::variation_bulk_set( $variations, 'stock_status', 'instock' );
2091
	}
2092
2093
	/**
2094
	 * Bulk action - Set Stock Status as Out of Stock.
2095
	 *
2096
	 * @param array $variations
2097
	 * @param array $data
2098
	 *
2099
	 * @used-by bulk_edit_variations
2100
	 */
2101
	private static function variation_bulk_action_variable_stock_status_outofstock( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2102
		self::variation_bulk_set( $variations, 'stock_status', 'outofstock' );
2103
	}
2104
2105
	/**
2106
	 * Bulk action - Set Stock Status as On Backorder.
2107
	 *
2108
	 * @param array $variations
2109
	 * @param array $data
2110
	 *
2111
	 * @used-by bulk_edit_variations
2112
	 */
2113
	private static function variation_bulk_action_variable_stock_status_onbackorder( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2114
		self::variation_bulk_set( $variations, 'stock_status', 'onbackorder' );
2115
	}
2116
2117
	/**
2118
	 * Bulk action - Set Stock.
2119
	 *
2120
	 * @param array $variations
2121
	 * @param array $data
2122
	 *
2123
	 * @used-by bulk_edit_variations
2124
	 */
2125
	private static function variation_bulk_action_variable_stock( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2126
		if ( ! isset( $data['value'] ) ) {
2127
			return;
2128
		}
2129
2130
		$quantity = wc_stock_amount( wc_clean( $data['value'] ) );
0 ignored issues
show
Documentation introduced by
wc_clean($data['value']) is of type string|array, but the function expects a integer|double.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
2131
2132
		foreach ( $variations as $variation_id ) {
2133
			$variation = wc_get_product( $variation_id );
2134
			if ( $variation->managing_stock() ) {
2135
				$variation->set_stock_quantity( $quantity );
2136
			} else {
2137
				$variation->set_stock_quantity( null );
2138
			}
2139
			$variation->save();
2140
		}
2141
	}
2142
2143
	/**
2144
	 * Bulk action - Set Weight.
2145
	 *
2146
	 * @param array $variations
2147
	 * @param array $data
2148
	 *
2149
	 * @used-by bulk_edit_variations
2150
	 */
2151
	private static function variation_bulk_action_variable_weight( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2152
		self::variation_bulk_set( $variations, 'weight', $data['value'] );
2153
	}
2154
2155
	/**
2156
	 * Bulk action - Set Length.
2157
	 *
2158
	 * @param array $variations
2159
	 * @param array $data
2160
	 *
2161
	 * @used-by bulk_edit_variations
2162
	 */
2163
	private static function variation_bulk_action_variable_length( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2164
		self::variation_bulk_set( $variations, 'length', $data['value'] );
2165
	}
2166
2167
	/**
2168
	 * Bulk action - Set Width.
2169
	 *
2170
	 * @param array $variations
2171
	 * @param array $data
2172
	 *
2173
	 * @used-by bulk_edit_variations
2174
	 */
2175
	private static function variation_bulk_action_variable_width( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2176
		self::variation_bulk_set( $variations, 'width', $data['value'] );
2177
	}
2178
2179
	/**
2180
	 * Bulk action - Set Height.
2181
	 *
2182
	 * @param array $variations
2183
	 * @param array $data
2184
	 *
2185
	 * @used-by bulk_edit_variations
2186
	 */
2187
	private static function variation_bulk_action_variable_height( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2188
		self::variation_bulk_set( $variations, 'height', $data['value'] );
2189
	}
2190
2191
	/**
2192
	 * Bulk action - Set Download Limit.
2193
	 *
2194
	 * @param array $variations
2195
	 * @param array $data
2196
	 *
2197
	 * @used-by bulk_edit_variations
2198
	 */
2199
	private static function variation_bulk_action_variable_download_limit( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2200
		self::variation_bulk_set( $variations, 'download_limit', $data['value'] );
2201
	}
2202
2203
	/**
2204
	 * Bulk action - Set Download Expiry.
2205
	 *
2206
	 * @param array $variations
2207
	 * @param array $data
2208
	 *
2209
	 * @used-by bulk_edit_variations
2210
	 */
2211
	private static function variation_bulk_action_variable_download_expiry( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2212
		self::variation_bulk_set( $variations, 'download_expiry', $data['value'] );
2213
	}
2214
2215
	/**
2216
	 * Bulk action - Delete all.
2217
	 *
2218
	 * @param array $variations
2219
	 * @param array $data
2220
	 *
2221
	 * @used-by bulk_edit_variations
2222
	 */
2223
	private static function variation_bulk_action_delete_all( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2224
		if ( isset( $data['allowed'] ) && 'true' === $data['allowed'] ) {
2225
			foreach ( $variations as $variation_id ) {
2226
				$variation = wc_get_product( $variation_id );
2227
				$variation->delete( true );
2228
			}
2229
		}
2230
	}
2231
2232
	/**
2233
	 * Bulk action - Sale Schedule.
2234
	 *
2235
	 * @param array $variations
2236
	 * @param array $data
2237
	 *
2238
	 * @used-by bulk_edit_variations
2239
	 */
2240
	private static function variation_bulk_action_variable_sale_schedule( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2241
		if ( ! isset( $data['date_from'] ) && ! isset( $data['date_to'] ) ) {
2242
			return;
2243
		}
2244
2245
		foreach ( $variations as $variation_id ) {
2246
			$variation = wc_get_product( $variation_id );
2247
2248
			if ( 'false' !== $data['date_from'] ) {
2249
				$variation->set_date_on_sale_from( wc_clean( $data['date_from'] ) );
2250
			}
2251
2252
			if ( 'false' !== $data['date_to'] ) {
2253
				$variation->set_date_on_sale_to( wc_clean( $data['date_to'] ) );
2254
			}
2255
2256
			$variation->save();
2257
		}
2258
	}
2259
2260
	/**
2261
	 * Bulk action - Increase Regular Prices.
2262
	 *
2263
	 * @param array $variations
2264
	 * @param array $data
2265
	 *
2266
	 * @used-by bulk_edit_variations
2267
	 */
2268
	private static function variation_bulk_action_variable_regular_price_increase( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2269
		self::variation_bulk_adjust_price( $variations, 'regular_price', '+', wc_clean( $data['value'] ) );
0 ignored issues
show
Bug introduced by
It seems like wc_clean($data['value']) targeting wc_clean() can also be of type array; however, WC_AJAX::variation_bulk_adjust_price() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
2270
	}
2271
2272
	/**
2273
	 * Bulk action - Decrease Regular Prices.
2274
	 *
2275
	 * @param array $variations
2276
	 * @param array $data
2277
	 *
2278
	 * @used-by bulk_edit_variations
2279
	 */
2280
	private static function variation_bulk_action_variable_regular_price_decrease( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2281
		self::variation_bulk_adjust_price( $variations, 'regular_price', '-', wc_clean( $data['value'] ) );
0 ignored issues
show
Bug introduced by
It seems like wc_clean($data['value']) targeting wc_clean() can also be of type array; however, WC_AJAX::variation_bulk_adjust_price() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
2282
	}
2283
2284
	/**
2285
	 * Bulk action - Increase Sale Prices.
2286
	 *
2287
	 * @param array $variations
2288
	 * @param array $data
2289
	 *
2290
	 * @used-by bulk_edit_variations
2291
	 */
2292
	private static function variation_bulk_action_variable_sale_price_increase( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2293
		self::variation_bulk_adjust_price( $variations, 'sale_price', '+', wc_clean( $data['value'] ) );
0 ignored issues
show
Bug introduced by
It seems like wc_clean($data['value']) targeting wc_clean() can also be of type array; however, WC_AJAX::variation_bulk_adjust_price() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
2294
	}
2295
2296
	/**
2297
	 * Bulk action - Decrease Sale Prices.
2298
	 *
2299
	 * @param array $variations
2300
	 * @param array $data
2301
	 *
2302
	 * @used-by bulk_edit_variations
2303
	 */
2304
	private static function variation_bulk_action_variable_sale_price_decrease( $variations, $data ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
2305
		self::variation_bulk_adjust_price( $variations, 'sale_price', '-', wc_clean( $data['value'] ) );
0 ignored issues
show
Bug introduced by
It seems like wc_clean($data['value']) targeting wc_clean() can also be of type array; however, WC_AJAX::variation_bulk_adjust_price() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
2306
	}
2307
2308
	/**
2309
	 * Bulk action - Set Price.
2310
	 *
2311
	 * @param array  $variations
2312
	 * @param string $operator + or -
2313
	 * @param string $field price being adjusted _regular_price or _sale_price
2314
	 * @param string $value Price or Percent
2315
	 *
2316
	 * @used-by bulk_edit_variations
2317
	 */
2318
	private static function variation_bulk_adjust_price( $variations, $field, $operator, $value ) {
2319
		foreach ( $variations as $variation_id ) {
2320
			$variation   = wc_get_product( $variation_id );
2321
			$field_value = $variation->{"get_$field"}( 'edit' );
2322
2323
			if ( '%' === substr( $value, -1 ) ) {
2324
				$percent      = wc_format_decimal( substr( $value, 0, -1 ) );
2325
				$field_value += round( ( $field_value / 100 ) * $percent, wc_get_price_decimals() ) * "{$operator}1";
2326
			} else {
2327
				$field_value += $value * "{$operator}1";
2328
			}
2329
2330
			$variation->{"set_$field"}( $field_value );
2331
			$variation->save();
2332
		}
2333
	}
2334
2335
	/**
2336
	 * Bulk set convenience function.
2337
	 *
2338
	 * @param array  $variations
2339
	 * @param string $field
2340
	 * @param string $value
2341
	 */
2342
	private static function variation_bulk_set( $variations, $field, $value ) {
2343
		foreach ( $variations as $variation_id ) {
2344
			$variation = wc_get_product( $variation_id );
2345
			$variation->{ "set_$field" }( wc_clean( $value ) );
2346
			$variation->save();
2347
		}
2348
	}
2349
2350
	/**
2351
	 * Bulk toggle convenience function.
2352
	 *
2353
	 * @param array  $variations
2354
	 * @param string $field
2355
	 */
2356
	private static function variation_bulk_toggle( $variations, $field ) {
2357
		foreach ( $variations as $variation_id ) {
2358
			$variation  = wc_get_product( $variation_id );
2359
			$prev_value = $variation->{ "get_$field" }( 'edit' );
2360
			$variation->{ "set_$field" }( ! $prev_value );
2361
			$variation->save();
2362
		}
2363
	}
2364
2365
	/**
2366
	 * Bulk edit variations via AJAX.
2367
	 *
2368
	 * @uses WC_AJAX::variation_bulk_set()
2369
	 * @uses WC_AJAX::variation_bulk_adjust_price()
2370
	 * @uses WC_AJAX::variation_bulk_action_variable_sale_price_decrease()
2371
	 * @uses WC_AJAX::variation_bulk_action_variable_sale_price_increase()
2372
	 * @uses WC_AJAX::variation_bulk_action_variable_regular_price_decrease()
2373
	 * @uses WC_AJAX::variation_bulk_action_variable_regular_price_increase()
2374
	 * @uses WC_AJAX::variation_bulk_action_variable_sale_schedule()
2375
	 * @uses WC_AJAX::variation_bulk_action_delete_all()
2376
	 * @uses WC_AJAX::variation_bulk_action_variable_download_expiry()
2377
	 * @uses WC_AJAX::variation_bulk_action_variable_download_limit()
2378
	 * @uses WC_AJAX::variation_bulk_action_variable_height()
2379
	 * @uses WC_AJAX::variation_bulk_action_variable_width()
2380
	 * @uses WC_AJAX::variation_bulk_action_variable_length()
2381
	 * @uses WC_AJAX::variation_bulk_action_variable_weight()
2382
	 * @uses WC_AJAX::variation_bulk_action_variable_stock()
2383
	 * @uses WC_AJAX::variation_bulk_action_variable_sale_price()
2384
	 * @uses WC_AJAX::variation_bulk_action_variable_regular_price()
2385
	 * @uses WC_AJAX::variation_bulk_action_toggle_manage_stock()
2386
	 * @uses WC_AJAX::variation_bulk_action_toggle_virtual()
2387
	 * @uses WC_AJAX::variation_bulk_action_toggle_downloadable()
2388
	 * @uses WC_AJAX::variation_bulk_action_toggle_enabled
2389
	 */
2390
	public static function bulk_edit_variations() {
2391
		ob_start();
2392
2393
		check_ajax_referer( 'bulk-edit-variations', 'security' );
2394
2395
		// Check permissions again and make sure we have what we need
2396 View Code Duplication
		if ( ! current_user_can( 'edit_products' ) || empty( $_POST['product_id'] ) || empty( $_POST['bulk_action'] ) ) {
2397
			wp_die( -1 );
2398
		}
2399
2400
		$product_id  = absint( $_POST['product_id'] );
2401
		$bulk_action = wc_clean( $_POST['bulk_action'] );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2402
		$data        = ! empty( $_POST['data'] ) ? array_map( 'wc_clean', $_POST['data'] ) : array();
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2403
		$variations  = array();
2404
2405
		if ( apply_filters( 'woocommerce_bulk_edit_variations_need_children', true ) ) {
2406
			$variations = get_posts(
2407
				array(
2408
					'post_parent'    => $product_id,
2409
					'posts_per_page' => -1,
0 ignored issues
show
introduced by
Disabling pagination is prohibited in VIP context, do not set posts_per_page to -1 ever.
Loading history...
2410
					'post_type'      => 'product_variation',
2411
					'fields'         => 'ids',
2412
					'post_status'    => array( 'publish', 'private' ),
2413
				)
2414
			);
2415
		}
2416
2417
		if ( method_exists( __CLASS__, "variation_bulk_action_$bulk_action" ) ) {
2418
			call_user_func( array( __CLASS__, "variation_bulk_action_$bulk_action" ), $variations, $data );
2419
		} else {
2420
			do_action( 'woocommerce_bulk_edit_variations_default', $bulk_action, $data, $product_id, $variations );
2421
		}
2422
2423
		do_action( 'woocommerce_bulk_edit_variations', $bulk_action, $data, $product_id, $variations );
2424
		WC_Product_Variable::sync( $product_id );
2425
		wc_delete_product_transients( $product_id );
2426
		wp_die();
2427
	}
2428
2429
	/**
2430
	 * Handle submissions from assets/js/settings-views-html-settings-tax.js Backbone model.
2431
	 */
2432
	public static function tax_rates_save_changes() {
2433
		if ( ! isset( $_POST['wc_tax_nonce'], $_POST['changes'] ) ) {
2434
			wp_send_json_error( 'missing_fields' );
2435
			wp_die();
2436
		}
2437
2438
		$current_class = ! empty( $_POST['current_class'] ) ? $_POST['current_class'] : ''; // This is sanitized seven lines later.
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2439
2440
		if ( ! wp_verify_nonce( $_POST['wc_tax_nonce'], 'wc_tax_nonce-class:' . $current_class ) ) {
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2441
			wp_send_json_error( 'bad_nonce' );
2442
			wp_die();
2443
		}
2444
2445
		$current_class = WC_Tax::format_tax_rate_class( $current_class );
2446
2447
		// Check User Caps
2448
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
2449
			wp_send_json_error( 'missing_capabilities' );
2450
			wp_die();
2451
		}
2452
2453
		$changes = stripslashes_deep( $_POST['changes'] );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2454
		foreach ( $changes as $tax_rate_id => $data ) {
2455
			if ( isset( $data['deleted'] ) ) {
2456
				if ( isset( $data['newRow'] ) ) {
2457
					// So the user added and deleted a new row.
2458
					// That's fine, it's not in the database anyways. NEXT!
2459
					continue;
2460
				}
2461
				WC_Tax::_delete_tax_rate( $tax_rate_id );
2462
			}
2463
2464
			$tax_rate = array_intersect_key(
2465
				$data, array(
2466
					'tax_rate_country'  => 1,
2467
					'tax_rate_state'    => 1,
2468
					'tax_rate'          => 1,
2469
					'tax_rate_name'     => 1,
2470
					'tax_rate_priority' => 1,
2471
					'tax_rate_compound' => 1,
2472
					'tax_rate_shipping' => 1,
2473
					'tax_rate_order'    => 1,
2474
				)
2475
			);
2476
2477
			if ( isset( $tax_rate['tax_rate'] ) ) {
2478
				$tax_rate['tax_rate'] = wc_format_decimal( $tax_rate['tax_rate'] );
2479
			}
2480
2481
			if ( isset( $data['newRow'] ) ) {
2482
				$tax_rate['tax_rate_class'] = $current_class;
2483
				$tax_rate_id                = WC_Tax::_insert_tax_rate( $tax_rate );
2484
			} elseif ( ! empty( $tax_rate ) ) {
2485
				WC_Tax::_update_tax_rate( $tax_rate_id, $tax_rate );
2486
			}
2487
2488
			if ( isset( $data['postcode'] ) ) {
2489
				$postcode = array_map( 'wc_clean', $data['postcode'] );
2490
				$postcode = array_map( 'wc_normalize_postcode', $postcode );
2491
				WC_Tax::_update_tax_rate_postcodes( $tax_rate_id, $postcode );
0 ignored issues
show
Documentation introduced by
$postcode is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
2492
			}
2493
			if ( isset( $data['city'] ) ) {
2494
				WC_Tax::_update_tax_rate_cities( $tax_rate_id, array_map( 'wc_clean', array_map( 'wp_unslash', $data['city'] ) ) );
0 ignored issues
show
Documentation introduced by
array_map('wc_clean', ar...slash', $data['city'])) is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
2495
			}
2496
		}
2497
2498
		WC_Cache_Helper::incr_cache_prefix( 'taxes' );
2499
		WC_Cache_Helper::get_transient_version( 'shipping', true );
2500
2501
		wp_send_json_success(
2502
			array(
2503
				'rates' => WC_Tax::get_rates_for_tax_class( $current_class ),
2504
			)
2505
		);
2506
	}
2507
2508
	/**
2509
	 * Handle submissions from assets/js/wc-shipping-zones.js Backbone model.
2510
	 */
2511
	public static function shipping_zones_save_changes() {
2512
		if ( ! isset( $_POST['wc_shipping_zones_nonce'], $_POST['changes'] ) ) {
2513
			wp_send_json_error( 'missing_fields' );
2514
			wp_die();
2515
		}
2516
2517
		if ( ! wp_verify_nonce( $_POST['wc_shipping_zones_nonce'], 'wc_shipping_zones_nonce' ) ) {
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2518
			wp_send_json_error( 'bad_nonce' );
2519
			wp_die();
2520
		}
2521
2522
		// Check User Caps
2523
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
2524
			wp_send_json_error( 'missing_capabilities' );
2525
			wp_die();
2526
		}
2527
2528
		$changes = $_POST['changes'];
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2529
		foreach ( $changes as $zone_id => $data ) {
2530
			if ( isset( $data['deleted'] ) ) {
2531
				if ( isset( $data['newRow'] ) ) {
2532
					// So the user added and deleted a new row.
2533
					// That's fine, it's not in the database anyways. NEXT!
2534
					continue;
2535
				}
2536
				WC_Shipping_Zones::delete_zone( $zone_id );
2537
				continue;
2538
			}
2539
2540
			$zone_data = array_intersect_key(
2541
				$data, array(
2542
					'zone_id'    => 1,
2543
					'zone_order' => 1,
2544
				)
2545
			);
2546
2547
			if ( isset( $zone_data['zone_id'] ) ) {
2548
				$zone = new WC_Shipping_Zone( $zone_data['zone_id'] );
2549
2550
				if ( isset( $zone_data['zone_order'] ) ) {
2551
					$zone->set_zone_order( $zone_data['zone_order'] );
2552
				}
2553
2554
				$zone->save();
2555
			}
2556
		}
2557
2558
		wp_send_json_success(
2559
			array(
2560
				'zones' => WC_Shipping_Zones::get_zones( 'json' ),
2561
			)
2562
		);
2563
	}
2564
2565
	/**
2566
	 * Handle submissions from assets/js/wc-shipping-zone-methods.js Backbone model.
2567
	 */
2568
	public static function shipping_zone_add_method() {
2569 View Code Duplication
		if ( ! isset( $_POST['wc_shipping_zones_nonce'], $_POST['zone_id'], $_POST['method_id'] ) ) {
2570
			wp_send_json_error( 'missing_fields' );
2571
			wp_die();
2572
		}
2573
2574
		if ( ! wp_verify_nonce( $_POST['wc_shipping_zones_nonce'], 'wc_shipping_zones_nonce' ) ) {
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2575
			wp_send_json_error( 'bad_nonce' );
2576
			wp_die();
2577
		}
2578
2579
		// Check User Caps
2580
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
2581
			wp_send_json_error( 'missing_capabilities' );
2582
			wp_die();
2583
		}
2584
2585
		$zone_id     = wc_clean( $_POST['zone_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2586
		$zone        = new WC_Shipping_Zone( $zone_id );
2587
		$instance_id = $zone->add_shipping_method( wc_clean( $_POST['method_id'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2588
2589
		wp_send_json_success(
2590
			array(
2591
				'instance_id' => $instance_id,
2592
				'zone_id'     => $zone->get_id(),
2593
				'zone_name'   => $zone->get_zone_name(),
2594
				'methods'     => $zone->get_shipping_methods( false, 'json' ),
2595
			)
2596
		);
2597
	}
2598
2599
	/**
2600
	 * Handle submissions from assets/js/wc-shipping-zone-methods.js Backbone model.
2601
	 */
2602
	public static function shipping_zone_methods_save_changes() {
2603 View Code Duplication
		if ( ! isset( $_POST['wc_shipping_zones_nonce'], $_POST['zone_id'], $_POST['changes'] ) ) {
2604
			wp_send_json_error( 'missing_fields' );
2605
			wp_die();
2606
		}
2607
2608
		if ( ! wp_verify_nonce( $_POST['wc_shipping_zones_nonce'], 'wc_shipping_zones_nonce' ) ) {
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2609
			wp_send_json_error( 'bad_nonce' );
2610
			wp_die();
2611
		}
2612
2613
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
2614
			wp_send_json_error( 'missing_capabilities' );
2615
			wp_die();
2616
		}
2617
2618
		global $wpdb;
2619
2620
		$zone_id = wc_clean( $_POST['zone_id'] );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2621
		$zone    = new WC_Shipping_Zone( $zone_id );
2622
		$changes = $_POST['changes'];
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2623
2624
		if ( isset( $changes['zone_name'] ) ) {
2625
			$zone->set_zone_name( wc_clean( $changes['zone_name'] ) );
2626
		}
2627
2628
		if ( isset( $changes['zone_locations'] ) ) {
2629
			$zone->clear_locations( array( 'state', 'country', 'continent' ) );
2630
			$locations = array_filter( array_map( 'wc_clean', (array) $changes['zone_locations'] ) );
2631
			foreach ( $locations as $location ) {
2632
				// Each posted location will be in the format type:code
2633
				$location_parts = explode( ':', $location );
2634
				switch ( $location_parts[0] ) {
2635
					case 'state':
2636
						$zone->add_location( $location_parts[1] . ':' . $location_parts[2], 'state' );
2637
						break;
2638
					case 'country':
2639
						$zone->add_location( $location_parts[1], 'country' );
2640
						break;
2641
					case 'continent':
2642
						$zone->add_location( $location_parts[1], 'continent' );
2643
						break;
2644
				}
2645
			}
2646
		}
2647
2648
		if ( isset( $changes['zone_postcodes'] ) ) {
2649
			$zone->clear_locations( 'postcode' );
2650
			$postcodes = array_filter( array_map( 'strtoupper', array_map( 'wc_clean', explode( "\n", $changes['zone_postcodes'] ) ) ) );
2651
			foreach ( $postcodes as $postcode ) {
2652
				$zone->add_location( $postcode, 'postcode' );
2653
			}
2654
		}
2655
2656
		if ( isset( $changes['methods'] ) ) {
2657
			foreach ( $changes['methods'] as $instance_id => $data ) {
2658
				$method_id = $wpdb->get_var( $wpdb->prepare( "SELECT method_id FROM {$wpdb->prefix}woocommerce_shipping_zone_methods WHERE instance_id = %d", $instance_id ) );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
introduced by
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
2659
2660
				if ( isset( $data['deleted'] ) ) {
2661
					$shipping_method = WC_Shipping_Zones::get_shipping_method( $instance_id );
2662
					$option_key      = $shipping_method->get_instance_option_key();
2663
					if ( $wpdb->delete( "{$wpdb->prefix}woocommerce_shipping_zone_methods", array( 'instance_id' => $instance_id ) ) ) {
2664
						delete_option( $option_key );
2665
						do_action( 'woocommerce_shipping_zone_method_deleted', $instance_id, $method_id, $zone_id );
2666
					}
2667
					continue;
2668
				}
2669
2670
				$method_data = array_intersect_key(
2671
					$data, array(
2672
						'method_order' => 1,
2673
						'enabled'      => 1,
2674
					)
2675
				);
2676
2677
				if ( isset( $method_data['method_order'] ) ) {
2678
					$wpdb->update( "{$wpdb->prefix}woocommerce_shipping_zone_methods", array( 'method_order' => absint( $method_data['method_order'] ) ), array( 'instance_id' => absint( $instance_id ) ) );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
2679
				}
2680
2681
				if ( isset( $method_data['enabled'] ) ) {
2682
					$is_enabled = absint( 'yes' === $method_data['enabled'] );
2683
					if ( $wpdb->update( "{$wpdb->prefix}woocommerce_shipping_zone_methods", array( 'is_enabled' => $is_enabled ), array( 'instance_id' => absint( $instance_id ) ) ) ) {
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
2684
						do_action( 'woocommerce_shipping_zone_method_status_toggled', $instance_id, $method_id, $zone_id, $is_enabled );
2685
					}
2686
				}
2687
			}
2688
		}
2689
2690
		$zone->save();
2691
2692
		wp_send_json_success(
2693
			array(
2694
				'zone_id'   => $zone->get_id(),
2695
				'zone_name' => $zone->get_zone_name(),
2696
				'methods'   => $zone->get_shipping_methods( false, 'json' ),
2697
			)
2698
		);
2699
	}
2700
2701
	/**
2702
	 * Save method settings
2703
	 */
2704
	public static function shipping_zone_methods_save_settings() {
2705
		if ( ! isset( $_POST['wc_shipping_zones_nonce'], $_POST['instance_id'], $_POST['data'] ) ) {
2706
			wp_send_json_error( 'missing_fields' );
2707
			wp_die();
2708
		}
2709
2710
		if ( ! wp_verify_nonce( $_POST['wc_shipping_zones_nonce'], 'wc_shipping_zones_nonce' ) ) {
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2711
			wp_send_json_error( 'bad_nonce' );
2712
			wp_die();
2713
		}
2714
2715
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
2716
			wp_send_json_error( 'missing_capabilities' );
2717
			wp_die();
2718
		}
2719
2720
		$instance_id     = absint( $_POST['instance_id'] );
2721
		$zone            = WC_Shipping_Zones::get_zone_by( 'instance_id', $instance_id );
2722
		$shipping_method = WC_Shipping_Zones::get_shipping_method( $instance_id );
2723
		$shipping_method->set_post_data( $_POST['data'] );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2724
		$shipping_method->process_admin_options();
2725
2726
		WC_Cache_Helper::get_transient_version( 'shipping', true );
2727
2728
		wp_send_json_success(
2729
			array(
2730
				'zone_id'   => $zone->get_id(),
2731
				'zone_name' => $zone->get_zone_name(),
2732
				'methods'   => $zone->get_shipping_methods( false, 'json' ),
2733
				'errors'    => $shipping_method->get_errors(),
2734
			)
2735
		);
2736
	}
2737
2738
	/**
2739
	 * Handle submissions from assets/js/wc-shipping-classes.js Backbone model.
2740
	 */
2741
	public static function shipping_classes_save_changes() {
2742
		if ( ! isset( $_POST['wc_shipping_classes_nonce'], $_POST['changes'] ) ) {
2743
			wp_send_json_error( 'missing_fields' );
2744
			wp_die();
2745
		}
2746
2747
		if ( ! wp_verify_nonce( $_POST['wc_shipping_classes_nonce'], 'wc_shipping_classes_nonce' ) ) {
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2748
			wp_send_json_error( 'bad_nonce' );
2749
			wp_die();
2750
		}
2751
2752
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
2753
			wp_send_json_error( 'missing_capabilities' );
2754
			wp_die();
2755
		}
2756
2757
		$changes = $_POST['changes'];
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2758
2759
		foreach ( $changes as $term_id => $data ) {
2760
			$term_id = absint( $term_id );
2761
2762
			if ( isset( $data['deleted'] ) ) {
2763
				if ( isset( $data['newRow'] ) ) {
2764
					// So the user added and deleted a new row.
2765
					// That's fine, it's not in the database anyways. NEXT!
2766
					continue;
2767
				}
2768
				wp_delete_term( $term_id, 'product_shipping_class' );
2769
				continue;
2770
			}
2771
2772
			$update_args = array();
2773
2774
			if ( isset( $data['name'] ) ) {
2775
				$update_args['name'] = wc_clean( $data['name'] );
2776
			}
2777
2778
			if ( isset( $data['slug'] ) ) {
2779
				$update_args['slug'] = wc_clean( $data['slug'] );
2780
			}
2781
2782
			if ( isset( $data['description'] ) ) {
2783
				$update_args['description'] = wc_clean( $data['description'] );
2784
			}
2785
2786
			if ( isset( $data['newRow'] ) ) {
2787
				$update_args = array_filter( $update_args );
2788
				if ( empty( $update_args['name'] ) ) {
2789
					continue;
2790
				}
2791
				$inserted_term = wp_insert_term( $update_args['name'], 'product_shipping_class', $update_args );
2792
				$term_id       = is_wp_error( $inserted_term ) ? 0 : $inserted_term['term_id'];
2793
			} else {
2794
				wp_update_term( $term_id, 'product_shipping_class', $update_args );
2795
			}
2796
2797
			do_action( 'woocommerce_shipping_classes_save_class', $term_id, $data );
2798
		}
2799
2800
		$wc_shipping = WC_Shipping::instance();
2801
2802
		wp_send_json_success(
2803
			array(
2804
				'shipping_classes' => $wc_shipping->get_shipping_classes(),
2805
			)
2806
		);
2807
	}
2808
2809
	/**
2810
	 * Toggle payment gateway on or off via AJAX.
2811
	 *
2812
	 * @since 3.4.0
2813
	 */
2814
	public static function toggle_gateway_enabled() {
2815
		if ( current_user_can( 'manage_woocommerce' ) && check_ajax_referer( 'woocommerce-toggle-payment-gateway-enabled', 'security' ) ) {
2816
			// Load gateways.
2817
			$payment_gateways = WC()->payment_gateways->payment_gateways();
2818
2819
			// Get posted gateway.
2820
			$gateway_id = wc_clean( wp_unslash( $_POST['gateway_id'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
2821
2822
			foreach ( $payment_gateways as $gateway ) {
2823
				if ( ! in_array( $gateway_id, array( $gateway->id, sanitize_title( get_class( $gateway ) ) ), true ) ) {
2824
					continue;
2825
				}
2826
				$enabled = $gateway->get_option( 'enabled', 'no' );
2827
2828
				if ( ! wc_string_to_bool( $enabled ) ) {
2829
					if ( $gateway->needs_setup() ) {
2830
						wp_send_json_error( 'needs_setup' );
2831
						wp_die();
2832
					} else {
2833
						$gateway->update_option( 'enabled', 'yes' );
2834
					}
2835
				} else {
2836
					// Disable the gateway.
2837
					$gateway->update_option( 'enabled', 'no' );
2838
				}
2839
2840
				wp_send_json_success( ! wc_string_to_bool( $enabled ) );
2841
				wp_die();
2842
			}
2843
		}
2844
2845
		wp_send_json_error( 'invalid_gateway_id' );
2846
		wp_die();
2847
	}
2848
}
2849
2850
WC_AJAX::init();
2851