Completed
Push — master ( 45f118...bcc91e )
by Devin
17:37 queued 14:12
created

  B

Complexity

Conditions 6
Paths 4

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 8
nc 4
nop 2
dl 0
loc 18
rs 8.8571
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 26 and the first side effect is on line 14.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Process Donation
4
 *
5
 * @package     Give
6
 * @subpackage  Functions
7
 * @copyright   Copyright (c) 2016, WordImpress
8
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
9
 * @since       1.0
10
 */
11
12
// Exit if accessed directly.
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Process Donation Form
19
 *
20
 * Handles the donation form process.
21
 *
22
 * @access      private
23
 * @since       1.0
24
 * @return      false|null
25
 */
26
function give_process_donation_form() {
27
28
	/**
29
	 * Fires before processing the donation form.
30
	 *
31
	 * @since 1.0
32
	 */
33
	do_action( 'give_pre_process_donation' );
34
35
	// Validate the form $_POST data
36
	$valid_data = give_purchase_form_validate_fields();
37
38
	/**
39
	 * Fires after validating donation form fields.
40
	 *
41
	 * Allow you to hook to donation form errors.
42
	 *
43
	 * @since 1.0
44
	 *
45
	 * @param bool|array $valid_data Validate fields.
46
	 * @param array $_POST Array of variables passed via the HTTP POST.
47
	 */
48
	do_action( 'give_checkout_error_checks', $valid_data, $_POST );
49
50
	$is_ajax = isset( $_POST['give_ajax'] );
51
52
	// Process the login form
53
	if ( isset( $_POST['give_login_submit'] ) ) {
54
		give_process_form_login();
55
	}
56
57
	// Validate the user
58
	$user = give_get_purchase_form_user( $valid_data );
59
60
	if ( false === $valid_data || give_get_errors() || ! $user ) {
61
		if ( $is_ajax ) {
62
			/**
63
			 * Fires when AJAX sends back errors from the donation form.
64
			 *
65
			 * @since 1.0
66
			 */
67
			do_action( 'give_ajax_donation_errors' );
68
			give_die();
69
		} else {
70
			return false;
71
		}
72
	}
73
74
	// If AJAX send back success to proceed with form submission
75
	if ( $is_ajax ) {
76
		echo 'success';
77
		give_die();
78
	}
79
80
	// After AJAX: Setup session if not using php_sessions
81
	if ( ! Give()->session->use_php_sessions() ) {
82
		// Double-check that set_cookie is publicly accessible;
83
		// we're using a slightly modified class-wp-sessions.php
84
		$session_reflection = new ReflectionMethod( 'WP_Session', 'set_cookie' );
85
		if ( $session_reflection->isPublic() ) {
86
			// Manually set the cookie.
87
			Give()->session->init()->set_cookie();
0 ignored issues
show
Bug introduced by
The method set_cookie cannot be called on Give()->session->init() (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
88
		}
89
	}
90
91
	// Setup user information
92
	$user_info = array(
93
		'id'         => $user['user_id'],
94
		'email'      => $user['user_email'],
95
		'first_name' => $user['user_first'],
96
		'last_name'  => $user['user_last'],
97
		'address'    => $user['address'],
98
	);
99
100
	$auth_key = defined( 'AUTH_KEY' ) ? AUTH_KEY : '';
101
102
	$price        = isset( $_POST['give-amount'] ) ? (float) apply_filters( 'give_donation_total', give_sanitize_amount( give_format_amount( $_POST['give-amount'] ) ) ) : '0.00';
103
	$purchase_key = strtolower( md5( $user['user_email'] . date( 'Y-m-d H:i:s' ) . $auth_key . uniqid( 'give', true ) ) );
104
105
	// Setup donation information
106
	$purchase_data = array(
107
		'price'        => $price,
108
		'purchase_key' => $purchase_key,
109
		'user_email'   => $user['user_email'],
110
		'date'         => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
111
		'user_info'    => stripslashes_deep( $user_info ),
112
		'post_data'    => $_POST,
113
		'gateway'      => $valid_data['gateway'],
114
		'card_info'    => $valid_data['cc_info'],
115
	);
116
117
	// Add the user data for hooks
118
	$valid_data['user'] = $user;
119
120
	/**
121
	 * Fires before donation form gateway.
122
	 *
123
	 * Allow you to hook to donation form before the gateway.
124
	 *
125
	 * @since 1.0
126
	 *
127
	 * @param array $_POST Array of variables passed via the HTTP POST.
128
	 * @param array $user_info Array containing basic user information.
129
	 * @param bool|array $valid_data Validate fields.
130
	 */
131
	do_action( 'give_checkout_before_gateway', $_POST, $user_info, $valid_data );
132
133
	// Sanity check for price
134
	if ( ! $purchase_data['price'] ) {
135
		// Revert to manual
136
		$purchase_data['gateway'] = 'manual';
137
		$_POST['give-gateway']    = 'manual';
138
	}
139
140
	/**
141
	 * Allow the purchase data to be modified before it is sent to the gateway
142
	 *
143
	 * @since 1.7
144
	 */
145
	$purchase_data = apply_filters( 'give_donation_data_before_gateway', $purchase_data, $valid_data );
146
147
	// Setup the data we're storing in the donation session
148
	$session_data = $purchase_data;
149
150
	// Make sure credit card numbers are never stored in sessions
151
	unset( $session_data['card_info']['card_number'] );
152
	unset( $session_data['post_data']['card_number'] );
153
154
	// Used for showing data to non logged-in users after donation, and for other plugins needing donation data.
155
	give_set_purchase_session( $session_data );
156
157
	// Send info to the gateway for payment processing
158
	give_send_to_gateway( $purchase_data['gateway'], $purchase_data );
159
	give_die();
160
161
}
162
163
add_action( 'give_purchase', 'give_process_donation_form' );
164
add_action( 'wp_ajax_give_process_donation', 'give_process_donation_form' );
165
add_action( 'wp_ajax_nopriv_give_process_donation', 'give_process_donation_form' );
166
167
168
/**
169
 * Verify that when a logged in user makes a donation that the email address used doesn't belong to a different customer
170
 *
171
 * @since  1.7
172
 *
173
 * @param  array $valid_data Validated data submitted for the purchase
174
 * @param  array $post Additional $_POST data submitted
175
 *
176
 * @return void
177
 */
178
function give_check_logged_in_user_for_existing_email( $valid_data, $post ) {
0 ignored issues
show
Unused Code introduced by
The parameter $post is not used and could be removed.

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

Loading history...
179
180
	// Verify that the email address belongs to this customer.
181
	if ( is_user_logged_in() ) {
182
183
		$submitted_email    = $valid_data['logged_in_user']['user_email'];
184
		$customer = new Give_Customer( get_current_user_id(), true );
185
186
		// If this email address is not registered with this customer, see if it belongs to any other customer
187
		if (
188
			$submitted_email !== $customer->email
189
			&& ( is_array( $customer->emails ) && ! in_array( $submitted_email, $customer->emails ) )
190
		) {
191
			$found_customer = new Give_Customer( $submitted_email );
192
193
			if ( $found_customer->id > 0 ) {
194
				give_set_error( 'give-customer-email-exists', sprintf(__('You are logged in as %1$s, and are submitting a donation as %2$s, which is an existing donor. To ensure that the email address is tied to the correct donor, please submit this donation from a logged-out browser, or choose another email address.'), $customer->email, $submitted_email) );
195
			}
196
		}
197
	}
198
}
199
200
add_action( 'give_checkout_error_checks', 'give_check_logged_in_user_for_existing_email', 10, 2 );
201
202
/**
203
 * Process the checkout login form
204
 *
205
 * @access      private
206
 * @since       1.0
207
 * @return      void
208
 */
209
function give_process_form_login() {
210
211
	$is_ajax = isset( $_POST['give_ajax'] );
212
213
	$user_data = give_purchase_form_validate_user_login();
214
215
	if ( give_get_errors() || $user_data['user_id'] < 1 ) {
216
		if ( $is_ajax ) {
217
			/**
218
			 * Fires when AJAX sends back errors from the donation form.
219
			 *
220
			 * @since 1.0
221
			 */
222
			do_action( 'give_ajax_donation_errors' );
223
			give_die();
224
		} else {
225
			wp_redirect( $_SERVER['HTTP_REFERER'] );
226
			exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The function give_process_form_login() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
227
		}
228
	}
229
230
	give_log_user_in( $user_data['user_id'], $user_data['user_login'], $user_data['user_pass'] );
231
232
	if ( $is_ajax ) {
233
		echo 'success';
234
		give_die();
235
	} else {
236
		wp_redirect( $_SERVER['HTTP_REFERER'] );
237
	}
238
}
239
240
add_action( 'wp_ajax_give_process_donation_login', 'give_process_form_login' );
241
add_action( 'wp_ajax_nopriv_give_process_donation_login', 'give_process_form_login' );
242
243
/**
244
 * Donation Form Validate Fields
245
 *
246
 * @access      private
247
 * @since       1.0
248
 * @return      bool|array
249
 */
250
function give_purchase_form_validate_fields() {
251
252
	// Check if there is $_POST
253
	if ( empty( $_POST ) ) {
254
		return false;
255
	}
256
257
	$form_id = isset( $_POST['give-form-id'] ) ? $_POST['give-form-id'] : '';
258
259
	// Start an array to collect valid data
260
	$valid_data = array(
261
		'gateway'          => give_purchase_form_validate_gateway(), // Gateway fallback (amount is validated here)
262
		'need_new_user'    => false,     // New user flag
263
		'need_user_login'  => false,     // Login user flag
264
		'logged_user_data' => array(),   // Logged user collected data
265
		'new_user_data'    => array(),   // New user collected data
266
		'login_user_data'  => array(),   // Login user collected data
267
		'guest_user_data'  => array(),   // Guest user collected data
268
		'cc_info'          => give_purchase_form_validate_cc(),// Credit card info
269
	);
270
271
	// Validate Honeypot First
272
	if ( ! empty( $_POST['give-honeypot'] ) ) {
273
		give_set_error( 'invalid_honeypot', esc_html__( 'Honeypot field detected. Go away bad bot!', 'give' ) );
274
	}
275
276
	// Validate agree to terms
277
	if ( give_is_terms_enabled( $form_id ) ) {
278
		give_purchase_form_validate_agree_to_terms();
279
	}
280
281
	// Stop processing donor registration, if donor registration is optional and donor can do guest checkout.
282
	// If registration form username field is empty that means donor do not want to registration instead want guest checkout.
283
	if (
284
		! give_logged_in_only( $form_id )
285
		&& isset( $_POST['give-purchase-var'] )
286
		&& $_POST['give-purchase-var'] == 'needs-to-register'
287
		&& empty( $_POST['give_user_login'] )
288
	) {
289
		unset( $_POST['give-purchase-var'] );
290
	}
291
292
	if ( is_user_logged_in() ) {
293
		// Collect logged in user data
294
		$valid_data['logged_in_user'] = give_purchase_form_validate_logged_in_user();
295
	} elseif ( isset( $_POST['give-purchase-var'] ) && $_POST['give-purchase-var'] == 'needs-to-register' ) {
296
		// Set new user registration as required
297
		$valid_data['need_new_user'] = true;
298
		// Validate new user data
299
		$valid_data['new_user_data'] = give_purchase_form_validate_new_user();
300
		// Check if login validation is needed
301
	} elseif ( isset( $_POST['give-purchase-var'] ) && $_POST['give-purchase-var'] == 'needs-to-login' ) {
302
		// Set user login as required
303
		$valid_data['need_user_login'] = true;
304
		// Validate users login info
305
		$valid_data['login_user_data'] = give_purchase_form_validate_user_login();
306
	} else {
307
		// Not registering or logging in, so setup guest user data
308
		$valid_data['guest_user_data'] = give_purchase_form_validate_guest_user();
309
	}
310
311
	// Return collected data
312
	return $valid_data;
313
}
314
315
/**
316
 * Donation Form Validate Gateway
317
 *
318
 * Validate the gateway and donation amount
319
 *
320
 * @access      private
321
 * @since       1.0
322
 * @return      string
323
 */
324
function give_purchase_form_validate_gateway() {
325
326
	$form_id = isset( $_REQUEST['give-form-id'] ) ? $_REQUEST['give-form-id'] : 0;
327
	$amount  = isset( $_REQUEST['give-amount'] ) ? give_sanitize_amount( $_REQUEST['give-amount'] ) : 0;
328
	$gateway = give_get_default_gateway( $form_id );
329
330
	// Check if a gateway value is present
331
	if ( ! empty( $_REQUEST['give-gateway'] ) ) {
332
333
		$gateway = sanitize_text_field( $_REQUEST['give-gateway'] );
334
335
		// Is amount being donated in LIVE mode 0.00? If so, error:
336
		if ( $amount == 0 && ! give_is_test_mode() ) {
337
338
			give_set_error( 'invalid_donation_amount', esc_html__( 'Please insert a valid donation amount.', 'give' ) );
339
340
		} //Check for a minimum custom amount
341
		elseif ( ! give_verify_minimum_price() ) {
342
			// translators: %s: minimum donation amount.
343
			give_set_error(
344
				'invalid_donation_minimum',
345
				sprintf(
346
				/* translators: %s: minimum donation amount */
347
					esc_html__( 'This form has a minimum donation amount of %s.', 'give' ),
348
					give_currency_filter( give_format_amount( give_get_form_minimum_price( $form_id ) ) )
349
				)
350
			);
351
352
		} //Is this test mode zero donation? Let it through but set to manual gateway.
353
		elseif ( $amount == 0 && give_is_test_mode() ) {
354
355
			$gateway = 'manual';
356
357
		} //Check if this gateway is active.
358
		elseif ( ! give_is_gateway_active( $gateway ) ) {
359
360
			give_set_error( 'invalid_gateway', esc_html__( 'The selected payment gateway is not enabled.', 'give' ) );
361
362
		}
363
	}
364
365
	return $gateway;
366
367
}
368
369
/**
370
 * Donation Form Validate Minimum Donation Amount
371
 *
372
 * @access      private
373
 * @since       1.3.6
374
 * @return      bool
375
 */
376
function give_verify_minimum_price() {
377
378
	$amount          = give_sanitize_amount( $_REQUEST['give-amount'] );
379
	$form_id         = isset( $_REQUEST['give-form-id'] ) ? $_REQUEST['give-form-id'] : 0;
380
	$price_id        = isset( $_REQUEST['give-price-id'] ) ? $_REQUEST['give-price-id'] : 0;
381
	$variable_prices = give_has_variable_prices( $form_id );
382
383
	if ( $variable_prices && ! empty( $price_id ) ) {
384
385
		$price_level_amount = give_get_price_option_amount( $form_id, $price_id );
386
387
		if ( $price_level_amount == $amount ) {
388
			return true;
389
		}
390
	}
391
392
	$minimum = give_get_form_minimum_price( $form_id );
393
394
	if ( $minimum > $amount ) {
395
		return false;
396
	}
397
398
	return true;
399
}
400
401
/**
402
 * Donation form validate agree to "Terms and Conditions".
403
 *
404
 * @access      private
405
 * @since       1.0
406
 * @return      void
407
 */
408
function give_purchase_form_validate_agree_to_terms() {
409
	// Validate agree to terms.
410
	if ( ! isset( $_POST['give_agree_to_terms'] ) || $_POST['give_agree_to_terms'] != 1 ) {
411
		// User did not agree.
412
		give_set_error( 'agree_to_terms', apply_filters( 'give_agree_to_terms_text', esc_html__( 'You must agree to the terms and conditions.', 'give' ) ) );
413
	}
414
}
415
416
/**
417
 * Donation Form Required Fields.
418
 *
419
 * @access      private
420
 * @since       1.0
421
 *
422
 * @param       $form_id
423
 *
424
 * @return      array
425
 */
426
function give_get_required_fields( $form_id ) {
427
428
	$payment_mode = give_get_chosen_gateway( $form_id );
429
430
	$required_fields = array(
431
		'give_email' => array(
432
			'error_id'      => 'invalid_email',
433
			'error_message' => esc_html__( 'Please enter a valid email address.', 'give' ),
434
		),
435
		'give_first' => array(
436
			'error_id'      => 'invalid_first_name',
437
			'error_message' => esc_html__( 'Please enter your first name.', 'give' ),
438
		),
439
	);
440
441
	$require_address = give_require_billing_address( $payment_mode );
442
443
	if ( $require_address ) {
444
		$required_fields['card_address']    = array(
445
			'error_id'      => 'invalid_card_address',
446
			'error_message' => esc_html__( 'Please enter your primary billing address.', 'give' ),
447
		);
448
		$required_fields['card_zip']        = array(
449
			'error_id'      => 'invalid_zip_code',
450
			'error_message' => esc_html__( 'Please enter your zip / postal code.', 'give' ),
451
		);
452
		$required_fields['card_city']       = array(
453
			'error_id'      => 'invalid_city',
454
			'error_message' => esc_html__( 'Please enter your billing city.', 'give' ),
455
		);
456
		$required_fields['billing_country'] = array(
457
			'error_id'      => 'invalid_country',
458
			'error_message' => esc_html__( 'Please select your billing country.', 'give' ),
459
		);
460
		$required_fields['card_state']      = array(
461
			'error_id'      => 'invalid_state',
462
			'error_message' => esc_html__( 'Please enter billing state / province.', 'give' ),
463
		);
464
	}
465
466
	/**
467
	 * Filters the donation form required field.
468
	 *
469
	 * @since 1.7
470
	 */
471
	$required_fields = apply_filters( 'give_donation_form_required_fields', $required_fields, $form_id );
472
473
	return $required_fields;
474
475
}
476
477
/**
478
 * Check if the Billing Address is required
479
 *
480
 * @since  1.0.1
481
 *
482
 * @param string $payment_mode
483
 *
484
 * @return mixed|void
485
 */
486
function give_require_billing_address( $payment_mode ) {
487
488
	$return = false;
489
490
	if ( isset( $_POST['billing_country'] ) || did_action( "give_{$payment_mode}_cc_form" ) || did_action( 'give_cc_form' ) ) {
491
		$return = true;
492
	}
493
494
	// Let payment gateways and other extensions determine if address fields should be required.
495
	return apply_filters( 'give_require_billing_address', $return );
496
497
}
498
499
/**
500
 * Donation Form Validate Logged In User
501
 *
502
 * @access      private
503
 * @since       1.0
504
 * @return      array
505
 */
506
function give_purchase_form_validate_logged_in_user() {
507
	global $user_ID;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
508
509
	$form_id = isset( $_POST['give-form-id'] ) ? $_POST['give-form-id'] : '';
510
511
	// Start empty array to collect valid user data.
512
	$valid_user_data = array(
513
		// Assume there will be errors.
514
		'user_id' => - 1,
515
	);
516
517
	// Verify there is a user_ID.
518
	if ( $user_ID > 0 ) {
519
		// Get the logged in user data.
520
		$user_data = get_userdata( $user_ID );
521
522
		// Loop through required fields and show error messages.
523
		foreach ( give_get_required_fields( $form_id ) as $field_name => $value ) {
524
			if ( in_array( $value, give_get_required_fields( $form_id ) ) && empty( $_POST[ $field_name ] ) ) {
525
				give_set_error( $value['error_id'], $value['error_message'] );
526
			}
527
		}
528
529
		// Verify data.
530
		if ( $user_data ) {
531
			// Collected logged in user data.
532
			$valid_user_data = array(
533
				'user_id'    => $user_ID,
534
				'user_email' => isset( $_POST['give_email'] ) ? sanitize_email( $_POST['give_email'] ) : $user_data->user_email,
535
				'user_first' => isset( $_POST['give_first'] ) && ! empty( $_POST['give_first'] ) ? sanitize_text_field( $_POST['give_first'] ) : $user_data->first_name,
536
				'user_last'  => isset( $_POST['give_last'] ) && ! empty( $_POST['give_last'] ) ? sanitize_text_field( $_POST['give_last'] ) : $user_data->last_name,
537
			);
538
539
			if ( ! is_email( $valid_user_data['user_email'] ) ) {
540
				give_set_error( 'email_invalid', esc_html__( 'Invalid email.', 'give' ) );
541
			}
542
		} else {
543
			// Set invalid user error.
544
			give_set_error( 'invalid_user', esc_html__( 'The user information is invalid.', 'give' ) );
545
		}
546
	}
547
548
	// Return user data.
549
	return $valid_user_data;
550
}
551
552
/**
553
 * Donate Form Validate New User
554
 *
555
 * @access      private
556
 * @since       1.0
557
 * @return      array
558
 */
559
function give_purchase_form_validate_new_user() {
560
	// Default user data.
561
	$default_user_data = array(
562
		'give-form-id'           => '',
563
		'user_id'                => - 1, // Assume there will be errors.
564
		'user_first'             => '',
565
		'user_last'              => '',
566
		'give_user_login'        => false,
567
		'give_email'             => false,
568
		'give_user_pass'         => false,
569
		'give_user_pass_confirm' => false,
570
	);
571
572
	// Get user data.
573
	$user_data            = wp_parse_args( array_map( 'trim', give_clean( $_POST ) ), $default_user_data );
574
	$registering_new_user = false;
575
	$form_id              = absint( $user_data['give-form-id'] );
576
577
	// Start an empty array to collect valid user data.
578
	$valid_user_data = array(
579
		// Assume there will be errors.
580
		'user_id'    => - 1,
581
582
		// Get first name.
583
		'user_first' => $user_data['give_first'],
584
585
		// Get last name.
586
		'user_last'  => $user_data['give_last'],
587
	);
588
589
	// Loop through required fields and show error messages.
590
	foreach ( give_get_required_fields( $form_id ) as $field_name => $value ) {
591
		if ( in_array( $value, give_get_required_fields( $form_id ) ) && empty( $_POST[ $field_name ] ) ) {
592
			give_set_error( $value['error_id'], $value['error_message'] );
593
		}
594
	}
595
596
	// Check if we have an username to register.
597
	if ( give_validate_username( $user_data['give_user_login'] ) ) {
598
		$registering_new_user          = true;
599
		$valid_user_data['user_login'] = $user_data['give_user_login'];
600
	}
601
602
	// Check if we have an email to verify.
603
	if ( give_validate_user_email( $user_data['give_email'], $registering_new_user ) ) {
604
		$valid_user_data['user_email'] = $user_data['give_email'];
605
	}
606
607
	// Check password.
608
	if ( give_validate_user_password( $user_data['give_user_pass'], $user_data['give_user_pass_confirm'], $registering_new_user ) ) {
609
		// All is good to go.
610
		$valid_user_data['user_pass'] = $user_data['give_user_pass'];
611
	}
612
613
	return $valid_user_data;
614
}
615
616
/**
617
 * Donation Form Validate User Login
618
 *
619
 * @access      private
620
 * @since       1.0
621
 * @return      array
622
 */
623
function give_purchase_form_validate_user_login() {
624
625
	// Start an array to collect valid user data.
626
	$valid_user_data = array(
627
		// Assume there will be errors
628
		'user_id' => - 1,
629
	);
630
631
	// Username.
632
	if ( ! isset( $_POST['give_user_login'] ) || $_POST['give_user_login'] == '' ) {
633
		give_set_error( 'must_log_in', esc_html__( 'You must register or login to complete your donation.', 'give' ) );
634
635
		return $valid_user_data;
636
	}
637
638
	// Get the user by login.
639
	$user_data = get_user_by( 'login', strip_tags( $_POST['give_user_login'] ) );
640
641
	// Check if user exists.
642
	if ( $user_data ) {
643
		// Get password.
644
		$user_pass = isset( $_POST['give_user_pass'] ) ? $_POST['give_user_pass'] : false;
645
646
		// Check user_pass.
647
		if ( $user_pass ) {
648
			// Check if password is valid.
649
			if ( ! wp_check_password( $user_pass, $user_data->user_pass, $user_data->ID ) ) {
650
				// Incorrect password.
651
				give_set_error(
652
					'password_incorrect',
653
					sprintf(
654
						'%1$s <a href="%2$s">%3$s</a>',
655
						esc_html__( 'The password you entered is incorrect.', 'give' ),
656
						wp_lostpassword_url( "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]" ),
657
						esc_html__( 'Reset Password', 'give' )
658
					)
659
				);
660
				// All is correct.
661
			} else {
662
				// Repopulate the valid user data array.
663
				$valid_user_data = array(
664
					'user_id'    => $user_data->ID,
665
					'user_login' => $user_data->user_login,
666
					'user_email' => $user_data->user_email,
667
					'user_first' => $user_data->first_name,
668
					'user_last'  => $user_data->last_name,
669
					'user_pass'  => $user_pass,
670
				);
671
			}
672
		} else {
673
			// Empty password.
674
			give_set_error( 'password_empty', esc_html__( 'Enter a password.', 'give' ) );
675
		}
676
	} else {
677
		// No username.
678
		give_set_error( 'username_incorrect', esc_html__( 'The username you entered does not exist.', 'give' ) );
679
	}
680
681
	return $valid_user_data;
682
}
683
684
/**
685
 * Donation Form Validate Guest User
686
 *
687
 * @access  private
688
 * @since   1.0
689
 * @return  array
690
 */
691
function give_purchase_form_validate_guest_user() {
692
693
	$form_id = isset( $_POST['give-form-id'] ) ? $_POST['give-form-id'] : '';
694
695
	// Start an array to collect valid user data.
696
	$valid_user_data = array(
697
		// Set a default id for guests.
698
		'user_id' => 0,
699
	);
700
701
	// Show error message if user must be logged in.
702
	if ( give_logged_in_only( $form_id ) ) {
703
		give_set_error( 'logged_in_only', esc_html__( 'You must be logged in to donate.', 'give' ) );
704
	}
705
706
	// Get the guest email.
707
	$guest_email = isset( $_POST['give_email'] ) ? $_POST['give_email'] : false;
708
709
	// Check email.
710
	if ( $guest_email && strlen( $guest_email ) > 0 ) {
711
		// Validate email.
712
		if ( ! is_email( $guest_email ) ) {
713
			// Invalid email.
714
			give_set_error( 'email_invalid', esc_html__( 'Invalid email.', 'give' ) );
715
		} else {
716
			// All is good to go.
717
			$valid_user_data['user_email'] = $guest_email;
718
719
			// Get user_id from donor if exist.
720
			$donor = new Give_Customer( $guest_email );
721
			if ( $donor->id && $donor->user_id ) {
722
				$valid_user_data['user_id'] = $donor->user_id;
723
			}
724
		}
725
	} else {
726
		// No email.
727
		give_set_error( 'email_empty', esc_html__( 'Enter an email.', 'give' ) );
728
	}
729
730
	// Loop through required fields and show error messages.
731
	foreach ( give_get_required_fields( $form_id ) as $field_name => $value ) {
732
		if ( in_array( $value, give_get_required_fields( $form_id ) ) && empty( $_POST[ $field_name ] ) ) {
733
			give_set_error( $value['error_id'], $value['error_message'] );
734
		}
735
	}
736
737
	return $valid_user_data;
738
}
739
740
/**
741
 * Register And Login New User
742
 *
743
 * @param array $user_data
744
 *
745
 * @access  private
746
 * @since   1.0
747
 * @return  integer
748
 */
749
function give_register_and_login_new_user( $user_data = array() ) {
750
	// Verify the array.
751
	if ( empty( $user_data ) ) {
752
		return - 1;
753
	}
754
755
	if ( give_get_errors() ) {
756
		return - 1;
757
	}
758
759
	$user_args = apply_filters( 'give_insert_user_args', array(
760
		'user_login'      => isset( $user_data['user_login'] ) ? $user_data['user_login'] : '',
761
		'user_pass'       => isset( $user_data['user_pass'] ) ? $user_data['user_pass'] : '',
762
		'user_email'      => isset( $user_data['user_email'] ) ? $user_data['user_email'] : '',
763
		'first_name'      => isset( $user_data['user_first'] ) ? $user_data['user_first'] : '',
764
		'last_name'       => isset( $user_data['user_last'] ) ? $user_data['user_last'] : '',
765
		'user_registered' => date( 'Y-m-d H:i:s' ),
766
		'role'            => get_option( 'default_role' ),
767
	), $user_data );
768
769
	// Insert new user.
770
	$user_id = wp_insert_user( $user_args );
771
772
	// Validate inserted user.
773
	if ( is_wp_error( $user_id ) ) {
774
		return - 1;
775
	}
776
777
	// Allow themes and plugins to filter the user data.
778
	$user_data = apply_filters( 'give_insert_user_data', $user_data, $user_args );
779
780
	/**
781
	 * Fires after inserting user.
782
	 *
783
	 * @since 1.0
784
	 *
785
	 * @param int $user_id User id.
786
	 * @param array $user_data Array containing user data.
787
	 */
788
	do_action( 'give_insert_user', $user_id, $user_data );
789
790
	// Login new user.
791
	give_log_user_in( $user_id, $user_data['user_login'], $user_data['user_pass'] );
792
793
	// Return user id.
794
	return $user_id;
795
}
796
797
/**
798
 * Get Donation Form User
799
 *
800
 * @param array $valid_data
801
 *
802
 * @access  private
803
 * @since   1.0
804
 * @return  array
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|array<string,array|false>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
805
 */
806
function give_get_purchase_form_user( $valid_data = array() ) {
807
808
	// Initialize user.
809
	$user    = false;
810
	$is_ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
811
812
	if ( $is_ajax ) {
813
		// Do not create or login the user during the ajax submission (check for errors only).
814
		return true;
815
	} elseif ( is_user_logged_in() ) {
816
		// Set the valid user as the logged in collected data.
817
		$user = $valid_data['logged_in_user'];
818
	} elseif ( $valid_data['need_new_user'] === true || $valid_data['need_user_login'] === true ) {
819
		// New user registration.
820
		if ( $valid_data['need_new_user'] === true ) {
821
			// Set user.
822
			$user = $valid_data['new_user_data'];
823
			// Register and login new user.
824
			$user['user_id'] = give_register_and_login_new_user( $user );
825
			// User login
826
		} elseif ( $valid_data['need_user_login'] === true && ! $is_ajax ) {
827
828
			/*
829
			 * The login form is now processed in the give_process_purchase_login() function.
830
			 * This is still here for backwards compatibility.
831
			 * This also allows the old login process to still work if a user removes the checkout login submit button.
832
			 *
833
			 * This also ensures that the donor is logged in correctly if they click "Donation" instead of submitting the login form, meaning the donor is logged in during the donation process.
834
			 */
835
836
			// Set user.
837
			$user = $valid_data['login_user_data'];
838
			// Login user.
839
			give_log_user_in( $user['user_id'], $user['user_login'], $user['user_pass'] );
840
		}
841
	}
842
843
	// Check guest checkout.
844
	if ( false === $user && false === give_logged_in_only( $_POST['give-form-id'] ) ) {
845
		// Set user
846
		$user = $valid_data['guest_user_data'];
847
	}
848
849
	// Verify we have an user.
850
	if ( false === $user || empty( $user ) ) {
851
		// Return false.
852
		return false;
853
	}
854
855
	// Get user first name.
856
	if ( ! isset( $user['user_first'] ) || strlen( trim( $user['user_first'] ) ) < 1 ) {
857
		$user['user_first'] = isset( $_POST['give_first'] ) ? strip_tags( trim( $_POST['give_first'] ) ) : '';
858
	}
859
860
	// Get user last name.
861
	if ( ! isset( $user['user_last'] ) || strlen( trim( $user['user_last'] ) ) < 1 ) {
862
		$user['user_last'] = isset( $_POST['give_last'] ) ? strip_tags( trim( $_POST['give_last'] ) ) : '';
863
	}
864
865
	// Get the user's billing address details.
866
	$user['address']            = array();
867
	$user['address']['line1']   = ! empty( $_POST['card_address'] ) ? sanitize_text_field( $_POST['card_address'] ) : false;
868
	$user['address']['line2']   = ! empty( $_POST['card_address_2'] ) ? sanitize_text_field( $_POST['card_address_2'] ) : false;
869
	$user['address']['city']    = ! empty( $_POST['card_city'] ) ? sanitize_text_field( $_POST['card_city'] ) : false;
870
	$user['address']['state']   = ! empty( $_POST['card_state'] ) ? sanitize_text_field( $_POST['card_state'] ) : false;
871
	$user['address']['country'] = ! empty( $_POST['billing_country'] ) ? sanitize_text_field( $_POST['billing_country'] ) : false;
872
	$user['address']['zip']     = ! empty( $_POST['card_zip'] ) ? sanitize_text_field( $_POST['card_zip'] ) : false;
873
874
	if ( empty( $user['address']['country'] ) ) {
875
		$user['address'] = false;
876
	} // Country will always be set if address fields are present.
877
878
	if ( ! empty( $user['user_id'] ) && $user['user_id'] > 0 && ! empty( $user['address'] ) ) {
879
		// Store the address in the user's meta so the donation form can be pre-populated with it on return purchases.
880
		update_user_meta( $user['user_id'], '_give_user_address', $user['address'] );
881
	}
882
883
	// Return valid user.
884
	return $user;
885
}
886
887
/**
888
 * Validates the credit card info
889
 *
890
 * @access  private
891
 * @since   1.0
892
 * @return  array
893
 */
894
function give_purchase_form_validate_cc() {
895
896
	$card_data = give_get_purchase_cc_info();
897
898
	// Validate the card zip.
899
	if ( ! empty( $card_data['card_zip'] ) ) {
900
		if ( ! give_purchase_form_validate_cc_zip( $card_data['card_zip'], $card_data['card_country'] ) ) {
901
			give_set_error( 'invalid_cc_zip', esc_html__( 'The zip / postal code you entered for your billing address is invalid.', 'give' ) );
902
		}
903
	}
904
905
	// Ensure no spaces.
906
	if ( ! empty( $card_data['card_number'] ) ) {
907
		$card_data['card_number'] = str_replace( '+', '', $card_data['card_number'] ); // no "+" signs
908
		$card_data['card_number'] = str_replace( ' ', '', $card_data['card_number'] ); // No spaces
909
	}
910
911
	// This should validate card numbers at some point too.
912
	return $card_data;
913
}
914
915
/**
916
 * Get Credit Card Info
917
 *
918
 * @access  private
919
 * @since   1.0
920
 * @return  array
921
 */
922
function give_get_purchase_cc_info() {
923
	$cc_info                   = array();
924
	$cc_info['card_name']      = isset( $_POST['card_name'] ) ? sanitize_text_field( $_POST['card_name'] ) : '';
925
	$cc_info['card_number']    = isset( $_POST['card_number'] ) ? sanitize_text_field( $_POST['card_number'] ) : '';
926
	$cc_info['card_cvc']       = isset( $_POST['card_cvc'] ) ? sanitize_text_field( $_POST['card_cvc'] ) : '';
927
	$cc_info['card_exp_month'] = isset( $_POST['card_exp_month'] ) ? sanitize_text_field( $_POST['card_exp_month'] ) : '';
928
	$cc_info['card_exp_year']  = isset( $_POST['card_exp_year'] ) ? sanitize_text_field( $_POST['card_exp_year'] ) : '';
929
	$cc_info['card_address']   = isset( $_POST['card_address'] ) ? sanitize_text_field( $_POST['card_address'] ) : '';
930
	$cc_info['card_address_2'] = isset( $_POST['card_address_2'] ) ? sanitize_text_field( $_POST['card_address_2'] ) : '';
931
	$cc_info['card_city']      = isset( $_POST['card_city'] ) ? sanitize_text_field( $_POST['card_city'] ) : '';
932
	$cc_info['card_state']     = isset( $_POST['card_state'] ) ? sanitize_text_field( $_POST['card_state'] ) : '';
933
	$cc_info['card_country']   = isset( $_POST['billing_country'] ) ? sanitize_text_field( $_POST['billing_country'] ) : '';
934
	$cc_info['card_zip']       = isset( $_POST['card_zip'] ) ? sanitize_text_field( $_POST['card_zip'] ) : '';
935
936
	// Return cc info
937
	return $cc_info;
938
}
939
940
/**
941
 * Validate zip code based on country code
942
 *
943
 * @since  1.0
944
 *
945
 * @param int $zip
946
 * @param string $country_code
947
 *
948
 * @return bool|mixed|void
949
 */
950
function give_purchase_form_validate_cc_zip( $zip = 0, $country_code = '' ) {
951
	$ret = false;
952
953
	if ( empty( $zip ) || empty( $country_code ) ) {
954
		return $ret;
955
	}
956
957
	$country_code = strtoupper( $country_code );
958
959
	$zip_regex = array(
960
		'AD' => 'AD\d{3}',
961
		'AM' => '(37)?\d{4}',
962
		'AR' => '^([A-Z]{1}\d{4}[A-Z]{3}|[A-Z]{1}\d{4}|\d{4})$',
963
		'AS' => '96799',
964
		'AT' => '\d{4}',
965
		'AU' => '^(0[289][0-9]{2})|([1345689][0-9]{3})|(2[0-8][0-9]{2})|(290[0-9])|(291[0-4])|(7[0-4][0-9]{2})|(7[8-9][0-9]{2})$',
966
		'AX' => '22\d{3}',
967
		'AZ' => '\d{4}',
968
		'BA' => '\d{5}',
969
		'BB' => '(BB\d{5})?',
970
		'BD' => '\d{4}',
971
		'BE' => '^[1-9]{1}[0-9]{3}$',
972
		'BG' => '\d{4}',
973
		'BH' => '((1[0-2]|[2-9])\d{2})?',
974
		'BM' => '[A-Z]{2}[ ]?[A-Z0-9]{2}',
975
		'BN' => '[A-Z]{2}[ ]?\d{4}',
976
		'BR' => '\d{5}[\-]?\d{3}',
977
		'BY' => '\d{6}',
978
		'CA' => '^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$',
979
		'CC' => '6799',
980
		'CH' => '^[1-9][0-9][0-9][0-9]$',
981
		'CK' => '\d{4}',
982
		'CL' => '\d{7}',
983
		'CN' => '\d{6}',
984
		'CR' => '\d{4,5}|\d{3}-\d{4}',
985
		'CS' => '\d{5}',
986
		'CV' => '\d{4}',
987
		'CX' => '6798',
988
		'CY' => '\d{4}',
989
		'CZ' => '\d{3}[ ]?\d{2}',
990
		'DE' => '\b((?:0[1-46-9]\d{3})|(?:[1-357-9]\d{4})|(?:[4][0-24-9]\d{3})|(?:[6][013-9]\d{3}))\b',
991
		'DK' => '^([D-d][K-k])?( |-)?[1-9]{1}[0-9]{3}$',
992
		'DO' => '\d{5}',
993
		'DZ' => '\d{5}',
994
		'EC' => '([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?',
995
		'EE' => '\d{5}',
996
		'EG' => '\d{5}',
997
		'ES' => '^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$',
998
		'ET' => '\d{4}',
999
		'FI' => '\d{5}',
1000
		'FK' => 'FIQQ 1ZZ',
1001
		'FM' => '(9694[1-4])([ \-]\d{4})?',
1002
		'FO' => '\d{3}',
1003
		'FR' => '^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$',
1004
		'GE' => '\d{4}',
1005
		'GF' => '9[78]3\d{2}',
1006
		'GL' => '39\d{2}',
1007
		'GN' => '\d{3}',
1008
		'GP' => '9[78][01]\d{2}',
1009
		'GR' => '\d{3}[ ]?\d{2}',
1010
		'GS' => 'SIQQ 1ZZ',
1011
		'GT' => '\d{5}',
1012
		'GU' => '969[123]\d([ \-]\d{4})?',
1013
		'GW' => '\d{4}',
1014
		'HM' => '\d{4}',
1015
		'HN' => '(?:\d{5})?',
1016
		'HR' => '\d{5}',
1017
		'HT' => '\d{4}',
1018
		'HU' => '\d{4}',
1019
		'ID' => '\d{5}',
1020
		'IE' => '((D|DUBLIN)?([1-9]|6[wW]|1[0-8]|2[024]))?',
1021
		'IL' => '\d{5}',
1022
		'IN' => '^[1-9][0-9][0-9][0-9][0-9][0-9]$', // india
1023
		'IO' => 'BBND 1ZZ',
1024
		'IQ' => '\d{5}',
1025
		'IS' => '\d{3}',
1026
		'IT' => '^(V-|I-)?[0-9]{5}$',
1027
		'JO' => '\d{5}',
1028
		'JP' => '\d{3}-\d{4}',
1029
		'KE' => '\d{5}',
1030
		'KG' => '\d{6}',
1031
		'KH' => '\d{5}',
1032
		'KR' => '\d{3}[\-]\d{3}',
1033
		'KW' => '\d{5}',
1034
		'KZ' => '\d{6}',
1035
		'LA' => '\d{5}',
1036
		'LB' => '(\d{4}([ ]?\d{4})?)?',
1037
		'LI' => '(948[5-9])|(949[0-7])',
1038
		'LK' => '\d{5}',
1039
		'LR' => '\d{4}',
1040
		'LS' => '\d{3}',
1041
		'LT' => '\d{5}',
1042
		'LU' => '\d{4}',
1043
		'LV' => '\d{4}',
1044
		'MA' => '\d{5}',
1045
		'MC' => '980\d{2}',
1046
		'MD' => '\d{4}',
1047
		'ME' => '8\d{4}',
1048
		'MG' => '\d{3}',
1049
		'MH' => '969[67]\d([ \-]\d{4})?',
1050
		'MK' => '\d{4}',
1051
		'MN' => '\d{6}',
1052
		'MP' => '9695[012]([ \-]\d{4})?',
1053
		'MQ' => '9[78]2\d{2}',
1054
		'MT' => '[A-Z]{3}[ ]?\d{2,4}',
1055
		'MU' => '(\d{3}[A-Z]{2}\d{3})?',
1056
		'MV' => '\d{5}',
1057
		'MX' => '\d{5}',
1058
		'MY' => '\d{5}',
1059
		'NC' => '988\d{2}',
1060
		'NE' => '\d{4}',
1061
		'NF' => '2899',
1062
		'NG' => '(\d{6})?',
1063
		'NI' => '((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?',
1064
		'NL' => '^[1-9][0-9]{3}\s?([a-zA-Z]{2})?$',
1065
		'NO' => '\d{4}',
1066
		'NP' => '\d{5}',
1067
		'NZ' => '\d{4}',
1068
		'OM' => '(PC )?\d{3}',
1069
		'PF' => '987\d{2}',
1070
		'PG' => '\d{3}',
1071
		'PH' => '\d{4}',
1072
		'PK' => '\d{5}',
1073
		'PL' => '\d{2}-\d{3}',
1074
		'PM' => '9[78]5\d{2}',
1075
		'PN' => 'PCRN 1ZZ',
1076
		'PR' => '00[679]\d{2}([ \-]\d{4})?',
1077
		'PT' => '\d{4}([\-]\d{3})?',
1078
		'PW' => '96940',
1079
		'PY' => '\d{4}',
1080
		'RE' => '9[78]4\d{2}',
1081
		'RO' => '\d{6}',
1082
		'RS' => '\d{5}',
1083
		'RU' => '\d{6}',
1084
		'SA' => '\d{5}',
1085
		'SE' => '^(s-|S-){0,1}[0-9]{3}\s?[0-9]{2}$',
1086
		'SG' => '\d{6}',
1087
		'SH' => '(ASCN|STHL) 1ZZ',
1088
		'SI' => '\d{4}',
1089
		'SJ' => '\d{4}',
1090
		'SK' => '\d{3}[ ]?\d{2}',
1091
		'SM' => '4789\d',
1092
		'SN' => '\d{5}',
1093
		'SO' => '\d{5}',
1094
		'SZ' => '[HLMS]\d{3}',
1095
		'TC' => 'TKCA 1ZZ',
1096
		'TH' => '\d{5}',
1097
		'TJ' => '\d{6}',
1098
		'TM' => '\d{6}',
1099
		'TN' => '\d{4}',
1100
		'TR' => '\d{5}',
1101
		'TW' => '\d{3}(\d{2})?',
1102
		'UA' => '\d{5}',
1103
		'UK' => '^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$',
1104
		'US' => '^\d{5}([\-]?\d{4})?$',
1105
		'UY' => '\d{5}',
1106
		'UZ' => '\d{6}',
1107
		'VA' => '00120',
1108
		'VE' => '\d{4}',
1109
		'VI' => '008(([0-4]\d)|(5[01]))([ \-]\d{4})?',
1110
		'WF' => '986\d{2}',
1111
		'YT' => '976\d{2}',
1112
		'YU' => '\d{5}',
1113
		'ZA' => '\d{4}',
1114
		'ZM' => '\d{5}',
1115
	);
1116
1117
	if ( ! isset( $zip_regex[ $country_code ] ) || preg_match( '/' . $zip_regex[ $country_code ] . '/i', $zip ) ) {
1118
		$ret = true;
1119
	}
1120
1121
	return apply_filters( 'give_is_zip_valid', $ret, $zip, $country_code );
1122
}
1123
1124
1125
/**
1126
 * Auto set correct donation level id on basis of amount.
1127
 *
1128
 * Note: If amount does not match to donation level amount then level id will be auto select to first match level id on basis of amount.
1129
 *
1130
 * @param array $valid_data
1131
 * @param array $data
1132
 *
1133
 * @return bool
1134
 */
1135
function give_validate_multi_donation_form_level( $valid_data, $data ) {
0 ignored issues
show
Unused Code introduced by
The parameter $valid_data is not used and could be removed.

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

Loading history...
1136
	/* @var Give_Donate_Form $form */
1137
	$form = new Give_Donate_Form( $data['give-form-id'] );
1138
1139
	$donation_level_matched = false;
1140
1141
	if ( $form->is_multi_type_donation_form() ) {
1142
1143
		// Bailout.
1144
		if ( ! ( $variable_prices = $form->get_prices() ) ) {
1145
			return false;
1146
		}
1147
1148
		// Sanitize donation amount.
1149
		$data['give-amount'] = give_sanitize_amount( $data['give-amount'] );
1150
1151
		// Get number of decimals.
1152
		$default_decimals = give_get_price_decimals();
1153
1154
		if ( $data['give-amount'] === give_sanitize_amount( give_get_price_option_amount( $data['give-form-id'], $data['give-price-id'] ), $default_decimals ) ) {
1155
			return true;
1156
		}
1157
1158
		// Find correct donation level from all donation levels.
1159
		foreach ( $variable_prices as $variable_price ) {
1160
			// Sanitize level amount.
1161
			$variable_price['_give_amount'] = give_sanitize_amount( $variable_price['_give_amount'], $default_decimals );
1162
1163
			// Set first match donation level ID.
1164
			if ( $data['give-amount'] === $variable_price['_give_amount'] ) {
1165
				$_POST['give-price-id'] = $variable_price['_give_id']['level_id'];
1166
				$donation_level_matched = true;
1167
				break;
1168
			}
1169
		}
1170
1171
		// If donation amount is not find in donation levels then check if form has custom donation feature enable or not.
1172
		// If yes then set price id to custom if amount is greater then custom minimum amount (if any).
1173
		if (
1174
			! $donation_level_matched
1175
			&& ( give_is_setting_enabled( get_post_meta( $data['give-form-id'], '_give_custom_amount', true ) ) )
1176
		) {
1177
			// Sanitize custom minimum amount.
1178
			$custom_minimum_amount = give_sanitize_amount( get_post_meta( $data['give-form-id'], '_give_custom_amount_minimum', true ), $default_decimals );
1179
1180
			if ( $data['give-amount'] >= $custom_minimum_amount ) {
1181
				$_POST['give-price-id'] = 'custom';
1182
				$donation_level_matched = true;
1183
			}
1184
		}
1185
	}
1186
1187
	return ( $donation_level_matched ? true : false );
1188
}
1189
1190
add_action( 'give_checkout_error_checks', 'give_validate_multi_donation_form_level', 10, 2 );
1191