Completed
Push — master ( fb5f9c...377d79 )
by Mike
64:31 queued 55:52
created

set_default_payment_method_action()   B

Complexity

Conditions 6
Paths 3

Size

Total Lines 21

Duplication

Lines 21
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
nc 3
nop 0
dl 21
loc 21
ccs 0
cts 10
cp 0
crap 42
rs 8.9617
c 0
b 0
f 0
1
<?php
2
/**
3
 * Handle frontend forms.
4
 *
5
 * @package WooCommerce/Classes/
6
 */
7
8
defined( 'ABSPATH' ) || exit;
9
10
/**
11
 * WC_Form_Handler class.
12
 */
13
class WC_Form_Handler {
14
15
	/**
16
	 * Hook in methods.
17
	 */
18
	public static function init() {
19
		add_action( 'template_redirect', array( __CLASS__, 'redirect_reset_password_link' ) );
20
		add_action( 'template_redirect', array( __CLASS__, 'save_address' ) );
21
		add_action( 'template_redirect', array( __CLASS__, 'save_account_details' ) );
22
		add_action( 'wp_loaded', array( __CLASS__, 'checkout_action' ), 20 );
23
		add_action( 'wp_loaded', array( __CLASS__, 'process_login' ), 20 );
24
		add_action( 'wp_loaded', array( __CLASS__, 'process_registration' ), 20 );
25
		add_action( 'wp_loaded', array( __CLASS__, 'process_lost_password' ), 20 );
26
		add_action( 'wp_loaded', array( __CLASS__, 'process_reset_password' ), 20 );
27
		add_action( 'wp_loaded', array( __CLASS__, 'cancel_order' ), 20 );
28
		add_action( 'wp_loaded', array( __CLASS__, 'update_cart_action' ), 20 );
29
		add_action( 'wp_loaded', array( __CLASS__, 'add_to_cart_action' ), 20 );
30
31
		// May need $wp global to access query vars.
32
		add_action( 'wp', array( __CLASS__, 'pay_action' ), 20 );
33
		add_action( 'wp', array( __CLASS__, 'add_payment_method_action' ), 20 );
34
		add_action( 'wp', array( __CLASS__, 'delete_payment_method_action' ), 20 );
35
		add_action( 'wp', array( __CLASS__, 'set_default_payment_method_action' ), 20 );
36
	}
37
38
	/**
39
	 * Remove key and user ID (or user login, as a fallback) from query string, set cookie, and redirect to account page to show the form.
40
	 */
41
	public static function redirect_reset_password_link() {
42
		if ( is_account_page() && isset( $_GET['key'] ) && ( isset( $_GET['id'] ) || isset( $_GET['login'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
43
44
			// If available, get $user_id from query string parameter for fallback purposes.
45 View Code Duplication
			if ( isset( $_GET['login'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
46
				$user    = get_user_by( 'login', sanitize_user( wp_unslash( $_GET['login'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
47
				$user_id = $user ? $user->ID : 0;
48
			} else {
49
				$user_id = absint( $_GET['id'] );
50
			}
51
52
			$value = sprintf( '%d:%s', $user_id, wp_unslash( $_GET['key'] ) ); // phpcs:ignore
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
53
			WC_Shortcode_My_Account::set_reset_password_cookie( $value );
54
			wp_safe_redirect( add_query_arg( 'show-reset-form', 'true', wc_lostpassword_url() ) );
55
			exit;
56
		}
57
	}
58
59
	/**
60
	 * Save and and update a billing or shipping address if the
61
	 * form was submitted through the user account page.
62
	 */
63
	public static function save_address() {
64
		global $wp;
65
66
		$nonce_value = wc_get_var( $_REQUEST['woocommerce-edit-address-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
67
68
		if ( ! wp_verify_nonce( $nonce_value, 'woocommerce-edit_address' ) ) {
69
			return;
70
		}
71
72
		if ( empty( $_POST['action'] ) || 'edit_address' !== $_POST['action'] ) {
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
73
			return;
74
		}
75
76
		wc_nocache_headers();
77
78
		$user_id = get_current_user_id();
79
80
		if ( $user_id <= 0 ) {
81
			return;
82
		}
83
84
		$load_address = isset( $wp->query_vars['edit-address'] ) ? wc_edit_address_i18n( sanitize_title( $wp->query_vars['edit-address'] ), true ) : 'billing';
85
86
		if ( ! isset( $_POST[ $load_address . '_country' ] ) ) {
87
			return;
88
		}
89
90
		$address = WC()->countries->get_address_fields( wc_clean( wp_unslash( $_POST[ $load_address . '_country' ] ) ), $load_address . '_' );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
91
92
		foreach ( $address as $key => $field ) {
93
			if ( ! isset( $field['type'] ) ) {
94
				$field['type'] = 'text';
95
			}
96
97
			// Get Value.
98
			if ( 'checkbox' === $field['type'] ) {
99
				$value = (int) isset( $_POST[ $key ] );
100
			} else {
101
				$value = isset( $_POST[ $key ] ) ? wc_clean( wp_unslash( $_POST[ $key ] ) ) : '';
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
102
			}
103
104
			// Hook to allow modification of value.
105
			$value = apply_filters( 'woocommerce_process_myaccount_field_' . $key, $value );
106
107
			// Validation: Required fields.
108
			if ( ! empty( $field['required'] ) && empty( $value ) ) {
109
				/* translators: %s: Field name. */
110
				wc_add_notice( sprintf( __( '%s is a required field.', 'woocommerce' ), $field['label'] ), 'error' );
111
			}
112
113
			if ( ! empty( $value ) ) {
114
115
				// Validation rules.
116
				if ( ! empty( $field['validate'] ) && is_array( $field['validate'] ) ) {
117
					foreach ( $field['validate'] as $rule ) {
118
						switch ( $rule ) {
119
							case 'postcode':
120
								$value = strtoupper( str_replace( ' ', '', $value ) );
121
122
								if ( ! WC_Validation::is_postcode( $value, wc_clean( wp_unslash( $_POST[ $load_address . '_country' ] ) ) ) ) {
0 ignored issues
show
Bug introduced by
It seems like wc_clean(wp_unslash($_PO...address . '_country'])) targeting wc_clean() can also be of type array; however, WC_Validation::is_postcode() 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...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
123
									wc_add_notice( __( 'Please enter a valid postcode / ZIP.', 'woocommerce' ), 'error' );
124
								} else {
125
									$value = wc_format_postcode( $value, wc_clean( wp_unslash( $_POST[ $load_address . '_country' ] ) ) );
0 ignored issues
show
Bug introduced by
It seems like wc_clean(wp_unslash($_PO...address . '_country'])) targeting wc_clean() can also be of type array; however, wc_format_postcode() 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...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
126
								}
127
								break;
128
							case 'phone':
129 View Code Duplication
								if ( ! WC_Validation::is_phone( $value ) ) {
130
									/* translators: %s: Phone number. */
131
									wc_add_notice( sprintf( __( '%s is not a valid phone number.', 'woocommerce' ), '<strong>' . $field['label'] . '</strong>' ), 'error' );
132
								}
133
								break;
134
							case 'email':
135
								$value = strtolower( $value );
136
137
								if ( ! is_email( $value ) ) {
138
									/* translators: %s: Email address. */
139
									wc_add_notice( sprintf( __( '%s is not a valid email address.', 'woocommerce' ), '<strong>' . $field['label'] . '</strong>' ), 'error' );
140
								}
141
								break;
142
						}
143
					}
144
				}
145
			}
146
		}
147
148
		do_action( 'woocommerce_after_save_address_validation', $user_id, $load_address, $address );
149
150
		if ( 0 === wc_notice_count( 'error' ) ) {
151
152
			$customer = new WC_Customer( $user_id );
153
154
			if ( $customer ) {
155
				foreach ( $address as $key => $field ) {
156
					if ( is_callable( array( $customer, "set_$key" ) ) ) {
157
						$customer->{"set_$key"}( $value );
158
					} else {
159
						$customer->update_meta_data( $key, $value );
160
					}
161
162 View Code Duplication
					if ( WC()->customer && is_callable( array( WC()->customer, "set_$key" ) ) ) {
163
						WC()->customer->{"set_$key"}( $value );
164
					}
165
				}
166
				$customer->save();
167
			}
168
169
			wc_add_notice( __( 'Address changed successfully.', 'woocommerce' ) );
170
171
			do_action( 'woocommerce_customer_save_address', $user_id, $load_address );
172
173
			wp_safe_redirect( wc_get_endpoint_url( 'edit-address', '', wc_get_page_permalink( 'myaccount' ) ) );
174
			exit;
175
		}
176
	}
177
178
	/**
179
	 * Save the password/account details and redirect back to the my account page.
180
	 */
181
	public static function save_account_details() {
182
		$nonce_value = wc_get_var( $_REQUEST['save-account-details-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
183
184
		if ( ! wp_verify_nonce( $nonce_value, 'save_account_details' ) ) {
185
			return;
186
		}
187
188
		if ( empty( $_POST['action'] ) || 'save_account_details' !== $_POST['action'] ) {
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
189
			return;
190
		}
191
192
		wc_nocache_headers();
193
194
		$user_id = get_current_user_id();
195
196
		if ( $user_id <= 0 ) {
197
			return;
198
		}
199
200
		$account_first_name   = ! empty( $_POST['account_first_name'] ) ? wc_clean( wp_unslash( $_POST['account_first_name'] ) ) : '';
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
201
		$account_last_name    = ! empty( $_POST['account_last_name'] ) ? wc_clean( wp_unslash( $_POST['account_last_name'] ) ) : '';
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
202
		$account_display_name = ! empty( $_POST['account_display_name'] ) ? wc_clean( wp_unslash( $_POST['account_display_name'] ) ) : '';
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
203
		$account_email        = ! empty( $_POST['account_email'] ) ? wc_clean( wp_unslash( $_POST['account_email'] ) ) : '';
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
204
		$pass_cur             = ! empty( $_POST['password_current'] ) ? wp_unslash( $_POST['password_current'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
205
		$pass1                = ! empty( $_POST['password_1'] ) ? wp_unslash( $_POST['password_1'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
206
		$pass2                = ! empty( $_POST['password_2'] ) ? wp_unslash( $_POST['password_2'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
207
		$save_pass            = true;
208
209
		// Current user data.
210
		$current_user       = get_user_by( 'id', $user_id );
211
		$current_first_name = $current_user->first_name;
212
		$current_last_name  = $current_user->last_name;
213
		$current_email      = $current_user->user_email;
214
215
		// New user data.
216
		$user               = new stdClass();
217
		$user->ID           = $user_id;
218
		$user->first_name   = $account_first_name;
219
		$user->last_name    = $account_last_name;
220
		$user->display_name = $account_display_name;
221
222
		// Prevent display name to be changed to email.
223
		if ( is_email( $account_display_name ) ) {
224
			wc_add_notice( __( 'Display name cannot be changed to email address due to privacy concern.', 'woocommerce' ), 'error' );
225
		}
226
227
		// Handle required fields.
228
		$required_fields = apply_filters(
229
			'woocommerce_save_account_details_required_fields',
230
			array(
231
				'account_first_name'   => __( 'First name', 'woocommerce' ),
232
				'account_last_name'    => __( 'Last name', 'woocommerce' ),
233
				'account_display_name' => __( 'Display name', 'woocommerce' ),
234
				'account_email'        => __( 'Email address', 'woocommerce' ),
235
			)
236
		);
237
238
		foreach ( $required_fields as $field_key => $field_name ) {
239 View Code Duplication
			if ( empty( $_POST[ $field_key ] ) ) {
240
				/* translators: %s: Field name. */
241
				wc_add_notice( sprintf( __( '%s is a required field.', 'woocommerce' ), '<strong>' . esc_html( $field_name ) . '</strong>' ), 'error' );
242
			}
243
		}
244
245
		if ( $account_email ) {
246
			$account_email = sanitize_email( $account_email );
247
			if ( ! is_email( $account_email ) ) {
248
				wc_add_notice( __( 'Please provide a valid email address.', 'woocommerce' ), 'error' );
249
			} elseif ( email_exists( $account_email ) && $account_email !== $current_user->user_email ) {
250
				wc_add_notice( __( 'This email address is already registered.', 'woocommerce' ), 'error' );
251
			}
252
			$user->user_email = $account_email;
253
		}
254
255
		if ( ! empty( $pass_cur ) && empty( $pass1 ) && empty( $pass2 ) ) {
256
			wc_add_notice( __( 'Please fill out all password fields.', 'woocommerce' ), 'error' );
257
			$save_pass = false;
258 View Code Duplication
		} elseif ( ! empty( $pass1 ) && empty( $pass_cur ) ) {
259
			wc_add_notice( __( 'Please enter your current password.', 'woocommerce' ), 'error' );
260
			$save_pass = false;
261
		} elseif ( ! empty( $pass1 ) && empty( $pass2 ) ) {
262
			wc_add_notice( __( 'Please re-enter your password.', 'woocommerce' ), 'error' );
263
			$save_pass = false;
264 View Code Duplication
		} elseif ( ( ! empty( $pass1 ) || ! empty( $pass2 ) ) && $pass1 !== $pass2 ) {
265
			wc_add_notice( __( 'New passwords do not match.', 'woocommerce' ), 'error' );
266
			$save_pass = false;
267
		} elseif ( ! empty( $pass1 ) && ! wp_check_password( $pass_cur, $current_user->user_pass, $current_user->ID ) ) {
268
			wc_add_notice( __( 'Your current password is incorrect.', 'woocommerce' ), 'error' );
269
			$save_pass = false;
270
		}
271
272
		if ( $pass1 && $save_pass ) {
273
			$user->user_pass = $pass1;
274
		}
275
276
		// Allow plugins to return their own errors.
277
		$errors = new WP_Error();
278
		do_action_ref_array( 'woocommerce_save_account_details_errors', array( &$errors, &$user ) );
279
280
		if ( $errors->get_error_messages() ) {
281
			foreach ( $errors->get_error_messages() as $error ) {
282
				wc_add_notice( $error, 'error' );
283
			}
284
		}
285
286
		if ( wc_notice_count( 'error' ) === 0 ) {
0 ignored issues
show
introduced by
Found "=== 0". Use Yoda Condition checks, you must
Loading history...
287
			wp_update_user( $user );
288
289
			// Update customer object to keep data in sync.
290
			$customer = new WC_Customer( $user->ID );
291
292
			if ( $customer ) {
293
				// Keep billing data in sync if data changed.
294
				if ( is_email( $user->user_email ) && $current_email !== $user->user_email ) {
295
					$customer->set_billing_email( $user->user_email );
296
				}
297
298
				if ( $current_first_name !== $user->first_name ) {
299
					$customer->set_billing_first_name( $user->first_name );
300
				}
301
302
				if ( $current_last_name !== $user->last_name ) {
303
					$customer->set_billing_last_name( $user->last_name );
304
				}
305
306
				$customer->save();
307
			}
308
309
			wc_add_notice( __( 'Account details changed successfully.', 'woocommerce' ) );
310
311
			do_action( 'woocommerce_save_account_details', $user->ID );
312
313
			wp_safe_redirect( wc_get_page_permalink( 'myaccount' ) );
314
			exit;
315
		}
316
	}
317
318
	/**
319
	 * Process the checkout form.
320
	 */
321
	public static function checkout_action() {
322
		if ( isset( $_POST['woocommerce_checkout_place_order'] ) || isset( $_POST['woocommerce_checkout_update_totals'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
323
			wc_nocache_headers();
324
325
			if ( WC()->cart->is_empty() ) {
326
				wp_safe_redirect( wc_get_page_permalink( 'cart' ) );
327
				exit;
328
			}
329
330
			wc_maybe_define_constant( 'WOOCOMMERCE_CHECKOUT', true );
331
332
			WC()->checkout()->process_checkout();
333
		}
334
	}
335
336
	/**
337
	 * Process the pay form.
338
	 */
339
	public static function pay_action() {
340
		global $wp;
341
342
		if ( isset( $_POST['woocommerce_pay'], $_GET['key'] ) ) {
343
			wc_nocache_headers();
344
345
			$nonce_value = wc_get_var( $_REQUEST['woocommerce-pay-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
346
347
			if ( ! wp_verify_nonce( $nonce_value, 'woocommerce-pay' ) ) {
348
				return;
349
			}
350
351
			ob_start();
352
353
			// Pay for existing order.
354
			$order_key = wp_unslash( $_GET['key'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
355
			$order_id  = absint( $wp->query_vars['order-pay'] );
356
			$order     = wc_get_order( $order_id );
357
358
			if ( $order_id === $order->get_id() && hash_equals( $order->get_order_key(), $order_key ) && $order->needs_payment() ) {
359
360
				do_action( 'woocommerce_before_pay_action', $order );
361
362
				WC()->customer->set_props(
363
					array(
364
						'billing_country'  => $order->get_billing_country() ? $order->get_billing_country() : null,
365
						'billing_state'    => $order->get_billing_state() ? $order->get_billing_state() : null,
366
						'billing_postcode' => $order->get_billing_postcode() ? $order->get_billing_postcode() : null,
367
						'billing_city'     => $order->get_billing_city() ? $order->get_billing_city() : null,
368
					)
369
				);
370
				WC()->customer->save();
371
372
				if ( ! empty( $_POST['terms-field'] ) && empty( $_POST['terms'] ) ) {
373
					wc_add_notice( __( 'Please read and accept the terms and conditions to proceed with your order.', 'woocommerce' ), 'error' );
374
					return;
375
				}
376
377
				// Update payment method.
378
				if ( $order->needs_payment() ) {
379
					$payment_method     = isset( $_POST['payment_method'] ) ? wc_clean( wp_unslash( $_POST['payment_method'] ) ) : false;
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
380
					$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
381
382
					if ( ! $payment_method ) {
383
						wc_add_notice( __( 'Invalid payment method.', 'woocommerce' ), 'error' );
384
						return;
385
					}
386
387
					update_post_meta( $order_id, '_payment_method', $payment_method );
388
389
					if ( isset( $available_gateways[ $payment_method ] ) ) {
390
						$payment_method_title = $available_gateways[ $payment_method ]->get_title();
391
					} else {
392
						$payment_method_title = '';
393
					}
394
395
					update_post_meta( $order_id, '_payment_method_title', $payment_method_title );
396
397
					$available_gateways[ $payment_method ]->validate_fields();
398
399
					if ( 0 === wc_notice_count( 'error' ) ) {
400
401
						$result = $available_gateways[ $payment_method ]->process_payment( $order_id );
402
403
						// Redirect to success/confirmation/payment page.
404
						if ( 'success' === $result['result'] ) {
405
							wp_redirect( $result['redirect'] ); //phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
406
							exit;
407
						}
408
					}
409
				} else {
410
					// No payment was required for order.
411
					$order->payment_complete();
412
					wp_safe_redirect( $order->get_checkout_order_received_url() );
413
					exit;
414
				}
415
416
				do_action( 'woocommerce_after_pay_action', $order );
417
418
			}
419
		}
420
	}
421
422
	/**
423
	 * Process the add payment method form.
424
	 */
425
	public static function add_payment_method_action() {
426
		if ( isset( $_POST['woocommerce_add_payment_method'], $_POST['payment_method'] ) ) {
427
			wc_nocache_headers();
428
429
			$nonce_value = wc_get_var( $_REQUEST['woocommerce-add-payment-method-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
430
431
			if ( ! wp_verify_nonce( $nonce_value, 'woocommerce-add-payment-method' ) ) {
432
				return;
433
			}
434
435
			ob_start();
436
437
			$payment_method_id  = wc_clean( wp_unslash( $_POST['payment_method'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
438
			$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
439
440
			if ( isset( $available_gateways[ $payment_method_id ] ) ) {
441
				$gateway = $available_gateways[ $payment_method_id ];
442
443
				if ( ! $gateway->supports( 'add_payment_method' ) && ! $gateway->supports( 'tokenization' ) ) {
444
					wc_add_notice( __( 'Invalid payment gateway.', 'woocommerce' ), 'error' );
445
					return;
446
				}
447
448
				$gateway->validate_fields();
449
450
				if ( wc_notice_count( 'error' ) > 0 ) {
451
					return;
452
				}
453
454
				$result = $gateway->add_payment_method();
455
456
				if ( 'success' === $result['result'] ) {
457
					wc_add_notice( __( 'Payment method successfully added.', 'woocommerce' ) );
458
				}
459
460
				if ( 'failure' === $result['result'] ) {
461
					wc_add_notice( __( 'Unable to add payment method to your account.', 'woocommerce' ), 'error' );
462
				}
463
464
				if ( ! empty( $result['redirect'] ) ) {
465
					wp_redirect( $result['redirect'] ); //phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
466
					exit();
467
				}
468
			}
469
		}
470
	}
471
472
	/**
473
	 * Process the delete payment method form.
474
	 */
475 View Code Duplication
	public static function delete_payment_method_action() {
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...
476
		global $wp;
477
478
		if ( isset( $wp->query_vars['delete-payment-method'] ) ) {
479
			wc_nocache_headers();
480
481
			$token_id = absint( $wp->query_vars['delete-payment-method'] );
482
			$token    = WC_Payment_Tokens::get( $token_id );
483
484
			if ( is_null( $token ) || get_current_user_id() !== $token->get_user_id() || ! isset( $_REQUEST['_wpnonce'] ) || false === wp_verify_nonce( wp_unslash( $_REQUEST['_wpnonce'] ), 'delete-payment-method-' . $token_id ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
485
				wc_add_notice( __( 'Invalid payment method.', 'woocommerce' ), 'error' );
486
			} else {
487
				WC_Payment_Tokens::delete( $token_id );
488
				wc_add_notice( __( 'Payment method deleted.', 'woocommerce' ) );
489
			}
490
491
			wp_safe_redirect( wc_get_account_endpoint_url( 'payment-methods' ) );
492
			exit();
493
		}
494
495
	}
496
497
	/**
498
	 * Process the delete payment method form.
499
	 */
500 View Code Duplication
	public static function set_default_payment_method_action() {
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...
501
		global $wp;
502
503
		if ( isset( $wp->query_vars['set-default-payment-method'] ) ) {
504
			wc_nocache_headers();
505
506
			$token_id = absint( $wp->query_vars['set-default-payment-method'] );
507
			$token    = WC_Payment_Tokens::get( $token_id );
508
509
			if ( is_null( $token ) || get_current_user_id() !== $token->get_user_id() || ! isset( $_REQUEST['_wpnonce'] ) || false === wp_verify_nonce( wp_unslash( $_REQUEST['_wpnonce'] ), 'set-default-payment-method-' . $token_id ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
510
				wc_add_notice( __( 'Invalid payment method.', 'woocommerce' ), 'error' );
511
			} else {
512
				WC_Payment_Tokens::set_users_default( $token->get_user_id(), intval( $token_id ) );
513
				wc_add_notice( __( 'This payment method was successfully set as your default.', 'woocommerce' ) );
514
			}
515
516
			wp_safe_redirect( wc_get_account_endpoint_url( 'payment-methods' ) );
517
			exit();
518
		}
519
520
	}
521
522
	/**
523
	 * Remove from cart/update.
524
	 */
525
	public static function update_cart_action() {
526
		if ( ! ( isset( $_REQUEST['apply_coupon'] ) || isset( $_REQUEST['remove_coupon'] ) || isset( $_REQUEST['remove_item'] ) || isset( $_REQUEST['undo_item'] ) || isset( $_REQUEST['update_cart'] ) || isset( $_REQUEST['proceed'] ) ) ) {
527
			return;
528
		}
529
530
		wc_nocache_headers();
531
532
		$nonce_value = wc_get_var( $_REQUEST['woocommerce-cart-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
533
534
		if ( ! empty( $_POST['apply_coupon'] ) && ! empty( $_POST['coupon_code'] ) ) {
535
			WC()->cart->add_discount( sanitize_text_field( wp_unslash( $_POST['coupon_code'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
536
537
		} elseif ( isset( $_GET['remove_coupon'] ) ) {
538
			WC()->cart->remove_coupon( wc_clean( wp_unslash( $_GET['remove_coupon'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
539
540
		} elseif ( ! empty( $_GET['remove_item'] ) && wp_verify_nonce( $nonce_value, 'woocommerce-cart' ) ) {
541
			$cart_item_key = sanitize_text_field( wp_unslash( $_GET['remove_item'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
542
			$cart_item     = WC()->cart->get_cart_item( $cart_item_key );
543
544
			if ( $cart_item ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $cart_item of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
545
				WC()->cart->remove_cart_item( $cart_item_key );
546
547
				$product = wc_get_product( $cart_item['product_id'] );
548
549
				/* translators: %s: Item name. */
550
				$item_removed_title = apply_filters( 'woocommerce_cart_item_removed_title', $product ? sprintf( _x( '&ldquo;%s&rdquo;', 'Item name in quotes', 'woocommerce' ), $product->get_name() ) : __( 'Item', 'woocommerce' ), $cart_item );
551
552
				// Don't show undo link if removed item is out of stock.
553
				if ( $product && $product->is_in_stock() && $product->has_enough_stock( $cart_item['quantity'] ) ) {
554
					/* Translators: %s Product title. */
555
					$removed_notice  = sprintf( __( '%s removed.', 'woocommerce' ), $item_removed_title );
556
					$removed_notice .= ' <a href="' . esc_url( wc_get_cart_undo_url( $cart_item_key ) ) . '" class="restore-item">' . __( 'Undo?', 'woocommerce' ) . '</a>';
557
				} else {
558
					/* Translators: %s Product title. */
559
					$removed_notice = sprintf( __( '%s removed.', 'woocommerce' ), $item_removed_title );
560
				}
561
562
				wc_add_notice( $removed_notice );
563
			}
564
565
			$referer = wp_get_referer() ? remove_query_arg( array( 'remove_item', 'add-to-cart', 'added-to-cart', 'order_again', '_wpnonce' ), add_query_arg( 'removed_item', '1', wp_get_referer() ) ) : wc_get_cart_url();
566
			wp_safe_redirect( $referer );
567
			exit;
568
569
		} elseif ( ! empty( $_GET['undo_item'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $nonce_value, 'woocommerce-cart' ) ) {
570
571
			// Undo Cart Item.
572
			$cart_item_key = sanitize_text_field( wp_unslash( $_GET['undo_item'] ) );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
573
574
			WC()->cart->restore_cart_item( $cart_item_key );
575
576
			$referer = wp_get_referer() ? remove_query_arg( array( 'undo_item', '_wpnonce' ), wp_get_referer() ) : wc_get_cart_url();
577
			wp_safe_redirect( $referer );
578
			exit;
579
580
		}
581
582
		// Update Cart - checks apply_coupon too because they are in the same form.
583
		if ( ( ! empty( $_POST['apply_coupon'] ) || ! empty( $_POST['update_cart'] ) || ! empty( $_POST['proceed'] ) ) && wp_verify_nonce( $nonce_value, 'woocommerce-cart' ) ) {
584
585
			$cart_updated = false;
586
			$cart_totals  = isset( $_POST['cart'] ) ? wp_unslash( $_POST['cart'] ) : ''; // PHPCS: input var ok, CSRF ok, sanitization ok.
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
587
588
			if ( ! WC()->cart->is_empty() && is_array( $cart_totals ) ) {
589
				foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
590
591
					$_product = $values['data'];
592
593
					// Skip product if no updated quantity was posted.
594
					if ( ! isset( $cart_totals[ $cart_item_key ] ) || ! isset( $cart_totals[ $cart_item_key ]['qty'] ) ) {
595
						continue;
596
					}
597
598
					// Sanitize.
599
					$quantity = apply_filters( 'woocommerce_stock_amount_cart_item', wc_stock_amount( preg_replace( '/[^0-9\.]/', '', $cart_totals[ $cart_item_key ]['qty'] ) ), $cart_item_key );
600
601
					if ( '' === $quantity || $quantity === $values['quantity'] ) {
602
						continue;
603
					}
604
605
					// Update cart validation.
606
					$passed_validation = apply_filters( 'woocommerce_update_cart_validation', true, $cart_item_key, $values, $quantity );
607
608
					// is_sold_individually.
609 View Code Duplication
					if ( $_product->is_sold_individually() && $quantity > 1 ) {
610
						/* Translators: %s Product title. */
611
						wc_add_notice( sprintf( __( 'You can only have 1 %s in your cart.', 'woocommerce' ), $_product->get_name() ), 'error' );
612
						$passed_validation = false;
613
					}
614
615
					if ( $passed_validation ) {
616
						WC()->cart->set_quantity( $cart_item_key, $quantity, false );
617
						$cart_updated = true;
618
					}
619
				}
620
			}
621
622
			// Trigger action - let 3rd parties update the cart if they need to and update the $cart_updated variable.
623
			$cart_updated = apply_filters( 'woocommerce_update_cart_action_cart_updated', $cart_updated );
624
625
			if ( $cart_updated ) {
626
				WC()->cart->calculate_totals();
627
			}
628
629
			if ( ! empty( $_POST['proceed'] ) ) {
630
				wp_safe_redirect( wc_get_checkout_url() );
631
				exit;
632
			} elseif ( $cart_updated ) {
633
				wc_add_notice( __( 'Cart updated.', 'woocommerce' ) );
634
				$referer = remove_query_arg( array( 'remove_coupon', 'add-to-cart' ), ( wp_get_referer() ? wp_get_referer() : wc_get_cart_url() ) );
635
				wp_safe_redirect( $referer );
636
				exit;
637
			}
638
		}
639
	}
640
641
	/**
642
	 * Place a previous order again.
643
	 *
644
	 * @deprecated 3.5.0 Logic moved to cart session handling.
645
	 */
646
	public static function order_again() {
647
		wc_deprecated_function( 'WC_Form_Handler::order_again', '3.5', 'This method should not be called manually.' );
648
	}
649
650
	/**
651
	 * Cancel a pending order.
652
	 */
653
	public static function cancel_order() {
654
		if (
655
			isset( $_GET['cancel_order'] ) &&
656
			isset( $_GET['order'] ) &&
657
			isset( $_GET['order_id'] ) &&
658
			( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), 'woocommerce-cancel_order' ) ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
659
		) {
660
			wc_nocache_headers();
661
662
			$order_key        = wp_unslash( $_GET['order'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
663
			$order_id         = absint( $_GET['order_id'] );
664
			$order            = wc_get_order( $order_id );
665
			$user_can_cancel  = current_user_can( 'cancel_order', $order_id );
666
			$order_can_cancel = $order->has_status( apply_filters( 'woocommerce_valid_order_statuses_for_cancel', array( 'pending', 'failed' ) ) );
667
			$redirect         = isset( $_GET['redirect'] ) ? wp_unslash( $_GET['redirect'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
668
669
			if ( $user_can_cancel && $order_can_cancel && $order->get_id() === $order_id && hash_equals( $order->get_order_key(), $order_key ) ) {
670
671
				// Cancel the order + restore stock.
672
				WC()->session->set( 'order_awaiting_payment', false );
673
				$order->update_status( 'cancelled', __( 'Order cancelled by customer.', 'woocommerce' ) );
674
675
				wc_add_notice( apply_filters( 'woocommerce_order_cancelled_notice', __( 'Your order was cancelled.', 'woocommerce' ) ), apply_filters( 'woocommerce_order_cancelled_notice_type', 'notice' ) );
676
677
				do_action( 'woocommerce_cancelled_order', $order->get_id() );
678
679
			} elseif ( $user_can_cancel && ! $order_can_cancel ) {
680
				wc_add_notice( __( 'Your order can no longer be cancelled. Please contact us if you need assistance.', 'woocommerce' ), 'error' );
681
			} else {
682
				wc_add_notice( __( 'Invalid order.', 'woocommerce' ), 'error' );
683
			}
684
685
			if ( $redirect ) {
686
				wp_safe_redirect( $redirect );
687
				exit;
688
			}
689
		}
690
	}
691
692
	/**
693
	 * Add to cart action.
694
	 *
695
	 * Checks for a valid request, does validation (via hooks) and then redirects if valid.
696
	 *
697
	 * @param bool $url (default: false) URL to redirect to.
698
	 */
699
	public static function add_to_cart_action( $url = false ) {
700
		if ( ! isset( $_REQUEST['add-to-cart'] ) || ! is_numeric( wp_unslash( $_REQUEST['add-to-cart'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
701
			return;
702
		}
703
704
		wc_nocache_headers();
705
706
		$product_id        = apply_filters( 'woocommerce_add_to_cart_product_id', absint( wp_unslash( $_REQUEST['add-to-cart'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
707
		$was_added_to_cart = false;
708
		$adding_to_cart    = wc_get_product( $product_id );
709
710
		if ( ! $adding_to_cart ) {
711
			return;
712
		}
713
714
		$add_to_cart_handler = apply_filters( 'woocommerce_add_to_cart_handler', $adding_to_cart->get_type(), $adding_to_cart );
715
716
		if ( 'variable' === $add_to_cart_handler || 'variation' === $add_to_cart_handler ) {
717
			$was_added_to_cart = self::add_to_cart_handler_variable( $product_id );
718
		} elseif ( 'grouped' === $add_to_cart_handler ) {
719
			$was_added_to_cart = self::add_to_cart_handler_grouped( $product_id );
720
		} elseif ( has_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler ) ) {
721
			do_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler, $url ); // Custom handler.
722
		} else {
723
			$was_added_to_cart = self::add_to_cart_handler_simple( $product_id );
724
		}
725
726
		// If we added the product to the cart we can now optionally do a redirect.
727
		if ( $was_added_to_cart && 0 === wc_notice_count( 'error' ) ) {
728
			$url = apply_filters( 'woocommerce_add_to_cart_redirect', $url, $adding_to_cart );
729
730
			if ( $url ) {
731
				wp_safe_redirect( $url );
732
				exit;
733
			} elseif ( 'yes' === get_option( 'woocommerce_cart_redirect_after_add' ) ) {
734
				wp_safe_redirect( wc_get_cart_url() );
735
				exit;
736
			}
737
		}
738
	}
739
740
	/**
741
	 * Handle adding simple products to the cart.
742
	 *
743
	 * @since 2.4.6 Split from add_to_cart_action.
744
	 * @param int $product_id Product ID to add to the cart.
745
	 * @return bool success or not
746
	 */
747
	private static function add_to_cart_handler_simple( $product_id ) {
748
		$quantity          = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $_REQUEST['quantity'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
749
		$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
750
751 View Code Duplication
		if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity ) ) {
752
			wc_add_to_cart_message( array( $product_id => $quantity ), true );
753
			return true;
754
		}
755
		return false;
756
	}
757
758
	/**
759
	 * Handle adding grouped products to the cart.
760
	 *
761
	 * @since 2.4.6 Split from add_to_cart_action.
762
	 * @param int $product_id Product ID to add to the cart.
763
	 * @return bool success or not
764
	 */
765
	private static function add_to_cart_handler_grouped( $product_id ) {
766
		$was_added_to_cart = false;
767
		$added_to_cart     = array();
768
		$items             = isset( $_REQUEST['quantity'] ) && is_array( $_REQUEST['quantity'] ) ? wp_unslash( $_REQUEST['quantity'] ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
769
770
		if ( ! empty( $items ) ) {
771
			$quantity_set = false;
772
773
			foreach ( $items as $item => $quantity ) {
774
				if ( $quantity <= 0 ) {
775
					continue;
776
				}
777
				$quantity_set = true;
778
779
				// Add to cart validation.
780
				$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $item, $quantity );
781
782
				// Suppress total recalculation until finished.
783
				remove_action( 'woocommerce_add_to_cart', array( WC()->cart, 'calculate_totals' ), 20, 0 );
784
785
				if ( $passed_validation && false !== WC()->cart->add_to_cart( $item, $quantity ) ) {
786
					$was_added_to_cart      = true;
787
					$added_to_cart[ $item ] = $quantity;
788
				}
789
790
				add_action( 'woocommerce_add_to_cart', array( WC()->cart, 'calculate_totals' ), 20, 0 );
791
			}
792
793
			if ( ! $was_added_to_cart && ! $quantity_set ) {
794
				wc_add_notice( __( 'Please choose the quantity of items you wish to add to your cart&hellip;', 'woocommerce' ), 'error' );
795
			} elseif ( $was_added_to_cart ) {
796
				wc_add_to_cart_message( $added_to_cart );
797
				WC()->cart->calculate_totals();
798
				return true;
799
			}
800
		} elseif ( $product_id ) {
801
			/* Link on product archives */
802
			wc_add_notice( __( 'Please choose a product to add to your cart&hellip;', 'woocommerce' ), 'error' );
803
		}
804
		return false;
805
	}
806
807
	/**
808
	 * Handle adding variable products to the cart.
809
	 *
810
	 * @since 2.4.6 Split from add_to_cart_action.
811
	 * @throws Exception If add to cart fails.
812
	 * @param int $product_id Product ID to add to the cart.
813
	 * @return bool success or not
814
	 */
815
	private static function add_to_cart_handler_variable( $product_id ) {
816
		try {
817
			$variation_id       = empty( $_REQUEST['variation_id'] ) ? '' : absint( wp_unslash( $_REQUEST['variation_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
818
			$quantity           = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $_REQUEST['quantity'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
819
			$missing_attributes = array();
820
			$variations         = array();
821
			$adding_to_cart     = wc_get_product( $product_id );
822
823
			if ( ! $adding_to_cart ) {
824
				return false;
825
			}
826
827
			// If the $product_id was in fact a variation ID, update the variables.
828
			if ( $adding_to_cart->is_type( 'variation' ) ) {
829
				$variation_id   = $product_id;
830
				$product_id     = $adding_to_cart->get_parent_id();
831
				$adding_to_cart = wc_get_product( $product_id );
832
833
				if ( ! $adding_to_cart ) {
834
					return false;
835
				}
836
			}
837
838
			// Gather posted attributes.
839
			$posted_attributes = array();
840
841
			foreach ( $adding_to_cart->get_attributes() as $attribute ) {
842
				if ( ! $attribute['is_variation'] ) {
843
					continue;
844
				}
845
				$attribute_key = 'attribute_' . sanitize_title( $attribute['name'] );
846
847
				if ( isset( $_REQUEST[ $attribute_key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
848
					if ( $attribute['is_taxonomy'] ) {
849
						// Don't use wc_clean as it destroys sanitized characters.
850
						$value = sanitize_title( wp_unslash( $_REQUEST[ $attribute_key ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
851
					} else {
852
						$value = html_entity_decode( wc_clean( wp_unslash( $_REQUEST[ $attribute_key ] ) ), ENT_QUOTES, get_bloginfo( 'charset' ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
853
					}
854
855
					$posted_attributes[ $attribute_key ] = $value;
856
				}
857
			}
858
859
			// If no variation ID is set, attempt to get a variation ID from posted attributes.
860
			if ( empty( $variation_id ) ) {
861
				$data_store   = WC_Data_Store::load( 'product' );
862
				$variation_id = $data_store->find_matching_product_variation( $adding_to_cart, $posted_attributes );
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...
863
			}
864
865
			// Do we have a variation ID?
866
			if ( empty( $variation_id ) ) {
867
				throw new Exception( __( 'Please choose product options&hellip;', 'woocommerce' ) );
868
			}
869
870
			// Check the data we have is valid.
871
			$variation_data = wc_get_product_variation_attributes( $variation_id );
872
873
			foreach ( $adding_to_cart->get_attributes() as $attribute ) {
874
				if ( ! $attribute['is_variation'] ) {
875
					continue;
876
				}
877
878
				// Get valid value from variation data.
879
				$attribute_key = 'attribute_' . sanitize_title( $attribute['name'] );
880
				$valid_value   = isset( $variation_data[ $attribute_key ] ) ? $variation_data[ $attribute_key ] : '';
881
882
				/**
883
				 * If the attribute value was posted, check if it's valid.
884
				 *
885
				 * If no attribute was posted, only error if the variation has an 'any' attribute which requires a value.
886
				 */
887
				if ( isset( $posted_attributes[ $attribute_key ] ) ) {
888
					$value = $posted_attributes[ $attribute_key ];
889
890
					// Allow if valid or show error.
891
					if ( $valid_value === $value ) {
892
						$variations[ $attribute_key ] = $value;
893
					} elseif ( '' === $valid_value && in_array( $value, $attribute->get_slugs(), true ) ) {
894
						// If valid values are empty, this is an 'any' variation so get all possible values.
895
						$variations[ $attribute_key ] = $value;
896
					} else {
897
						/* translators: %s: Attribute name. */
898
						throw new Exception( sprintf( __( 'Invalid value posted for %s', 'woocommerce' ), wc_attribute_label( $attribute['name'] ) ) );
899
					}
900
				} elseif ( '' === $valid_value ) {
901
					$missing_attributes[] = wc_attribute_label( $attribute['name'] );
902
				}
903
			}
904
			if ( ! empty( $missing_attributes ) ) {
905
				/* translators: %s: Attribute name. */
906
				throw new Exception( sprintf( _n( '%s is a required field', '%s are required fields', count( $missing_attributes ), 'woocommerce' ), wc_format_list_of_items( $missing_attributes ) ) );
907
			}
908
		} catch ( Exception $e ) {
909
			wc_add_notice( $e->getMessage(), 'error' );
910
			return false;
911
		}
912
913
		$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations );
914
915 View Code Duplication
		if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) ) {
916
			wc_add_to_cart_message( array( $product_id => $quantity ), true );
917
			return true;
918
		}
919
920
		return false;
921
	}
922
923
	/**
924
	 * Process the login form.
925
	 *
926
	 * @throws Exception On login error.
927
	 */
928
	public static function process_login() {
929
		// The global form-login.php template used `_wpnonce` in template versions < 3.3.0.
930
		$nonce_value = wc_get_var( $_REQUEST['woocommerce-login-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
931
932
		if ( isset( $_POST['login'], $_POST['username'], $_POST['password'] ) && wp_verify_nonce( $nonce_value, 'woocommerce-login' ) ) {
933
934
			try {
935
				$creds = array(
936
					'user_login'    => trim( wp_unslash( $_POST['username'] ) ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
937
					'user_password' => wp_unslash( $_POST['password'] ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
938
					'remember'      => isset( $_POST['rememberme'] ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
939
				);
940
941
				$validation_error = new WP_Error();
942
				$validation_error = apply_filters( 'woocommerce_process_login_errors', $validation_error, $creds['user_login'], $creds['user_password'] );
943
944
				if ( $validation_error->get_error_code() ) {
945
					throw new Exception( '<strong>' . __( 'Error:', 'woocommerce' ) . '</strong> ' . $validation_error->get_error_message() );
946
				}
947
948
				if ( empty( $creds['user_login'] ) ) {
949
					throw new Exception( '<strong>' . __( 'Error:', 'woocommerce' ) . '</strong> ' . __( 'Username is required.', 'woocommerce' ) );
950
				}
951
952
				// On multisite, ensure user exists on current site, if not add them before allowing login.
953
				if ( is_multisite() ) {
954
					$user_data = get_user_by( is_email( $creds['user_login'] ) ? 'email' : 'login', $creds['user_login'] );
955
956
					if ( $user_data && ! is_user_member_of_blog( $user_data->ID, get_current_blog_id() ) ) {
957
						add_user_to_blog( get_current_blog_id(), $user_data->ID, 'customer' );
958
					}
959
				}
960
961
				// Perform the login.
962
				$user = wp_signon( apply_filters( 'woocommerce_login_credentials', $creds ), is_ssl() );
963
964
				if ( is_wp_error( $user ) ) {
965
					$message = $user->get_error_message();
966
					$message = str_replace( '<strong>' . esc_html( $creds['user_login'] ) . '</strong>', '<strong>' . esc_html( $creds['user_login'] ) . '</strong>', $message );
967
					throw new Exception( $message );
968
				} else {
969
970 View Code Duplication
					if ( ! empty( $_POST['redirect'] ) ) {
971
						$redirect = wp_unslash( $_POST['redirect'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
972
					} elseif ( wc_get_raw_referer() ) {
973
						$redirect = wc_get_raw_referer();
974
					} else {
975
						$redirect = wc_get_page_permalink( 'myaccount' );
976
					}
977
978
					wp_redirect( wp_validate_redirect( apply_filters( 'woocommerce_login_redirect', remove_query_arg( 'wc_error', $redirect ), $user ), wc_get_page_permalink( 'myaccount' ) ) ); // phpcs:ignore
979
					exit;
980
				}
981
			} catch ( Exception $e ) {
982
				wc_add_notice( apply_filters( 'login_errors', $e->getMessage() ), 'error' );
983
				do_action( 'woocommerce_login_failed' );
984
			}
985
		}
986
	}
987
988
	/**
989
	 * Handle lost password form.
990
	 */
991
	public static function process_lost_password() {
992
		if ( isset( $_POST['wc_reset_password'], $_POST['user_login'] ) ) {
993
			$nonce_value = wc_get_var( $_REQUEST['woocommerce-lost-password-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
994
995
			if ( ! wp_verify_nonce( $nonce_value, 'lost_password' ) ) {
996
				return;
997
			}
998
999
			$success = WC_Shortcode_My_Account::retrieve_password();
1000
1001
			// If successful, redirect to my account with query arg set.
1002
			if ( $success ) {
1003
				wp_safe_redirect( add_query_arg( 'reset-link-sent', 'true', wc_get_account_endpoint_url( 'lost-password' ) ) );
1004
				exit;
1005
			}
1006
		}
1007
	}
1008
1009
	/**
1010
	 * Handle reset password form.
1011
	 */
1012
	public static function process_reset_password() {
1013
		$nonce_value = wc_get_var( $_REQUEST['woocommerce-reset-password-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
1014
1015
		if ( ! wp_verify_nonce( $nonce_value, 'reset_password' ) ) {
1016
			return;
1017
		}
1018
1019
		$posted_fields = array( 'wc_reset_password', 'password_1', 'password_2', 'reset_key', 'reset_login' );
1020
1021
		foreach ( $posted_fields as $field ) {
1022
			if ( ! isset( $_POST[ $field ] ) ) {
1023
				return;
1024
			}
1025
			$posted_fields[ $field ] = wp_unslash( $_POST[ $field ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1026
		}
1027
1028
		$user = WC_Shortcode_My_Account::check_password_reset_key( $posted_fields['reset_key'], $posted_fields['reset_login'] );
1029
1030
		if ( $user instanceof WP_User ) {
0 ignored issues
show
Bug introduced by
The class WP_User does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
1031
			if ( empty( $posted_fields['password_1'] ) ) {
1032
				wc_add_notice( __( 'Please enter your password.', 'woocommerce' ), 'error' );
1033
			}
1034
1035
			if ( $posted_fields['password_1'] !== $posted_fields['password_2'] ) {
1036
				wc_add_notice( __( 'Passwords do not match.', 'woocommerce' ), 'error' );
1037
			}
1038
1039
			$errors = new WP_Error();
1040
1041
			do_action( 'validate_password_reset', $errors, $user );
1042
1043
			wc_add_wp_error_notices( $errors );
1044
1045
			if ( 0 === wc_notice_count( 'error' ) ) {
1046
				WC_Shortcode_My_Account::reset_password( $user, $posted_fields['password_1'] );
1047
1048
				do_action( 'woocommerce_customer_reset_password', $user );
1049
1050
				wp_safe_redirect( add_query_arg( 'password-reset', 'true', wc_get_page_permalink( 'myaccount' ) ) );
1051
				exit;
1052
			}
1053
		}
1054
	}
1055
1056
	/**
1057
	 * Process the registration form.
1058
	 *
1059
	 * @throws Exception On registration error.
1060
	 */
1061
	public static function process_registration() {
1062
		$nonce_value = isset( $_POST['_wpnonce'] ) ? wp_unslash( $_POST['_wpnonce'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.NoNonceVerification
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1063
		$nonce_value = isset( $_POST['woocommerce-register-nonce'] ) ? wp_unslash( $_POST['woocommerce-register-nonce'] ) : $nonce_value; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.NoNonceVerification
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1064
1065
		if ( isset( $_POST['register'], $_POST['email'] ) && wp_verify_nonce( $nonce_value, 'woocommerce-register' ) ) {
1066
			$username = 'no' === get_option( 'woocommerce_registration_generate_username' ) && isset( $_POST['username'] ) ? wp_unslash( $_POST['username'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1067
			$password = 'no' === get_option( 'woocommerce_registration_generate_password' ) && isset( $_POST['password'] ) ? wp_unslash( $_POST['password'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1068
			$email    = wp_unslash( $_POST['email'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1069
1070
			try {
1071
				$validation_error = new WP_Error();
1072
				$validation_error = apply_filters( 'woocommerce_process_registration_errors', $validation_error, $username, $password, $email );
1073
1074
				if ( $validation_error->get_error_code() ) {
1075
					throw new Exception( $validation_error->get_error_message() );
1076
				}
1077
1078
				$new_customer = wc_create_new_customer( sanitize_email( $email ), wc_clean( $username ), $password );
0 ignored issues
show
Bug introduced by
It seems like wc_clean($username) targeting wc_clean() can also be of type array; however, wc_create_new_customer() 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...
1079
1080
				if ( is_wp_error( $new_customer ) ) {
1081
					throw new Exception( $new_customer->get_error_message() );
1082
				}
1083
1084
				if ( 'yes' === get_option( 'woocommerce_registration_generate_password' ) ) {
1085
					wc_add_notice( __( 'Your account was created successfully and a password has been sent to your email address.', 'woocommerce' ) );
1086
				} else {
1087
					wc_add_notice( __( 'Your account was created successfully. Your login details have been sent to your email address.', 'woocommerce' ) );
1088
				}
1089
1090
				// Only redirect after a forced login - otherwise output a success notice.
1091
				if ( apply_filters( 'woocommerce_registration_auth_new_customer', true, $new_customer ) ) {
1092
					wc_set_customer_auth_cookie( $new_customer );
1093
1094 View Code Duplication
					if ( ! empty( $_POST['redirect'] ) ) {
1095
						$redirect = wp_sanitize_redirect( wp_unslash( $_POST['redirect'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
1096
					} elseif ( wc_get_raw_referer() ) {
1097
						$redirect = wc_get_raw_referer();
1098
					} else {
1099
						$redirect = wc_get_page_permalink( 'myaccount' );
1100
					}
1101
1102
					wp_redirect( wp_validate_redirect( apply_filters( 'woocommerce_registration_redirect', $redirect ), wc_get_page_permalink( 'myaccount' ) ) ); //phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
1103
					exit;
1104
				}
1105
			} catch ( Exception $e ) {
1106
				wc_add_notice( '<strong>' . __( 'Error:', 'woocommerce' ) . '</strong> ' . $e->getMessage(), 'error' );
1107
			}
1108
		}
1109
	}
1110
}
1111
1112
WC_Form_Handler::init();
1113