WC_Form_Handler::update_cart_action()   D
last analyzed

Complexity

Conditions 36
Paths 83

Size

Total Lines 108
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 36
dl 0
loc 108
rs 4.273
c 0
b 0
f 0
eloc 55
nc 83
nop 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
if ( ! defined( 'ABSPATH' ) ) {
4
	exit; // Exit if accessed directly
5
}
6
7
/**
8
 * Handle frontend forms.
9
 *
10
 * @class 		WC_Form_Handler
11
 * @version		2.2.0
12
 * @package		WooCommerce/Classes/
13
 * @category	Class
14
 * @author 		WooThemes
15
 */
16
class WC_Form_Handler {
17
18
	/**
19
	 * Hook in methods.
20
	 */
21
	public static function init() {
22
		add_action( 'template_redirect', array( __CLASS__, 'save_address' ) );
23
		add_action( 'template_redirect', array( __CLASS__, 'save_account_details' ) );
24
		add_action( 'wp_loaded', array( __CLASS__, 'checkout_action' ), 20 );
25
		add_action( 'wp_loaded', array( __CLASS__, 'process_login' ), 20 );
26
		add_action( 'wp_loaded', array( __CLASS__, 'process_registration' ), 20 );
27
		add_action( 'wp_loaded', array( __CLASS__, 'process_lost_password' ), 20 );
28
		add_action( 'wp_loaded', array( __CLASS__, 'process_reset_password' ), 20 );
29
		add_action( 'wp_loaded', array( __CLASS__, 'cancel_order' ), 20 );
30
		add_action( 'wp_loaded', array( __CLASS__, 'order_again' ), 20 );
31
		add_action( 'wp_loaded', array( __CLASS__, 'update_cart_action' ), 20 );
32
		add_action( 'wp_loaded', array( __CLASS__, 'add_to_cart_action' ), 20 );
33
34
		// May need $wp global to access query vars.
35
		add_action( 'wp', array( __CLASS__, 'pay_action' ), 20 );
36
		add_action( 'wp', array( __CLASS__, 'add_payment_method_action' ), 20 );
37
		add_action( 'wp', array( __CLASS__, 'delete_payment_method_action' ), 20 );
38
		add_action( 'wp', array( __CLASS__, 'set_default_payment_method_action' ), 20 );
39
	}
40
41
	/**
42
	 * Save and and update a billing or shipping address if the
43
	 * form was submitted through the user account page.
44
	 */
45
	public static function save_address() {
46
		global $wp;
47
48
		if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
49
			return;
50
		}
51
52 View Code Duplication
		if ( empty( $_POST['action'] ) || 'edit_address' !== $_POST['action'] || empty( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-edit_address' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
53
			return;
54
		}
55
56
		$user_id = get_current_user_id();
57
58
		if ( $user_id <= 0 ) {
59
			return;
60
		}
61
62
		$load_address = isset( $wp->query_vars['edit-address'] ) ? wc_edit_address_i18n( sanitize_title( $wp->query_vars['edit-address'] ), true ) : 'billing';
63
64
		$address = WC()->countries->get_address_fields( esc_attr( $_POST[ $load_address . '_country' ] ), $load_address . '_' );
65
66
		foreach ( $address as $key => $field ) {
67
68
			if ( ! isset( $field['type'] ) ) {
69
				$field['type'] = 'text';
70
			}
71
72
			// Get Value.
73
			switch ( $field['type'] ) {
74
				case 'checkbox' :
75
					$_POST[ $key ] = isset( $_POST[ $key ] ) ? 1 : 0;
76
				break;
77
				default :
78
					$_POST[ $key ] = isset( $_POST[ $key ] ) ? wc_clean( $_POST[ $key ] ) : '';
79
				break;
80
			}
81
82
			// Hook to allow modification of value.
83
			$_POST[ $key ] = apply_filters( 'woocommerce_process_myaccount_field_' . $key, $_POST[ $key ] );
84
85
			// Validation: Required fields.
86
			if ( ! empty( $field['required'] ) && empty( $_POST[ $key ] ) ) {
87
				wc_add_notice( $field['label'] . ' ' . __( 'is a required field.', 'woocommerce' ), 'error' );
88
			}
89
90
			if ( ! empty( $_POST[ $key ] ) ) {
91
92
				// Validation rules
93
				if ( ! empty( $field['validate'] ) && is_array( $field['validate'] ) ) {
94
					foreach ( $field['validate'] as $rule ) {
95
						switch ( $rule ) {
96
							case 'postcode' :
97
								$_POST[ $key ] = strtoupper( str_replace( ' ', '', $_POST[ $key ] ) );
98
99
								if ( ! WC_Validation::is_postcode( $_POST[ $key ], $_POST[ $load_address . '_country' ] ) ) {
100
									wc_add_notice( __( 'Please enter a valid postcode/ZIP.', 'woocommerce' ), 'error' );
101
								} else {
102
									$_POST[ $key ] = wc_format_postcode( $_POST[ $key ], $_POST[ $load_address . '_country' ] );
103
								}
104
							break;
105
							case 'phone' :
106
								$_POST[ $key ] = wc_format_phone_number( $_POST[ $key ] );
107
108
								if ( ! WC_Validation::is_phone( $_POST[ $key ] ) ) {
109
									wc_add_notice( '<strong>' . $field['label'] . '</strong> ' . __( 'is not a valid phone number.', 'woocommerce' ), 'error' );
110
								}
111
							break;
112
							case 'email' :
113
								$_POST[ $key ] = strtolower( $_POST[ $key ] );
114
115
								if ( ! is_email( $_POST[ $key ] ) ) {
116
									wc_add_notice( '<strong>' . $field['label'] . '</strong> ' . __( 'is not a valid email address.', 'woocommerce' ), 'error' );
117
								}
118
							break;
119
						}
120
					}
121
				}
122
			}
123
		}
124
125
		if ( wc_notice_count( 'error' ) == 0 ) {
126
127
			foreach ( $address as $key => $field ) {
128
				update_user_meta( $user_id, $key, $_POST[ $key ] );
129
			}
130
131
			wc_add_notice( __( 'Address changed successfully.', 'woocommerce' ) );
132
133
			do_action( 'woocommerce_customer_save_address', $user_id, $load_address );
134
135
			wp_safe_redirect( wc_get_page_permalink( 'myaccount' ) );
136
			exit;
137
		}
138
	}
139
140
	/**
141
	 * Save the password/account details and redirect back to the my account page.
142
	 */
143
	public static function save_account_details() {
144
145
		if ( 'POST' !== strtoupper( $_SERVER[ 'REQUEST_METHOD' ] ) ) {
146
			return;
147
		}
148
149 View Code Duplication
		if ( empty( $_POST[ 'action' ] ) || 'save_account_details' !== $_POST[ 'action' ] || empty( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'save_account_details' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
150
			return;
151
		}
152
153
		$errors       = new WP_Error();
154
		$user         = new stdClass();
155
156
		$user->ID     = (int) get_current_user_id();
157
		$current_user = get_user_by( 'id', $user->ID );
158
159
		if ( $user->ID <= 0 ) {
160
			return;
161
		}
162
163
		$account_first_name = ! empty( $_POST[ 'account_first_name' ] ) ? wc_clean( $_POST[ 'account_first_name' ] ) : '';
164
		$account_last_name  = ! empty( $_POST[ 'account_last_name' ] ) ? wc_clean( $_POST[ 'account_last_name' ] ) : '';
165
		$account_email      = ! empty( $_POST[ 'account_email' ] ) ? sanitize_email( $_POST[ 'account_email' ] ) : '';
166
		$pass_cur           = ! empty( $_POST[ 'password_current' ] ) ? $_POST[ 'password_current' ] : '';
167
		$pass1              = ! empty( $_POST[ 'password_1' ] ) ? $_POST[ 'password_1' ] : '';
168
		$pass2              = ! empty( $_POST[ 'password_2' ] ) ? $_POST[ 'password_2' ] : '';
169
		$save_pass          = true;
170
171
		$user->first_name   = $account_first_name;
172
		$user->last_name    = $account_last_name;
173
174
		// Prevent emails being displayed, or leave alone.
175
		$user->display_name = is_email( $current_user->display_name ) ? $user->first_name : $current_user->display_name;
176
177
		// Handle required fields
178
		$required_fields = apply_filters( 'woocommerce_save_account_details_required_fields', array(
179
			'account_first_name' => __( 'First Name', 'woocommerce' ),
180
			'account_last_name'  => __( 'Last Name', 'woocommerce' ),
181
			'account_email'      => __( 'Email address', 'woocommerce' ),
182
		) );
183
184
		foreach ( $required_fields as $field_key => $field_name ) {
185
			$value = wc_clean( $_POST[ $field_key ] );
186
			if ( empty( $value ) ) {
187
				wc_add_notice( '<strong>' . esc_html( $field_name ) . '</strong> ' . __( 'is a required field.', 'woocommerce' ), 'error' );
188
			}
189
		}
190
191
		if ( $account_email ) {
192
			if ( ! is_email( $account_email ) ) {
193
				wc_add_notice( __( 'Please provide a valid email address.', 'woocommerce' ), 'error' );
194
			} elseif ( email_exists( $account_email ) && $account_email !== $current_user->user_email ) {
195
				wc_add_notice( __( 'This email address is already registered.', 'woocommerce' ), 'error' );
196
			}
197
			$user->user_email = $account_email;
198
		}
199
200
		if ( ! empty( $pass1 ) && ! wp_check_password( $pass_cur, $current_user->user_pass, $current_user->ID ) ) {
201
			wc_add_notice( __( 'Your current password is incorrect.', 'woocommerce' ), 'error' );
202
			$save_pass = false;
203
		}
204
205
		if ( ! empty( $pass_cur ) && empty( $pass1 ) && empty( $pass2 ) ) {
206
			wc_add_notice( __( 'Please fill out all password fields.', 'woocommerce' ), 'error' );
207
			$save_pass = false;
208 View Code Duplication
		} elseif ( ! empty( $pass1 ) && empty( $pass_cur ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
209
			wc_add_notice( __( 'Please enter your current password.', 'woocommerce' ), 'error' );
210
			$save_pass = false;
211
		} elseif ( ! empty( $pass1 ) && empty( $pass2 ) ) {
212
			wc_add_notice( __( 'Please re-enter your password.', 'woocommerce' ), 'error' );
213
			$save_pass = false;
214 View Code Duplication
		} elseif ( ( ! empty( $pass1 ) || ! empty( $pass2 ) ) && $pass1 !== $pass2 ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
215
			wc_add_notice( __( 'New passwords do not match.', 'woocommerce' ), 'error' );
216
			$save_pass = false;
217
		}
218
219
		if ( $pass1 && $save_pass ) {
220
			$user->user_pass = $pass1;
221
		}
222
223
		// Allow plugins to return their own errors.
224
		do_action_ref_array( 'woocommerce_save_account_details_errors', array( &$errors, &$user ) );
225
226
		if ( $errors->get_error_messages() ) {
227
			foreach ( $errors->get_error_messages() as $error ) {
228
				wc_add_notice( $error, 'error' );
229
			}
230
		}
231
232
		if ( wc_notice_count( 'error' ) === 0 ) {
233
234
			wp_update_user( $user ) ;
235
236
			wc_add_notice( __( 'Account details changed successfully.', 'woocommerce' ) );
237
238
			do_action( 'woocommerce_save_account_details', $user->ID );
239
240
			wp_safe_redirect( wc_get_page_permalink( 'myaccount' ) );
241
			exit;
242
		}
243
	}
244
245
	/**
246
	 * Process the checkout form.
247
	 */
248
	public static function checkout_action() {
249
		if ( isset( $_POST['woocommerce_checkout_place_order'] ) || isset( $_POST['woocommerce_checkout_update_totals'] ) ) {
250
251
			if ( WC()->cart->is_empty() ) {
252
				wp_redirect( wc_get_page_permalink( 'cart' ) );
253
				exit;
254
			}
255
256
			if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) {
257
				define( 'WOOCOMMERCE_CHECKOUT', true );
258
			}
259
260
			WC()->checkout()->process_checkout();
261
		}
262
	}
263
264
	/**
265
	 * Process the pay form.
266
	 */
267
	public static function pay_action() {
268
		global $wp;
269
270
		if ( isset( $_POST['woocommerce_pay'] ) && isset( $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-pay' ) ) {
271
272
			ob_start();
273
274
			// Pay for existing order
275
			$order_key  = $_GET['key'];
276
			$order_id   = absint( $wp->query_vars['order-pay'] );
277
			$order      = wc_get_order( $order_id );
278
279
			if ( $order->id == $order_id && $order->order_key == $order_key && $order->needs_payment() ) {
280
281
				do_action( 'woocommerce_before_pay_action', $order );
282
283
				// Set customer location to order location
284
				if ( $order->billing_country ) {
285
					WC()->customer->set_country( $order->billing_country );
286
				}
287
				if ( $order->billing_state ) {
288
					WC()->customer->set_state( $order->billing_state );
289
				}
290
				if ( $order->billing_postcode ) {
291
					WC()->customer->set_postcode( $order->billing_postcode );
292
				}
293
				if ( $order->billing_city ) {
294
					WC()->customer->set_city( $order->billing_city );
295
				}
296
297
				// Terms
298
				if ( ! empty( $_POST['terms-field'] ) && empty( $_POST['terms'] ) ) {
299
					wc_add_notice( __( 'You must accept our Terms &amp; Conditions.', 'woocommerce' ), 'error' );
300
					return;
301
				}
302
303
				// Update payment method
304
				if ( $order->needs_payment() ) {
305
					$payment_method     = isset( $_POST['payment_method'] ) ? wc_clean( $_POST['payment_method'] ) : false;
306
					$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
307
308
					if ( ! $payment_method ) {
309
						wc_add_notice( __( 'Invalid payment method.', 'woocommerce' ), 'error' );
310
						return;
311
					}
312
313
					// Update meta
314
					update_post_meta( $order_id, '_payment_method', $payment_method );
315
316
					if ( isset( $available_gateways[ $payment_method ] ) ) {
317
						$payment_method_title = $available_gateways[ $payment_method ]->get_title();
318
					} else {
319
						$payment_method_title = '';
320
					}
321
322
					update_post_meta( $order_id, '_payment_method_title', $payment_method_title );
323
324
					// Validate
325
					$available_gateways[ $payment_method ]->validate_fields();
326
327
					// Process
328
					if ( wc_notice_count( 'error' ) == 0 ) {
329
330
						$result = $available_gateways[ $payment_method ]->process_payment( $order_id );
331
332
						// Redirect to success/confirmation/payment page
333
						if ( 'success' === $result['result'] ) {
334
							wp_redirect( $result['redirect'] );
335
							exit;
336
						}
337
					}
338
339
				} else {
340
					// No payment was required for order
341
					$order->payment_complete();
342
					wp_safe_redirect( $order->get_checkout_order_received_url() );
343
					exit;
344
				}
345
346
				do_action( 'woocommerce_after_pay_action', $order );
347
348
			}
349
350
		}
351
	}
352
353
	/**
354
	 * Process the add payment method form.
355
	 */
356
	public static function add_payment_method_action() {
357
		if ( isset( $_POST['woocommerce_add_payment_method'], $_POST['payment_method'], $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-add-payment-method' ) ) {
358
359
			ob_start();
360
361
			$payment_method = wc_clean( $_POST['payment_method'] );
362
363
			$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
364
			// Validate
365
			$available_gateways[ $payment_method ]->validate_fields();
366
367
			// Process
368
			if ( wc_notice_count( 'wc_errors' ) == 0 ) {
369
				$result = $available_gateways[ $payment_method ]->add_payment_method();
370
				// Redirect to success/confirmation/payment page
371
				if ( $result['result'] == 'success' ) {
372
					wc_add_notice( __( 'Payment method added.', 'woocommerce' ) );
373
					wp_redirect( $result['redirect'] );
374
					exit();
375
				}
376
377
			}
378
379
		}
380
381
	}
382
383
	/**
384
	 * Process the delete payment method form.
385
	 */
386 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...
387
		global $wp;
388
389
		if ( isset( $wp->query_vars['delete-payment-method'] ) ) {
390
391
			$token_id = absint( $wp->query_vars['delete-payment-method'] );
392
			$token = WC_Payment_Tokens::get( $token_id );
393
			$delete = true;
394
395
			if ( is_null( $token ) ) {
396
				wc_add_notice( __( 'Invalid payment method', 'woocommerce' ), 'error' );
397
				$delete = false;
398
			}
399
400
			if ( get_current_user_id() !== $token->get_user_id() ) {
401
				wc_add_notice( __( 'Invalid payment method', 'woocommerce' ), 'error' );
402
				$delete = false;
403
			}
404
405
			if ( false === wp_verify_nonce( $_REQUEST['_wpnonce'], 'delete-payment-method-' . $token_id ) ) {
406
				wc_add_notice( __( 'Invalid payment method', 'woocommerce' ), 'error' );
407
				$delete = false;
408
			}
409
410
			if ( $delete ) {
411
				WC_Payment_Tokens::delete( $token_id );
412
				wc_add_notice( __( 'Payment method deleted.', 'woocommerce' ) );
413
			}
414
415
			wp_redirect( wc_get_account_endpoint_url( 'payment-methods' ) );
416
			exit();
417
		}
418
419
	}
420
421
	/**
422
	 * Process the delete payment method form.
423
	 */
424 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...
425
		global $wp;
426
427
		if ( isset( $wp->query_vars['set-default-payment-method'] ) ) {
428
429
			$token_id = absint( $wp->query_vars['set-default-payment-method'] );
430
			$token = WC_Payment_Tokens::get( $token_id );
431
			$delete = true;
432
433
			if ( is_null( $token ) ) {
434
				wc_add_notice( __( 'Invalid payment method', 'woocommerce' ), 'error' );
435
				$delete = false;
436
			}
437
438
			if ( get_current_user_id() !== $token->get_user_id() ) {
439
				wc_add_notice( __( 'Invalid payment method', 'woocommerce' ), 'error' );
440
				$delete = false;
441
			}
442
443
			if ( false === wp_verify_nonce( $_REQUEST['_wpnonce'], 'set-default-payment-method-' . $token_id ) ) {
444
				wc_add_notice( __( 'Invalid payment method', 'woocommerce' ), 'error' );
445
				$delete = false;
446
			}
447
448
			if ( $delete ) {
449
				WC_Payment_Tokens::set_users_default( $token->get_user_id(), intval( $token_id ) );
450
				wc_add_notice( __( 'This payment method was successfully set as your default.', 'woocommerce' ) );
451
			}
452
453
			wp_redirect( wc_get_account_endpoint_url( 'payment-methods' ) );
454
			exit();
455
		}
456
457
	}
458
459
	/**
460
	 * Remove from cart/update.
461
	 */
462
	public static function update_cart_action() {
463
464
		// Add Discount
465
		if ( ! empty( $_POST['apply_coupon'] ) && ! empty( $_POST['coupon_code'] ) ) {
466
			WC()->cart->add_discount( sanitize_text_field( $_POST['coupon_code'] ) );
467
		}
468
469
		// Remove Coupon Codes
470
		elseif ( isset( $_GET['remove_coupon'] ) ) {
471
			WC()->cart->remove_coupon( wc_clean( $_GET['remove_coupon'] ) );
472
		}
473
474
		// Remove from cart
475
		elseif ( ! empty( $_GET['remove_item'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-cart' ) ) {
476
			$cart_item_key = sanitize_text_field( $_GET['remove_item'] );
477
478
			if ( $cart_item = WC()->cart->get_cart_item( $cart_item_key ) ) {
479
				WC()->cart->remove_cart_item( $cart_item_key );
480
481
				$product = wc_get_product( $cart_item['product_id'] );
482
483
				$item_removed_title = apply_filters( 'woocommerce_cart_item_removed_title', $product ? $product->get_title() : __( 'Item', 'woocommerce' ), $cart_item );
484
485
				// Don't show undo link if removed item is out of stock.
486
				if ( $product->is_in_stock() && $product->has_enough_stock( $cart_item['quantity'] ) ) {
487
					$removed_notice  = sprintf( __( '%s removed.', 'woocommerce' ), $item_removed_title );
488
					$removed_notice .= ' <a href="' . esc_url( WC()->cart->get_undo_url( $cart_item_key ) ) . '">' . __( 'Undo?', 'woocommerce' ) . '</a>';
489
				} else {
490
					$removed_notice = sprintf( __( '%s removed.', 'woocommerce' ), $item_removed_title );
491
				}
492
493
				wc_add_notice( $removed_notice );
494
			}
495
496
			$referer  = wp_get_referer() ? remove_query_arg( array( 'remove_item', 'add-to-cart', 'added-to-cart' ), add_query_arg( 'removed_item', '1', wp_get_referer() ) ) : wc_get_cart_url();
497
			wp_safe_redirect( $referer );
498
			exit;
499
		}
500
501
		// Undo Cart Item
502
		elseif ( ! empty( $_GET['undo_item'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-cart' ) ) {
503
			$cart_item_key = sanitize_text_field( $_GET['undo_item'] );
504
505
			WC()->cart->restore_cart_item( $cart_item_key );
506
507
			$referer  = wp_get_referer() ? remove_query_arg( array( 'undo_item', '_wpnonce' ), wp_get_referer() ) : wc_get_cart_url();
508
			wp_safe_redirect( $referer );
509
			exit;
510
		}
511
512
		// Update Cart - checks apply_coupon too because they are in the same form
513
		if ( ( ! empty( $_POST['apply_coupon'] ) || ! empty( $_POST['update_cart'] ) || ! empty( $_POST['proceed'] ) ) && isset( $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-cart' ) ) {
514
515
			$cart_updated = false;
516
			$cart_totals  = isset( $_POST['cart'] ) ? $_POST['cart'] : '';
517
518
			if ( ! WC()->cart->is_empty() && is_array( $cart_totals ) ) {
519
				foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
520
521
					$_product = $values['data'];
522
523
					// Skip product if no updated quantity was posted
524
					if ( ! isset( $cart_totals[ $cart_item_key ] ) || ! isset( $cart_totals[ $cart_item_key ]['qty'] ) ) {
525
						continue;
526
					}
527
528
					// Sanitize
529
					$quantity = apply_filters( 'woocommerce_stock_amount_cart_item', wc_stock_amount( preg_replace( "/[^0-9\.]/", '', $cart_totals[ $cart_item_key ]['qty'] ) ), $cart_item_key );
530
531
					if ( '' === $quantity || $quantity == $values['quantity'] )
532
						continue;
533
534
					// Update cart validation
535
					$passed_validation 	= apply_filters( 'woocommerce_update_cart_validation', true, $cart_item_key, $values, $quantity );
536
537
					// is_sold_individually
538
					if ( $_product->is_sold_individually() && $quantity > 1 ) {
539
						wc_add_notice( sprintf( __( 'You can only have 1 %s in your cart.', 'woocommerce' ), $_product->get_title() ), 'error' );
540
						$passed_validation = false;
541
					}
542
543
					if ( $passed_validation ) {
544
						WC()->cart->set_quantity( $cart_item_key, $quantity, false );
545
						$cart_updated = true;
546
					}
547
548
				}
549
			}
550
551
			// Trigger action - let 3rd parties update the cart if they need to and update the $cart_updated variable
552
			$cart_updated = apply_filters( 'woocommerce_update_cart_action_cart_updated', $cart_updated );
553
554
			if ( $cart_updated ) {
555
				// Recalc our totals
556
				WC()->cart->calculate_totals();
557
			}
558
559
			if ( ! empty( $_POST['proceed'] ) ) {
560
				wp_safe_redirect( wc_get_checkout_url() );
561
				exit;
562
			} elseif ( $cart_updated ) {
563
				wc_add_notice( __( 'Cart updated.', 'woocommerce' ) );
564
				$referer = remove_query_arg( 'remove_coupon', ( wp_get_referer() ? wp_get_referer() : wc_get_cart_url() ) );
565
				wp_safe_redirect( $referer );
566
				exit;
567
			}
568
		}
569
	}
570
571
	/**
572
	 * Place a previous order again.
573
	 */
574
	public static function order_again() {
575
576
		// Nothing to do
577
		if ( ! isset( $_GET['order_again'] ) || ! is_user_logged_in() || ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-order_again' ) ) {
578
			return;
579
		}
580
581
		// Clear current cart
582
		WC()->cart->empty_cart();
583
584
		// Load the previous order - Stop if the order does not exist
585
		$order = wc_get_order( absint( $_GET['order_again'] ) );
586
587
		if ( empty( $order->id ) ) {
588
			return;
589
		}
590
591
		if ( ! $order->has_status( 'completed' ) ) {
592
			return;
593
		}
594
595
		// Make sure the user is allowed to order again. By default it check if the
596
		// previous order belonged to the current user.
597
		if ( ! current_user_can( 'order_again', $order->id ) ) {
598
			return;
599
		}
600
601
		// Copy products from the order to the cart
602
		foreach ( $order->get_items() as $item ) {
603
			// Load all product info including variation data
604
			$product_id   = (int) apply_filters( 'woocommerce_add_to_cart_product_id', $item['product_id'] );
605
			$quantity     = (int) $item['qty'];
606
			$variation_id = (int) $item['variation_id'];
607
			$variations   = array();
608
			$cart_item_data = apply_filters( 'woocommerce_order_again_cart_item_data', array(), $item, $order );
609
610
			foreach ( $item['item_meta'] as $meta_name => $meta_value ) {
611
				if ( taxonomy_is_product_attribute( $meta_name ) ) {
612
					$variations[ $meta_name ] = $meta_value[0];
613
				} elseif ( meta_is_product_attribute( $meta_name, $meta_value[0], $product_id ) ) {
614
					$variations[ $meta_name ] = $meta_value[0];
615
				}
616
			}
617
618
			// Add to cart validation
619
			if ( ! apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations, $cart_item_data ) ) {
620
				continue;
621
			}
622
623
			WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations, $cart_item_data );
624
		}
625
626
		do_action( 'woocommerce_ordered_again', $order->id );
627
628
		// Redirect to cart
629
		wc_add_notice( __( 'The cart has been filled with the items from your previous order.', 'woocommerce' ) );
630
		wp_safe_redirect( wc_get_cart_url() );
631
		exit;
632
	}
633
634
	/**
635
	 * Cancel a pending order.
636
	 */
637
	public static function cancel_order() {
638
		if ( isset( $_GET['cancel_order'] ) && isset( $_GET['order'] ) && isset( $_GET['order_id'] ) ) {
639
640
			$order_key        = $_GET['order'];
641
			$order_id         = absint( $_GET['order_id'] );
642
			$order            = wc_get_order( $order_id );
643
			$user_can_cancel  = current_user_can( 'cancel_order', $order_id );
644
			$order_can_cancel = $order->has_status( apply_filters( 'woocommerce_valid_order_statuses_for_cancel', array( 'pending', 'failed' ) ) );
645
			$redirect         = $_GET['redirect'];
646
647
			if ( $order->has_status( 'cancelled' ) ) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
648
				// Already cancelled - take no action
649
			} elseif ( $user_can_cancel && $order_can_cancel && $order->id === $order_id && $order->order_key === $order_key ) {
650
651
				// Cancel the order + restore stock
652
				$order->cancel_order( __('Order cancelled by customer.', 'woocommerce' ) );
653
654
				// Message
655
				wc_add_notice( apply_filters( 'woocommerce_order_cancelled_notice', __( 'Your order was cancelled.', 'woocommerce' ) ), apply_filters( 'woocommerce_order_cancelled_notice_type', 'notice' ) );
656
657
				do_action( 'woocommerce_cancelled_order', $order->id );
658
659
			} elseif ( $user_can_cancel && ! $order_can_cancel ) {
660
				wc_add_notice( __( 'Your order can no longer be cancelled. Please contact us if you need assistance.', 'woocommerce' ), 'error' );
661
			} else {
662
				wc_add_notice( __( 'Invalid order.', 'woocommerce' ), 'error' );
663
			}
664
665
			if ( $redirect ) {
666
				wp_safe_redirect( $redirect );
667
				exit;
668
			}
669
		}
670
	}
671
672
	/**
673
	 * Add to cart action.
674
	 *
675
	 * Checks for a valid request, does validation (via hooks) and then redirects if valid.
676
	 *
677
	 * @param bool $url (default: false)
678
	 */
679
	public static function add_to_cart_action( $url = false ) {
680
		if ( empty( $_REQUEST['add-to-cart'] ) || ! is_numeric( $_REQUEST['add-to-cart'] ) ) {
681
			return;
682
		}
683
684
		$product_id          = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_REQUEST['add-to-cart'] ) );
685
		$was_added_to_cart   = false;
686
		$adding_to_cart      = wc_get_product( $product_id );
687
688
		if ( ! $adding_to_cart ) {
689
			return;
690
		}
691
692
		$add_to_cart_handler = apply_filters( 'woocommerce_add_to_cart_handler', $adding_to_cart->product_type, $adding_to_cart );
693
694
		// Variable product handling
695
		if ( 'variable' === $add_to_cart_handler ) {
696
			$was_added_to_cart = self::add_to_cart_handler_variable( $product_id );
697
698
		// Grouped Products
699
		} elseif ( 'grouped' === $add_to_cart_handler ) {
700
			$was_added_to_cart = self::add_to_cart_handler_grouped( $product_id );
701
702
		// Custom Handler
703
		} elseif ( has_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler ) ){
704
			do_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler, $url );
705
706
		// Simple Products
707
		} else {
708
			$was_added_to_cart = self::add_to_cart_handler_simple( $product_id );
709
		}
710
711
		// If we added the product to the cart we can now optionally do a redirect.
712
		if ( $was_added_to_cart && wc_notice_count( 'error' ) === 0 ) {
713
			// If has custom URL redirect there
714
			if ( $url = apply_filters( 'woocommerce_add_to_cart_redirect', $url ) ) {
715
				wp_safe_redirect( $url );
716
				exit;
717
			} elseif ( get_option( 'woocommerce_cart_redirect_after_add' ) === 'yes' ) {
718
				wp_safe_redirect( wc_get_cart_url() );
719
				exit;
720
			}
721
		}
722
	}
723
724
	/**
725
	 * Handle adding simple products to the cart.
726
	 * @since 2.4.6 Split from add_to_cart_action
727
	 * @param int $product_id
728
	 * @return bool success or not
729
	 */
730
	private static function add_to_cart_handler_simple( $product_id ) {
731
		$quantity 			= empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
732
		$passed_validation 	= apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
733
734 View Code Duplication
		if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity ) !== false ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
735
			wc_add_to_cart_message( array( $product_id => $quantity ), true );
736
			return true;
737
		}
738
		return false;
739
	}
740
741
	/**
742
	 * Handle adding grouped products to the cart.
743
	 * @since 2.4.6 Split from add_to_cart_action
744
	 * @param int $product_id
745
	 * @return bool success or not
746
	 */
747
	private static function add_to_cart_handler_grouped( $product_id ) {
748
		$was_added_to_cart = false;
749
		$added_to_cart     = array();
750
751
		if ( ! empty( $_REQUEST['quantity'] ) && is_array( $_REQUEST['quantity'] ) ) {
752
			$quantity_set = false;
753
754
			foreach ( $_REQUEST['quantity'] as $item => $quantity ) {
755
				if ( $quantity <= 0 ) {
756
					continue;
757
				}
758
				$quantity_set = true;
759
760
				// Add to cart validation
761
				$passed_validation 	= apply_filters( 'woocommerce_add_to_cart_validation', true, $item, $quantity );
762
763
				if ( $passed_validation && WC()->cart->add_to_cart( $item, $quantity ) !== false ) {
764
					$was_added_to_cart = true;
765
					$added_to_cart[ $item ] = $quantity;
766
				}
767
			}
768
769
			if ( ! $was_added_to_cart && ! $quantity_set ) {
770
				wc_add_notice( __( 'Please choose the quantity of items you wish to add to your cart&hellip;', 'woocommerce' ), 'error' );
771
			} elseif ( $was_added_to_cart ) {
772
				wc_add_to_cart_message( $added_to_cart );
773
				return true;
774
			}
775
776
		} elseif ( $product_id ) {
777
			/* Link on product archives */
778
			wc_add_notice( __( 'Please choose a product to add to your cart&hellip;', 'woocommerce' ), 'error' );
779
		}
780
		return false;
781
	}
782
783
	/**
784
	 * Handle adding variable products to the cart.
785
	 * @since 2.4.6 Split from add_to_cart_action
786
	 * @param int $product_id
787
	 * @return bool success or not
788
	 */
789
	private static function add_to_cart_handler_variable( $product_id ) {
790
		$adding_to_cart     = wc_get_product( $product_id );
791
		$variation_id       = empty( $_REQUEST['variation_id'] ) ? '' : absint( $_REQUEST['variation_id'] );
792
		$quantity           = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
793
		$missing_attributes = array();
794
		$variations         = array();
795
		$attributes         = $adding_to_cart->get_attributes();
796
797
		// If no variation ID is set, attempt to get a variation ID from posted attributes.
798
		if ( empty( $variation_id ) ) {
799
			$variation_id = $adding_to_cart->get_matching_variation( wp_unslash( $_POST ) );
800
		}
801
802
		$variation = wc_get_product( $variation_id );
803
804
		// Verify all attributes
805
		foreach ( $attributes as $attribute ) {
806
			if ( ! $attribute['is_variation'] ) {
807
				continue;
808
			}
809
810
			$taxonomy = 'attribute_' . sanitize_title( $attribute['name'] );
811
812
			if ( isset( $_REQUEST[ $taxonomy ] ) ) {
813
814
				// Get value from post data
815
				if ( $attribute['is_taxonomy'] ) {
816
					// Don't use wc_clean as it destroys sanitized characters
817
					$value = sanitize_title( stripslashes( $_REQUEST[ $taxonomy ] ) );
818
				} else {
819
					$value = wc_clean( stripslashes( $_REQUEST[ $taxonomy ] ) );
820
				}
821
822
				// Get valid value from variation
823
				$valid_value = isset( $variation->variation_data[ $taxonomy ] ) ? $variation->variation_data[ $taxonomy ] : '';
824
825
				// Allow if valid
826
				if ( '' === $valid_value || $valid_value === $value ) {
827
					$variations[ $taxonomy ] = $value;
828
					continue;
829
				}
830
831
			} else {
832
				$missing_attributes[] = wc_attribute_label( $attribute['name'] );
833
			}
834
		}
835
836
		if ( $missing_attributes ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $missing_attributes 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...
837
			wc_add_notice( sprintf( _n( '%s is a required field', '%s are required fields', sizeof( $missing_attributes ), 'woocommerce' ), wc_format_list_of_items( $missing_attributes ) ), 'error' );
838
		} elseif ( empty( $variation_id ) ) {
839
			wc_add_notice( __( 'Please choose product options&hellip;', 'woocommerce' ), 'error' );
840
		} else {
841
			// Add to cart validation
842
			$passed_validation 	= apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations );
843
844 View Code Duplication
			if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) !== false ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
845
				wc_add_to_cart_message( array( $product_id => $quantity ), true );
846
				return true;
847
			}
848
		}
849
		return false;
850
	}
851
852
	/**
853
	 * Process the login form.
854
	 */
855
	public static function process_login() {
856
		if ( ! empty( $_POST['login'] ) && ! empty( $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-login' ) ) {
857
858
			try {
859
				$creds    = array();
860
				$username = trim( $_POST['username'] );
861
862
				$validation_error = new WP_Error();
863
				$validation_error = apply_filters( 'woocommerce_process_login_errors', $validation_error, $_POST['username'], $_POST['password'] );
864
865
				if ( $validation_error->get_error_code() ) {
866
					throw new Exception( '<strong>' . __( 'Error', 'woocommerce' ) . ':</strong> ' . $validation_error->get_error_message() );
867
				}
868
869 View Code Duplication
				if ( empty( $username ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
870
					throw new Exception( '<strong>' . __( 'Error', 'woocommerce' ) . ':</strong> ' . __( 'Username is required.', 'woocommerce' ) );
871
				}
872
873 View Code Duplication
				if ( empty( $_POST['password'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
874
					throw new Exception( '<strong>' . __( 'Error', 'woocommerce' ) . ':</strong> ' . __( 'Password is required.', 'woocommerce' ) );
875
				}
876
877
				if ( is_email( $username ) && apply_filters( 'woocommerce_get_username_from_email', true ) ) {
878
					$user = get_user_by( 'email', $username );
879
880
					if ( isset( $user->user_login ) ) {
881
						$creds['user_login'] = $user->user_login;
882
					} else {
883
						throw new Exception( '<strong>' . __( 'Error', 'woocommerce' ) . ':</strong> ' . __( 'A user could not be found with this email address.', 'woocommerce' ) );
884
					}
885
886
				} else {
887
					$creds['user_login'] = $username;
888
				}
889
890
				$creds['user_password'] = $_POST['password'];
891
				$creds['remember']      = isset( $_POST['rememberme'] );
892
				$secure_cookie          = is_ssl() ? true : false;
893
				$user                   = wp_signon( apply_filters( 'woocommerce_login_credentials', $creds ), $secure_cookie );
894
895
				if ( is_wp_error( $user ) ) {
896
					$message = $user->get_error_message();
897
					$message = str_replace( '<strong>' . esc_html( $creds['user_login'] ) . '</strong>', '<strong>' . esc_html( $username ) . '</strong>', $message );
898
					throw new Exception( $message );
899
				} else {
900
901
					if ( ! empty( $_POST['redirect'] ) ) {
902
						$redirect = $_POST['redirect'];
903
					} elseif ( wp_get_referer() ) {
904
						$redirect = wp_get_referer();
905
					} else {
906
						$redirect = wc_get_page_permalink( 'myaccount' );
907
					}
908
909
					wp_redirect( apply_filters( 'woocommerce_login_redirect', $redirect, $user ) );
910
					exit;
911
				}
912
913
			} catch ( Exception $e ) {
914
				wc_add_notice( apply_filters('login_errors', $e->getMessage() ), 'error' );
915
			}
916
		}
917
	}
918
919
	/**
920
	 * Handle lost password form.
921
	 */
922
	public static function process_lost_password() {
923
		if ( isset( $_POST['wc_reset_password'] ) && isset( $_POST['user_login'] ) && isset( $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'lost_password' ) ) {
924
			$success = WC_Shortcode_My_Account::retrieve_password();
925
926
			// If successful, redirect to my account with query arg set
927
			if ( $success ) {
928
				wp_redirect( add_query_arg( 'reset-link-sent', 'true', remove_query_arg( array( 'key', 'login', 'reset' ) ) ) );
929
				exit;
930
			}
931
		}
932
	}
933
934
	/**
935
	 * Handle reset password form.
936
	 */
937
	public static function process_reset_password() {
938
		$posted_fields = array( 'wc_reset_password', 'password_1', 'password_2', 'reset_key', 'reset_login', '_wpnonce' );
939
940
		foreach ( $posted_fields as $field ) {
941
			if ( ! isset( $_POST[ $field ] ) ) {
942
				return;
943
			}
944
			$posted_fields[ $field ] = $_POST[ $field ];
945
		}
946
947
		if ( ! wp_verify_nonce( $posted_fields['_wpnonce'], 'reset_password' ) ) {
948
			return;
949
		}
950
951
		$user = WC_Shortcode_My_Account::check_password_reset_key( $posted_fields['reset_key'], $posted_fields['reset_login'] );
952
953
		if ( $user instanceof WP_User ) {
954
			if ( empty( $posted_fields['password_1'] ) ) {
955
				wc_add_notice( __( 'Please enter your password.', 'woocommerce' ), 'error' );
956
			}
957
958
			if ( $posted_fields[ 'password_1' ] !== $posted_fields[ 'password_2' ] ) {
959
				wc_add_notice( __( 'Passwords do not match.', 'woocommerce' ), 'error' );
960
			}
961
962
			$errors = new WP_Error();
963
964
			do_action( 'validate_password_reset', $errors, $user );
965
966
			wc_add_wp_error_notices( $errors );
967
968
			if ( 0 === wc_notice_count( 'error' ) ) {
969
				WC_Shortcode_My_Account::reset_password( $user, $posted_fields['password_1'] );
970
971
				do_action( 'woocommerce_customer_reset_password', $user );
972
973
				wp_redirect( add_query_arg( 'reset', 'true', remove_query_arg( array( 'key', 'login', 'reset-link-sent' ) ) ) );
974
				exit;
975
			}
976
		}
977
	}
978
979
	/**
980
	 * Process the registration form.
981
	 */
982
	public static function process_registration() {
983
		if ( ! empty( $_POST['register'] ) && isset( $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-register' ) ) {
984
			$username = 'no' === get_option( 'woocommerce_registration_generate_username' ) ? $_POST['username'] : '';
985
			$password = 'no' === get_option( 'woocommerce_registration_generate_password' ) ? $_POST['password'] : '';
986
			$email    = $_POST['email'];
987
988
			try {
989
				$validation_error = new WP_Error();
990
				$validation_error = apply_filters( 'woocommerce_process_registration_errors', $validation_error, $username, $password, $email );
991
992
				if ( $validation_error->get_error_code() ) {
993
					throw new Exception( $validation_error->get_error_message() );
994
				}
995
996
				// Anti-spam trap
997
				if ( ! empty( $_POST['email_2'] ) ) {
998
					throw new Exception( __( 'Anti-spam field was filled in.', 'woocommerce' ) );
999
				}
1000
1001
				$new_customer = wc_create_new_customer( sanitize_email( $email ), wc_clean( $username ), $password );
1002
1003
				if ( is_wp_error( $new_customer ) ) {
1004
					throw new Exception( $new_customer->get_error_message() );
1005
				}
1006
1007
				if ( apply_filters( 'woocommerce_registration_auth_new_customer', true, $new_customer ) ) {
1008
					wc_set_customer_auth_cookie( $new_customer );
1009
				}
1010
1011
				wp_safe_redirect( apply_filters( 'woocommerce_registration_redirect', wp_get_referer() ? wp_get_referer() : wc_get_page_permalink( 'myaccount' ) ) );
1012
				exit;
1013
1014
			} catch ( Exception $e ) {
1015
				wc_add_notice( '<strong>' . __( 'Error', 'woocommerce' ) . ':</strong> ' . $e->getMessage(), 'error' );
1016
			}
1017
		}
1018
	}
1019
}
1020
1021
WC_Form_Handler::init();
1022