PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.1.3
GiveWP – Donation Plugin and Fundraising Platform v2.1.3
4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / includes / process-donation.php
give / includes Last commit date
admin 8 years ago api 8 years ago deprecated 8 years ago donors 8 years ago emails 8 years ago forms 8 years ago gateways 8 years ago libraries 8 years ago payments 8 years ago actions.php 8 years ago ajax-functions.php 8 years ago class-give-async-process.php 8 years ago class-give-background-updater.php 8 years ago class-give-cache.php 8 years ago class-give-cli-commands.php 8 years ago class-give-cron.php 8 years ago class-give-db-donor-meta.php 8 years ago class-give-db-donors.php 8 years ago class-give-db-form-meta.php 8 years ago class-give-db-logs-meta.php 8 years ago class-give-db-logs.php 8 years ago class-give-db-meta.php 8 years ago class-give-db-payment-meta.php 8 years ago class-give-db-sequential-ordering.php 8 years ago class-give-db.php 8 years ago class-give-donate-form.php 8 years ago class-give-donor.php 8 years ago class-give-email-access.php 8 years ago class-give-gravatars.php 8 years ago class-give-html-elements.php 8 years ago class-give-license-handler.php 8 years ago class-give-logging.php 8 years ago class-give-roles.php 8 years ago class-give-scripts.php 8 years ago class-give-session.php 8 years ago class-give-stats.php 8 years ago class-give-template-loader.php 8 years ago class-give-tooltips.php 8 years ago class-give-translation.php 8 years ago class-notices.php 8 years ago country-functions.php 8 years ago currency-functions.php 8 years ago error-tracking.php 8 years ago filters.php 8 years ago formatting.php 8 years ago import-functions.php 8 years ago install.php 8 years ago login-register.php 8 years ago misc-functions.php 8 years ago plugin-compatibility.php 8 years ago post-types.php 8 years ago price-functions.php 8 years ago process-donation.php 8 years ago shortcodes.php 8 years ago template-functions.php 8 years ago user-functions.php 8 years ago
process-donation.php
1434 lines
1 <?php
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 *
25 * @throws ReflectionException Exception Handling.
26 *
27 * @return mixed
28 */
29 function give_process_donation_form() {
30
31 $post_data = give_clean( $_POST ); // WPCS: input var ok, CSRF ok.
32 $is_ajax = isset( $post_data['give_ajax'] );
33
34 // Verify donation form nonce.
35 if ( ! give_verify_donation_form_nonce( $post_data['give-form-hash'], $post_data['give-form-id'] ) ) {
36 if ( $is_ajax ) {
37 /**
38 * Fires when AJAX sends back errors from the donation form.
39 *
40 * @since 1.0
41 */
42 do_action( 'give_ajax_donation_errors' );
43 give_die();
44 } else {
45 give_send_back_to_checkout();
46 }
47 }
48
49 /**
50 * Fires before processing the donation form.
51 *
52 * @since 1.0
53 */
54 do_action( 'give_pre_process_donation' );
55
56 // Validate the form $_POST data.
57 $valid_data = give_donation_form_validate_fields();
58
59 /**
60 * Fires after validating donation form fields.
61 *
62 * Allow you to hook to donation form errors.
63 *
64 * @since 1.0
65 *
66 * @param bool|array $valid_data Validate fields.
67 * @param array $deprecated Deprecated Since 2.0.2. Use $_POST instead.
68 */
69 $deprecated = $post_data;
70 do_action( 'give_checkout_error_checks', $valid_data, $deprecated );
71
72 // Process the login form.
73 if ( isset( $post_data['give_login_submit'] ) ) {
74 give_process_form_login();
75 }
76
77 // Validate the user.
78 $user = give_get_donation_form_user( $valid_data );
79
80 if ( false === $valid_data || give_get_errors() || ! $user ) {
81 if ( $is_ajax ) {
82 /**
83 * Fires when AJAX sends back errors from the donation form.
84 *
85 * @since 1.0
86 */
87 do_action( 'give_ajax_donation_errors' );
88 give_die();
89 } else {
90 return false;
91 }
92 }
93
94 // If AJAX send back success to proceed with form submission.
95 if ( $is_ajax ) {
96 echo 'success';
97 give_die();
98 }
99
100 // After AJAX: Setup session if not using php_sessions.
101 if ( ! Give()->session->use_php_sessions() ) {
102 // Double-check that set_cookie is publicly accessible.
103 // we're using a slightly modified class-wp-sessions.php.
104 $session_reflection = new ReflectionMethod( 'WP_Session', 'set_cookie' );
105 if ( $session_reflection->isPublic() ) {
106 // Manually set the cookie.
107 Give()->session->init()->set_cookie();
108 }
109 }
110
111 // Setup user information.
112 $user_info = array(
113 'id' => $user['user_id'],
114 'email' => $user['user_email'],
115 'first_name' => $user['user_first'],
116 'last_name' => $user['user_last'],
117 'address' => $user['address'],
118 );
119
120 $auth_key = defined( 'AUTH_KEY' ) ? AUTH_KEY : '';
121
122 $price = isset( $post_data['give-amount'] ) ?
123 (float) apply_filters( 'give_donation_total', give_maybe_sanitize_amount( $post_data['give-amount'] ) ) :
124 '0.00';
125 $purchase_key = strtolower( md5( $user['user_email'] . date( 'Y-m-d H:i:s' ) . $auth_key . uniqid( 'give', true ) ) );
126
127 // Setup donation information.
128 $donation_data = array(
129 'price' => $price,
130 'purchase_key' => $purchase_key,
131 'user_email' => $user['user_email'],
132 'date' => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
133 'user_info' => stripslashes_deep( $user_info ),
134 'post_data' => $post_data,
135 'gateway' => $valid_data['gateway'],
136 'card_info' => $valid_data['cc_info'],
137 );
138
139 // Add the user data for hooks.
140 $valid_data['user'] = $user;
141
142 /**
143 * Fires before donation form gateway.
144 *
145 * Allow you to hook to donation form before the gateway.
146 *
147 * @since 1.0
148 *
149 * @param array $post_data Array of variables passed via the HTTP POST.
150 * @param array $user_info Array containing basic user information.
151 * @param bool|array $valid_data Validate fields.
152 */
153 do_action( 'give_checkout_before_gateway', $post_data, $user_info, $valid_data );
154
155 // Sanity check for price.
156 if ( ! $donation_data['price'] ) {
157 // Revert to manual.
158 $donation_data['gateway'] = 'manual';
159 $_POST['give-gateway'] = 'manual';
160 }
161
162 /**
163 * Allow the donation data to be modified before it is sent to the gateway.
164 *
165 * @since 1.7
166 */
167 $donation_data = apply_filters( 'give_donation_data_before_gateway', $donation_data, $valid_data );
168
169 // Setup the data we're storing in the donation session.
170 $session_data = $donation_data;
171
172 // Make sure credit card numbers are never stored in sessions.
173 unset( $session_data['card_info']['card_number'] );
174 unset( $session_data['post_data']['card_number'] );
175
176 // Used for showing data to non logged-in users after donation, and for other plugins needing donation data.
177 give_set_purchase_session( $session_data );
178
179 // Send info to the gateway for payment processing.
180 give_send_to_gateway( $donation_data['gateway'], $donation_data );
181 give_die();
182 }
183
184 add_action( 'give_purchase', 'give_process_donation_form' );
185 add_action( 'wp_ajax_give_process_donation', 'give_process_donation_form' );
186 add_action( 'wp_ajax_nopriv_give_process_donation', 'give_process_donation_form' );
187
188 /**
189 * Verify that when a logged in user makes a donation that the email address used doesn't belong to a different customer.
190 *
191 * @since 1.7
192 *
193 * @param array $valid_data Validated data submitted for the donation.
194 *
195 * @return void
196 */
197 function give_check_logged_in_user_for_existing_email( $valid_data ) {
198
199 // Verify that the email address belongs to this customer.
200 if ( is_user_logged_in() ) {
201
202 $submitted_email = $valid_data['logged_in_user']['user_email'];
203 $donor = new Give_Donor( get_current_user_id(), true );
204
205 // If this email address is not registered with this customer, see if it belongs to any other customer.
206 if (
207 $submitted_email !== $donor->email
208 && ( is_array( $donor->emails ) && ! in_array( $submitted_email, $donor->emails, true ) )
209 ) {
210 $found_donor = new Give_Donor( $submitted_email );
211
212 if ( $found_donor->id > 0 ) {
213 give_set_error(
214 'give-customer-email-exists',
215 sprintf(
216 /* translators: 1. Donor Email, 2. Submitted Email */
217 __( '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.', 'give' ),
218 $donor->email,
219 $submitted_email
220 )
221 );
222 }
223 }
224 }
225 }
226
227 add_action( 'give_checkout_error_checks', 'give_check_logged_in_user_for_existing_email', 10, 1 );
228
229 /**
230 * Process the checkout login form
231 *
232 * @access private
233 * @since 1.0
234 *
235 * @return void
236 */
237 function give_process_form_login() {
238
239 $is_ajax = ! empty( $_POST['give_ajax'] ) ? give_clean( $_POST['give_ajax'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
240 $referrer = wp_get_referer();
241 $user_data = give_donation_form_validate_user_login();
242
243 if ( give_get_errors() || $user_data['user_id'] < 1 ) {
244 if ( $is_ajax ) {
245 /**
246 * Fires when AJAX sends back errors from the donation form.
247 *
248 * @since 1.0
249 */
250 ob_start();
251 do_action( 'give_ajax_donation_errors' );
252 $message = ob_get_contents();
253 ob_end_clean();
254 wp_send_json_error( $message );
255 } else {
256 wp_safe_redirect( $referrer );
257 exit;
258 }
259 }
260
261 give_log_user_in( $user_data['user_id'], $user_data['user_login'], $user_data['user_pass'] );
262
263 if ( $is_ajax ) {
264 $message = Give()->notices->print_frontend_notice(
265 sprintf(
266 /* translators: %s: user first name */
267 esc_html__( 'Welcome %s! You have successfully logged into your account.', 'give' ),
268 ( ! empty( $user_data['user_first'] ) ) ? $user_data['user_first'] : $user_data['user_login']
269 ),
270 false,
271 'success'
272 );
273
274 wp_send_json_success( $message );
275 } else {
276 wp_safe_redirect( $referrer );
277 }
278 }
279
280 add_action( 'wp_ajax_give_process_donation_login', 'give_process_form_login' );
281 add_action( 'wp_ajax_nopriv_give_process_donation_login', 'give_process_form_login' );
282
283 /**
284 * Donation Form Validate Fields.
285 *
286 * @access private
287 * @since 1.0
288 *
289 * @return bool|array
290 */
291 function give_donation_form_validate_fields() {
292
293 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
294
295 // Validate Honeypot First.
296 if ( ! empty( $post_data['give-honeypot'] ) ) {
297 give_set_error( 'invalid_honeypot', esc_html__( 'Honeypot field detected. Go away bad bot!', 'give' ) );
298 }
299
300 // Check spam detect.
301 if (
302 isset( $post_data['action'] ) &&
303 give_is_setting_enabled( give_get_option( 'akismet_spam_protection' ) ) &&
304 give_is_spam_donation()
305 ) {
306 give_set_error( 'spam_donation', __( 'This donation has been flagged as spam. Please try again.', 'give' ) );
307 }
308
309 // Start an array to collect valid data.
310 $valid_data = array(
311 'gateway' => give_donation_form_validate_gateway(), // Gateway fallback (amount is validated here).
312 'need_new_user' => false, // New user flag.
313 'need_user_login' => false, // Login user flag.
314 'logged_user_data' => array(), // Logged user collected data.
315 'new_user_data' => array(), // New user collected data.
316 'login_user_data' => array(), // Login user collected data.
317 'guest_user_data' => array(), // Guest user collected data.
318 'cc_info' => give_donation_form_validate_cc(), // Credit card info.
319 );
320
321 $form_id = intval( $post_data['give-form-id'] );
322
323 // Validate agree to terms.
324 if ( give_is_terms_enabled( $form_id ) ) {
325 give_donation_form_validate_agree_to_terms();
326 }
327
328 if ( is_user_logged_in() ) {
329
330 // Collect logged in user data.
331 $valid_data['logged_in_user'] = give_donation_form_validate_logged_in_user();
332 } elseif (
333 isset( $post_data['give-purchase-var'] ) &&
334 'needs-to-register' === $post_data['give-purchase-var'] &&
335 ! empty( $post_data['give_create_account'] )
336 ) {
337
338 // Set new user registration as required.
339 $valid_data['need_new_user'] = true;
340
341 // Validate new user data.
342 $valid_data['new_user_data'] = give_donation_form_validate_new_user();
343 } elseif (
344 isset( $post_data['give-purchase-var'] ) &&
345 'needs-to-login' === $post_data['give-purchase-var']
346 ) {
347
348 // Set user login as required.
349 $valid_data['need_user_login'] = true;
350
351 // Validate users login info.
352 $valid_data['login_user_data'] = give_donation_form_validate_user_login();
353 } else {
354
355 // Not registering or logging in, so setup guest user data.
356 $valid_data['guest_user_data'] = give_donation_form_validate_guest_user();
357 }
358
359 // Return collected data.
360 return $valid_data;
361 }
362
363 /**
364 * Detect spam donation.
365 *
366 * @since 1.8.14
367 *
368 * @return bool|mixed
369 */
370 function give_is_spam_donation() {
371 $spam = false;
372
373 $user_agent = (string) isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
374
375 if ( strlen( $user_agent ) < 2 ) {
376 $spam = true;
377 }
378
379 // Allow developer to customized Akismet spam detect API call and it's response.
380 return apply_filters( 'give_spam', $spam );
381 }
382
383 /**
384 * Donation Form Validate Gateway
385 *
386 * Validate the gateway and donation amount.
387 *
388 * @access private
389 * @since 1.0
390 *
391 * @return string
392 */
393 function give_donation_form_validate_gateway() {
394
395 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
396 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
397 $amount = ! empty( $post_data['give-amount'] ) ? give_maybe_sanitize_amount( $post_data['give-amount'] ) : 0;
398 $gateway = ! empty( $post_data['give-gateway'] ) ? $post_data['give-gateway'] : 0;
399
400 // Bailout, if payment gateway is not submitted with donation form data.
401 if ( empty( $gateway ) ) {
402
403 give_set_error( 'empty_gateway', __( 'The donation form will process with a valid payment gateway.', 'give' ) );
404
405 } elseif ( ! give_is_gateway_active( $gateway ) ) {
406
407 give_set_error( 'invalid_gateway', __( 'The selected payment gateway is not enabled.', 'give' ) );
408
409 } elseif ( empty( $amount ) ) {
410
411 give_set_error( 'invalid_donation_amount', __( 'Please insert a valid donation amount.', 'give' ) );
412
413 } elseif ( ! give_verify_minimum_price( 'minimum' ) ) {
414
415 give_set_error(
416 'invalid_donation_minimum',
417 sprintf(
418 /* translators: %s: minimum donation amount */
419 __( 'This form has a minimum donation amount of %s.', 'give' ),
420 give_currency_filter(
421 give_format_amount( give_get_form_minimum_price( $form_id ),
422 array(
423 'sanitize' => false,
424 )
425 )
426 )
427 )
428 );
429 } elseif ( ! give_verify_minimum_price( 'maximum' ) ) {
430
431 give_set_error(
432 'invalid_donation_maximum',
433 sprintf(
434 /* translators: %s: Maximum donation amount */
435 __( 'This form has a maximum donation amount of %s.', 'give' ),
436 give_currency_filter(
437 give_format_amount( give_get_form_maximum_price( $form_id ),
438 array(
439 'sanitize' => false,
440 )
441 )
442 )
443 )
444 );
445 } // End if().
446
447 return $gateway;
448
449 }
450
451 /**
452 * Donation Form Validate Minimum or Maximum Donation Amount
453 *
454 * @access private
455 * @since 1.3.6
456 * @since 2.1 Added support for give maximum amount.
457 * @since 2.1.3 Added new filter to modify the return value.
458 *
459 * @param string $amount_range Which amount needs to verify? minimum or maximum.
460 *
461 * @return bool
462 */
463 function give_verify_minimum_price( $amount_range = 'minimum' ) {
464
465 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
466 $amount = ! empty( $post_data['give-amount'] ) ? give_maybe_sanitize_amount( $post_data['give-amount'] ) : 0;
467 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
468 $price_id = ! empty( $post_data['give-price-id'] ) ? $post_data['give-price-id'] : '';
469
470 $variable_prices = give_has_variable_prices( $form_id );
471 $verified_stat = false;
472
473 if ( $variable_prices && in_array( $price_id, give_get_variable_price_ids( $form_id ), true ) ) {
474
475 $price_level_amount = give_get_price_option_amount( $form_id, $price_id );
476
477 if ( $price_level_amount == $amount ) {
478 $verified_stat = true;
479 }
480 }
481
482 if ( ! $verified_stat ) {
483 switch ( $amount_range ) {
484 case 'minimum' :
485 $verified_stat = ( give_get_form_minimum_price( $form_id ) > $amount ) ? false : true;
486 break;
487 case 'maximum' :
488 $verified_stat = ( give_get_form_maximum_price( $form_id ) < $amount ) ? false : true;
489 break;
490 }
491 }
492
493 /**
494 * Filter the verify amount
495 *
496 * @since 2.1.3
497 *
498 * @param bool $verified_stat Was verification passed or not?
499 * @param string $amount_range Type of the amount.
500 * @param integer $form_id Give Donation Form ID.
501 */
502 return apply_filters( 'give_verify_minimum_maximum_price', $verified_stat, $amount_range, $form_id );
503 }
504
505 /**
506 * Donation form validate agree to "Terms and Conditions".
507 *
508 * @access private
509 * @since 1.0
510 *
511 * @return void
512 */
513 function give_donation_form_validate_agree_to_terms() {
514
515 $agree_to_terms = ! empty( $_POST['give_agree_to_terms'] ) ? give_clean( $_POST['give_agree_to_terms'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
516
517 // Proceed only, if donor agreed to terms.
518 if ( ! $agree_to_terms ) {
519
520 // User did not agree.
521 give_set_error( 'agree_to_terms', apply_filters( 'give_agree_to_terms_text', __( 'You must agree to the terms and conditions.', 'give' ) ) );
522 }
523 }
524
525 /**
526 * Donation Form Required Fields.
527 *
528 * @access private
529 * @since 1.0
530 *
531 * @param int $form_id Donation Form ID.
532 *
533 * @return array
534 */
535 function give_get_required_fields( $form_id ) {
536
537 $payment_mode = give_get_chosen_gateway( $form_id );
538
539 $required_fields = array(
540 'give_email' => array(
541 'error_id' => 'invalid_email',
542 'error_message' => __( 'Please enter a valid email address.', 'give' ),
543 ),
544 'give_first' => array(
545 'error_id' => 'invalid_first_name',
546 'error_message' => __( 'Please enter your first name.', 'give' ),
547 ),
548 );
549
550 $require_address = give_require_billing_address( $payment_mode );
551
552 if ( $require_address ) {
553 $required_fields['card_address'] = array(
554 'error_id' => 'invalid_card_address',
555 'error_message' => __( 'Please enter your primary billing address.', 'give' ),
556 );
557 $required_fields['card_zip'] = array(
558 'error_id' => 'invalid_zip_code',
559 'error_message' => __( 'Please enter your zip / postal code.', 'give' ),
560 );
561 $required_fields['card_city'] = array(
562 'error_id' => 'invalid_city',
563 'error_message' => __( 'Please enter your billing city.', 'give' ),
564 );
565 $required_fields['billing_country'] = array(
566 'error_id' => 'invalid_country',
567 'error_message' => __( 'Please select your billing country.', 'give' ),
568 );
569
570
571 $required_fields['card_state'] = array(
572 'error_id' => 'invalid_state',
573 'error_message' => __( 'Please enter billing state / province / County.', 'give' ),
574 );
575
576 $country = ! empty( $_POST['billing_country'] ) ? give_clean( $_POST['billing_country'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
577
578 // Check if billing country already exists.
579 if ( $country ) {
580
581 // Get the country list that does not required any states init.
582 $states_country = give_states_not_required_country_list();
583
584 // Check if states is empty or not.
585 if ( array_key_exists( $country, $states_country ) ) {
586 // If states is empty remove the required fields of state in billing cart.
587 unset( $required_fields['card_state'] );
588 }
589 }
590 } // End if().
591
592 if ( give_is_company_field_enabled( $form_id ) ) {
593 $form_option = give_get_meta( $form_id, '_give_company_field', true );
594 $global_setting = give_get_option( 'company_field' );
595
596 $is_company_field_required = false;
597
598 if ( ! empty( $form_option ) && give_is_setting_enabled( $form_option, array( 'required' ) ) ) {
599 $is_company_field_required = true;
600
601 } elseif ( 'global' === $form_option && give_is_setting_enabled( $global_setting, array( 'required' ) ) ) {
602 $is_company_field_required = true;
603
604 } elseif ( empty( $form_option ) && give_is_setting_enabled( $global_setting, array( 'required' ) ) ) {
605 $is_company_field_required = true;
606
607 }
608
609 if ( $is_company_field_required ) {
610 $required_fields['give_company_name'] = array(
611 'error_id' => 'invalid_company',
612 'error_message' => __( 'Please enter Company Name.', 'give' ),
613 );
614 }
615 }
616
617 /**
618 * Filters the donation form required field.
619 *
620 * @since 1.7
621 */
622 $required_fields = apply_filters( 'give_donation_form_required_fields', $required_fields, $form_id );
623
624 return $required_fields;
625
626 }
627
628 /**
629 * Check if the Billing Address is required
630 *
631 * @since 1.0.1
632 *
633 * @param string $payment_mode Payment Mode.
634 *
635 * @return bool
636 */
637 function give_require_billing_address( $payment_mode ) {
638
639 $return = false;
640 $billing_country = ! empty( $_POST['billing_country'] ) ? give_clean( $_POST['billing_country'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
641
642 if ( $billing_country || did_action( "give_{$payment_mode}_cc_form" ) || did_action( 'give_cc_form' ) ) {
643 $return = true;
644 }
645
646 // Let payment gateways and other extensions determine if address fields should be required.
647 return apply_filters( 'give_require_billing_address', $return );
648
649 }
650
651 /**
652 * Donation Form Validate Logged In User.
653 *
654 * @access private
655 * @since 1.0
656 *
657 * @return array
658 */
659 function give_donation_form_validate_logged_in_user() {
660
661 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
662 $user_id = get_current_user_id();
663 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
664
665 // Start empty array to collect valid user data.
666 $valid_user_data = array(
667
668 // Assume there will be errors.
669 'user_id' => - 1,
670 );
671
672 // Proceed on;y, if valid $user_id found.
673 if ( $user_id > 0 ) {
674
675 // Get the logged in user data.
676 $user_data = get_userdata( $user_id );
677
678 // Validate Required Form Fields.
679 give_validate_required_form_fields( $form_id );
680
681 // Verify data.
682 if ( is_object( $user_data ) && $user_data->ID > 0 ) {
683
684 // Collected logged in user data.
685 $valid_user_data = array(
686 'user_id' => $user_id,
687 'user_email' => ! empty( $post_data['give_email'] ) ? sanitize_email( $post_data['give_email'] ) : $user_data->user_email,
688 'user_first' => ! empty( $post_data['give_first'] ) ? $post_data['give_first'] : $user_data->first_name,
689 'user_last' => ! empty( $post_data['give_last'] ) ? $post_data['give_last'] : $user_data->last_name,
690 );
691
692 // Validate essential form fields.
693 give_donation_form_validate_name_fields( $post_data );
694
695 if ( ! is_email( $valid_user_data['user_email'] ) ) {
696 give_set_error( 'email_invalid', esc_html__( 'Invalid email.', 'give' ) );
697 }
698 } else {
699
700 // Set invalid user information error.
701 give_set_error( 'invalid_user', esc_html__( 'The user information is invalid.', 'give' ) );
702 }
703 }
704
705 // Return user data.
706 return $valid_user_data;
707 }
708
709 /**
710 * Donate Form Validate New User
711 *
712 * @access private
713 * @since 1.0
714 *
715 * @return array
716 */
717 function give_donation_form_validate_new_user() {
718
719 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
720 $nonce = ! empty( $post_data['give-form-user-register-hash'] ) ? $post_data['give-form-user-register-hash'] : '';
721
722 // Validate user creation nonce.
723 if ( ! wp_verify_nonce( $nonce, 'give_form_create_user_nonce' ) ) {
724 give_set_error( 'invalid_nonce', __( 'Nonce verification has failed.', 'give' ) );
725 }
726
727 $auto_generated_password = wp_generate_password();
728
729 // Default user data.
730 $default_user_data = array(
731 'give-form-id' => '',
732 'user_id' => - 1, // Assume there will be errors.
733 'user_first' => '',
734 'user_last' => '',
735 'give_user_login' => false,
736 'give_email' => false,
737 'give_user_pass' => $auto_generated_password,
738 'give_user_pass_confirm' => $auto_generated_password,
739 );
740
741 // Get user data.
742 $user_data = wp_parse_args( $post_data, $default_user_data );
743 $registering_new_user = false;
744 $form_id = absint( $user_data['give-form-id'] );
745
746 give_donation_form_validate_name_fields( $user_data );
747
748 // Start an empty array to collect valid user data.
749 $valid_user_data = array(
750
751 // Assume there will be errors.
752 'user_id' => - 1,
753
754 // Get first name.
755 'user_first' => $user_data['give_first'],
756
757 // Get last name.
758 'user_last' => $user_data['give_last'],
759
760 // Get Password.
761 'user_pass' => $user_data['give_user_pass'],
762 );
763
764 // Validate Required Form Fields.
765 give_validate_required_form_fields( $form_id );
766
767 // Set Email as Username.
768 $valid_user_data['user_login'] = $user_data['give_email'];
769
770 // Check if we have an email to verify.
771 if ( give_validate_user_email( $user_data['give_email'], $registering_new_user ) ) {
772 $valid_user_data['user_email'] = $user_data['give_email'];
773 }
774
775 return $valid_user_data;
776 }
777
778 /**
779 * Donation Form Validate User Login
780 *
781 * @access private
782 * @since 1.0
783 *
784 * @return array
785 */
786 function give_donation_form_validate_user_login() {
787
788 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
789
790 // Start an array to collect valid user data.
791 $valid_user_data = array(
792
793 // Assume there will be errors.
794 'user_id' => - 1,
795 );
796
797 // Bailout, if Username is empty.
798 if ( empty( $post_data['give_user_login'] ) ) {
799 give_set_error( 'must_log_in', __( 'You must register or login to complete your donation.', 'give' ) );
800
801 return $valid_user_data;
802 }
803
804 // Get the user by login.
805 $user_data = get_user_by( 'login', strip_tags( $post_data['give_user_login'] ) );
806
807 // Check if user exists.
808 if ( $user_data ) {
809
810 // Get password.
811 $user_pass = ! empty( $post_data['give_user_pass'] ) ? $post_data['give_user_pass'] : false;
812
813 // Check user_pass.
814 if ( $user_pass ) {
815
816 // Check if password is valid.
817 if ( ! wp_check_password( $user_pass, $user_data->user_pass, $user_data->ID ) ) {
818
819 $current_page_url = site_url() . '/' . get_page_uri();
820
821 // Incorrect password.
822 give_set_error(
823 'password_incorrect',
824 sprintf(
825 '%1$s <a href="%2$s">%3$s</a>',
826 __( 'The password you entered is incorrect.', 'give' ),
827 wp_lostpassword_url( $current_page_url ),
828 __( 'Reset Password', 'give' )
829 )
830 );
831
832 } else {
833
834 // Repopulate the valid user data array.
835 $valid_user_data = array(
836 'user_id' => $user_data->ID,
837 'user_login' => $user_data->user_login,
838 'user_email' => $user_data->user_email,
839 'user_first' => $user_data->first_name,
840 'user_last' => $user_data->last_name,
841 'user_pass' => $user_pass,
842 );
843 }
844 } else {
845 // Empty password.
846 give_set_error( 'password_empty', __( 'Enter a password.', 'give' ) );
847 }
848 } else {
849 // No username.
850 give_set_error( 'username_incorrect', __( 'The username you entered does not exist.', 'give' ) );
851 } // End if().
852
853 return $valid_user_data;
854 }
855
856 /**
857 * Donation Form Validate Guest User
858 *
859 * @access private
860 * @since 1.0
861 *
862 * @return array
863 */
864 function give_donation_form_validate_guest_user() {
865
866 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
867 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
868
869 // Start an array to collect valid user data.
870 $valid_user_data = array(
871 // Set a default id for guests.
872 'user_id' => 0,
873 );
874
875 // Validate name fields.
876 give_donation_form_validate_name_fields( $post_data );
877
878 // Validate Required Form Fields.
879 give_validate_required_form_fields( $form_id );
880
881 // Get the guest email.
882 $guest_email = ! empty( $post_data['give_email'] ) ? $post_data['give_email'] : false;
883
884 // Check email.
885 if ( $guest_email && strlen( $guest_email ) > 0 ) {
886
887 // Validate email.
888 if ( ! is_email( $guest_email ) ) {
889
890 // Invalid email.
891 give_set_error( 'email_invalid', __( 'Invalid email.', 'give' ) );
892
893 } else {
894
895 // All is good to go.
896 $valid_user_data['user_email'] = $guest_email;
897
898 // Get user_id from donor if exist.
899 $donor = new Give_Donor( $guest_email );
900
901 if ( $donor->id && $donor->user_id ) {
902 $valid_user_data['user_id'] = $donor->user_id;
903 }
904 }
905 } else {
906 // No email.
907 give_set_error( 'email_empty', __( 'Enter an email.', 'give' ) );
908 }
909
910 return $valid_user_data;
911 }
912
913 /**
914 * Register And Login New User
915 *
916 * @param array $user_data User Data.
917 *
918 * @access private
919 * @since 1.0
920 *
921 * @return integer
922 */
923 function give_register_and_login_new_user( $user_data = array() ) {
924 // Verify the array.
925 if ( empty( $user_data ) ) {
926 return - 1;
927 }
928
929 if ( give_get_errors() ) {
930 return - 1;
931 }
932
933 $user_args = apply_filters( 'give_insert_user_args', array(
934 'user_login' => isset( $user_data['user_login'] ) ? $user_data['user_login'] : '',
935 'user_pass' => isset( $user_data['user_pass'] ) ? $user_data['user_pass'] : '',
936 'user_email' => isset( $user_data['user_email'] ) ? $user_data['user_email'] : '',
937 'first_name' => isset( $user_data['user_first'] ) ? $user_data['user_first'] : '',
938 'last_name' => isset( $user_data['user_last'] ) ? $user_data['user_last'] : '',
939 'user_registered' => date( 'Y-m-d H:i:s' ),
940 'role' => give_get_option( 'donor_default_user_role', 'give_donor' ),
941 ), $user_data );
942
943 // Insert new user.
944 $user_id = wp_insert_user( $user_args );
945
946 // Validate inserted user.
947 if ( is_wp_error( $user_id ) ) {
948 return - 1;
949 }
950
951 // Allow themes and plugins to filter the user data.
952 $user_data = apply_filters( 'give_insert_user_data', $user_data, $user_args );
953
954 /**
955 * Fires after inserting user.
956 *
957 * @since 1.0
958 *
959 * @param int $user_id User id.
960 * @param array $user_data Array containing user data.
961 */
962 do_action( 'give_insert_user', $user_id, $user_data );
963
964 /**
965 * Filter allow user to alter if user when to login or not when user is register for the first time.
966 *
967 * @since 1.8.13
968 *
969 * return bool True if login with registration and False if only want to register.
970 */
971 if ( true === (bool) apply_filters( 'give_log_user_in_on_register', true ) ) {
972 // Login new user.
973 give_log_user_in( $user_id, $user_data['user_login'], $user_data['user_pass'] );
974 }
975
976 // Return user id.
977 return $user_id;
978 }
979
980 /**
981 * Get Donation Form User
982 *
983 * @param array $valid_data Valid Data.
984 *
985 * @access private
986 * @since 1.0
987 *
988 * @return array|bool
989 */
990 function give_get_donation_form_user( $valid_data = array() ) {
991
992 // Initialize user.
993 $user = false;
994 $is_ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
995 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
996
997 if ( $is_ajax ) {
998
999 // Do not create or login the user during the ajax submission (check for errors only).
1000 return true;
1001 } elseif ( is_user_logged_in() ) {
1002
1003 // Set the valid user as the logged in collected data.
1004 $user = $valid_data['logged_in_user'];
1005 } elseif ( true === $valid_data['need_new_user'] || true === $valid_data['need_user_login'] ) {
1006
1007 // New user registration.
1008 if ( true === $valid_data['need_new_user'] ) {
1009
1010 // Set user.
1011 $user = $valid_data['new_user_data'];
1012
1013 // Register and login new user.
1014 $user['user_id'] = give_register_and_login_new_user( $user );
1015
1016 } elseif ( true === $valid_data['need_user_login'] && ! $is_ajax ) {
1017
1018 /**
1019 * The login form is now processed in the give_process_donation_login() function.
1020 * This is still here for backwards compatibility.
1021 * This also allows the old login process to still work if a user removes the checkout login submit button.
1022 *
1023 * 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.
1024 */
1025 $user = $valid_data['login_user_data'];
1026
1027 // Login user.
1028 give_log_user_in( $user['user_id'], $user['user_login'], $user['user_pass'] );
1029 }
1030 } // End if().
1031
1032 // Check guest checkout.
1033 if ( false === $user && false === give_logged_in_only( $post_data['give-form-id'] ) ) {
1034
1035 // Set user.
1036 $user = $valid_data['guest_user_data'];
1037 }
1038
1039 // Verify we have an user.
1040 if ( false === $user || empty( $user ) ) {
1041 return false;
1042 }
1043
1044 // Get user first name.
1045 if ( ! isset( $user['user_first'] ) || strlen( trim( $user['user_first'] ) ) < 1 ) {
1046 $user['user_first'] = isset( $post_data['give_first'] ) ? strip_tags( trim( $post_data['give_first'] ) ) : '';
1047 }
1048
1049 // Get user last name.
1050 if ( ! isset( $user['user_last'] ) || strlen( trim( $user['user_last'] ) ) < 1 ) {
1051 $user['user_last'] = isset( $post_data['give_last'] ) ? strip_tags( trim( $post_data['give_last'] ) ) : '';
1052 }
1053
1054 // Get the user's billing address details.
1055 $user['address'] = array();
1056 $user['address']['line1'] = ! empty( $post_data['card_address'] ) ? $post_data['card_address'] : false;
1057 $user['address']['line2'] = ! empty( $post_data['card_address_2'] ) ? $post_data['card_address_2'] : false;
1058 $user['address']['city'] = ! empty( $post_data['card_city'] ) ? $post_data['card_city'] : false;
1059 $user['address']['state'] = ! empty( $post_data['card_state'] ) ? $post_data['card_state'] : false;
1060 $user['address']['zip'] = ! empty( $post_data['card_zip'] ) ? $post_data['card_zip'] : false;
1061 $user['address']['country'] = ! empty( $post_data['billing_country'] ) ? $post_data['billing_country'] : false;
1062
1063 if ( empty( $user['address']['country'] ) ) {
1064 $user['address'] = false;
1065 } // End if().
1066
1067 // Return valid user.
1068 return $user;
1069 }
1070
1071 /**
1072 * Validates the credit card info.
1073 *
1074 * @access private
1075 * @since 1.0
1076 *
1077 * @return array
1078 */
1079 function give_donation_form_validate_cc() {
1080
1081 $card_data = give_get_donation_cc_info();
1082
1083 // Validate the card zip.
1084 if ( ! empty( $card_data['card_zip'] ) ) {
1085 if ( ! give_donation_form_validate_cc_zip( $card_data['card_zip'], $card_data['card_country'] ) ) {
1086 give_set_error( 'invalid_cc_zip', __( 'The zip / postal code you entered for your billing address is invalid.', 'give' ) );
1087 }
1088 }
1089
1090 // Ensure no spaces.
1091 if ( ! empty( $card_data['card_number'] ) ) {
1092 $card_data['card_number'] = str_replace( '+', '', $card_data['card_number'] ); // no "+" signs.
1093 $card_data['card_number'] = str_replace( ' ', '', $card_data['card_number'] ); // No spaces.
1094 }
1095
1096 // This should validate card numbers at some point too.
1097 return $card_data;
1098 }
1099
1100 /**
1101 * Get credit card info.
1102 *
1103 * @access private
1104 * @since 1.0
1105 *
1106 * @return array
1107 */
1108 function give_get_donation_cc_info() {
1109
1110 // Sanitize the values submitted with donation form.
1111 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1112
1113 $cc_info = array();
1114 $cc_info['card_name'] = ! empty( $post_data['card_name'] ) ? $post_data['card_name'] : '';
1115 $cc_info['card_number'] = ! empty( $post_data['card_number'] ) ? $post_data['card_number'] : '';
1116 $cc_info['card_cvc'] = ! empty( $post_data['card_cvc'] ) ? $post_data['card_cvc'] : '';
1117 $cc_info['card_exp_month'] = ! empty( $post_data['card_exp_month'] ) ? $post_data['card_exp_month'] : '';
1118 $cc_info['card_exp_year'] = ! empty( $post_data['card_exp_year'] ) ? $post_data['card_exp_year'] : '';
1119 $cc_info['card_address'] = ! empty( $post_data['card_address'] ) ? $post_data['card_address'] : '';
1120 $cc_info['card_address_2'] = ! empty( $post_data['card_address_2'] ) ? $post_data['card_address_2'] : '';
1121 $cc_info['card_city'] = ! empty( $post_data['card_city'] ) ? $post_data['card_city'] : '';
1122 $cc_info['card_state'] = ! empty( $post_data['card_state'] ) ? $post_data['card_state'] : '';
1123 $cc_info['card_country'] = ! empty( $post_data['billing_country'] ) ? $post_data['billing_country'] : '';
1124 $cc_info['card_zip'] = ! empty( $post_data['card_zip'] ) ? $post_data['card_zip'] : '';
1125
1126 // Return cc info.
1127 return $cc_info;
1128 }
1129
1130 /**
1131 * Validate zip code based on country code
1132 *
1133 * @since 1.0
1134 *
1135 * @param int $zip ZIP Code.
1136 * @param string $country_code Country Code.
1137 *
1138 * @return bool|mixed
1139 */
1140 function give_donation_form_validate_cc_zip( $zip = 0, $country_code = '' ) {
1141 $ret = false;
1142
1143 if ( empty( $zip ) || empty( $country_code ) ) {
1144 return $ret;
1145 }
1146
1147 $country_code = strtoupper( $country_code );
1148
1149 $zip_regex = array(
1150 'AD' => 'AD\d{3}',
1151 'AM' => '(37)?\d{4}',
1152 'AR' => '^([A-Z]{1}\d{4}[A-Z]{3}|[A-Z]{1}\d{4}|\d{4})$',
1153 'AS' => '96799',
1154 'AT' => '\d{4}',
1155 '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})$',
1156 'AX' => '22\d{3}',
1157 'AZ' => '\d{4}',
1158 'BA' => '\d{5}',
1159 'BB' => '(BB\d{5})?',
1160 'BD' => '\d{4}',
1161 'BE' => '^[1-9]{1}[0-9]{3}$',
1162 'BG' => '\d{4}',
1163 'BH' => '((1[0-2]|[2-9])\d{2})?',
1164 'BM' => '[A-Z]{2}[ ]?[A-Z0-9]{2}',
1165 'BN' => '[A-Z]{2}[ ]?\d{4}',
1166 'BR' => '\d{5}[\-]?\d{3}',
1167 'BY' => '\d{6}',
1168 'CA' => '^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$',
1169 'CC' => '6799',
1170 'CH' => '^[1-9][0-9][0-9][0-9]$',
1171 'CK' => '\d{4}',
1172 'CL' => '\d{7}',
1173 'CN' => '\d{6}',
1174 'CR' => '\d{4,5}|\d{3}-\d{4}',
1175 'CS' => '\d{5}',
1176 'CV' => '\d{4}',
1177 'CX' => '6798',
1178 'CY' => '\d{4}',
1179 'CZ' => '\d{3}[ ]?\d{2}',
1180 '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',
1181 'DK' => '^([D-d][K-k])?( |-)?[1-9]{1}[0-9]{3}$',
1182 'DO' => '\d{5}',
1183 'DZ' => '\d{5}',
1184 'EC' => '([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?',
1185 'EE' => '\d{5}',
1186 'EG' => '\d{5}',
1187 'ES' => '^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$',
1188 'ET' => '\d{4}',
1189 'FI' => '\d{5}',
1190 'FK' => 'FIQQ 1ZZ',
1191 'FM' => '(9694[1-4])([ \-]\d{4})?',
1192 'FO' => '\d{3}',
1193 'FR' => '^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$',
1194 'GE' => '\d{4}',
1195 'GF' => '9[78]3\d{2}',
1196 'GL' => '39\d{2}',
1197 'GN' => '\d{3}',
1198 'GP' => '9[78][01]\d{2}',
1199 'GR' => '\d{3}[ ]?\d{2}',
1200 'GS' => 'SIQQ 1ZZ',
1201 'GT' => '\d{5}',
1202 'GU' => '969[123]\d([ \-]\d{4})?',
1203 'GW' => '\d{4}',
1204 'HM' => '\d{4}',
1205 'HN' => '(?:\d{5})?',
1206 'HR' => '\d{5}',
1207 'HT' => '\d{4}',
1208 'HU' => '\d{4}',
1209 'ID' => '\d{5}',
1210 'IE' => '((D|DUBLIN)?([1-9]|6[wW]|1[0-8]|2[024]))?',
1211 'IL' => '\d{5}',
1212 'IN' => '^[1-9][0-9][0-9][0-9][0-9][0-9]$', // India.
1213 'IO' => 'BBND 1ZZ',
1214 'IQ' => '\d{5}',
1215 'IS' => '\d{3}',
1216 'IT' => '^(V-|I-)?[0-9]{5}$',
1217 'JO' => '\d{5}',
1218 'JP' => '\d{3}-\d{4}',
1219 'KE' => '\d{5}',
1220 'KG' => '\d{6}',
1221 'KH' => '\d{5}',
1222 'KR' => '\d{3}[\-]\d{3}',
1223 'KW' => '\d{5}',
1224 'KZ' => '\d{6}',
1225 'LA' => '\d{5}',
1226 'LB' => '(\d{4}([ ]?\d{4})?)?',
1227 'LI' => '(948[5-9])|(949[0-7])',
1228 'LK' => '\d{5}',
1229 'LR' => '\d{4}',
1230 'LS' => '\d{3}',
1231 'LT' => '\d{5}',
1232 'LU' => '\d{4}',
1233 'LV' => '\d{4}',
1234 'MA' => '\d{5}',
1235 'MC' => '980\d{2}',
1236 'MD' => '\d{4}',
1237 'ME' => '8\d{4}',
1238 'MG' => '\d{3}',
1239 'MH' => '969[67]\d([ \-]\d{4})?',
1240 'MK' => '\d{4}',
1241 'MN' => '\d{6}',
1242 'MP' => '9695[012]([ \-]\d{4})?',
1243 'MQ' => '9[78]2\d{2}',
1244 'MT' => '[A-Z]{3}[ ]?\d{2,4}',
1245 'MU' => '(\d{3}[A-Z]{2}\d{3})?',
1246 'MV' => '\d{5}',
1247 'MX' => '\d{5}',
1248 'MY' => '\d{5}',
1249 'NC' => '988\d{2}',
1250 'NE' => '\d{4}',
1251 'NF' => '2899',
1252 'NG' => '(\d{6})?',
1253 'NI' => '((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?',
1254 'NL' => '^[1-9][0-9]{3}\s?([a-zA-Z]{2})?$',
1255 'NO' => '\d{4}',
1256 'NP' => '\d{5}',
1257 'NZ' => '\d{4}',
1258 'OM' => '(PC )?\d{3}',
1259 'PF' => '987\d{2}',
1260 'PG' => '\d{3}',
1261 'PH' => '\d{4}',
1262 'PK' => '\d{5}',
1263 'PL' => '\d{2}-\d{3}',
1264 'PM' => '9[78]5\d{2}',
1265 'PN' => 'PCRN 1ZZ',
1266 'PR' => '00[679]\d{2}([ \-]\d{4})?',
1267 'PT' => '\d{4}([\-]\d{3})?',
1268 'PW' => '96940',
1269 'PY' => '\d{4}',
1270 'RE' => '9[78]4\d{2}',
1271 'RO' => '\d{6}',
1272 'RS' => '\d{5}',
1273 'RU' => '\d{6}',
1274 'SA' => '\d{5}',
1275 'SE' => '^(s-|S-){0,1}[0-9]{3}\s?[0-9]{2}$',
1276 'SG' => '\d{6}',
1277 'SH' => '(ASCN|STHL) 1ZZ',
1278 'SI' => '\d{4}',
1279 'SJ' => '\d{4}',
1280 'SK' => '\d{3}[ ]?\d{2}',
1281 'SM' => '4789\d',
1282 'SN' => '\d{5}',
1283 'SO' => '\d{5}',
1284 'SZ' => '[HLMS]\d{3}',
1285 'TC' => 'TKCA 1ZZ',
1286 'TH' => '\d{5}',
1287 'TJ' => '\d{6}',
1288 'TM' => '\d{6}',
1289 'TN' => '\d{4}',
1290 'TR' => '\d{5}',
1291 'TW' => '\d{3}(\d{2})?',
1292 'UA' => '\d{5}',
1293 'UK' => '^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$',
1294 'US' => '^\d{5}([\-]?\d{4})?$',
1295 'UY' => '\d{5}',
1296 'UZ' => '\d{6}',
1297 'VA' => '00120',
1298 'VE' => '\d{4}',
1299 'VI' => '008(([0-4]\d)|(5[01]))([ \-]\d{4})?',
1300 'WF' => '986\d{2}',
1301 'YT' => '976\d{2}',
1302 'YU' => '\d{5}',
1303 'ZA' => '\d{4}',
1304 'ZM' => '\d{5}',
1305 );
1306
1307 if ( ! isset( $zip_regex[ $country_code ] ) || preg_match( '/' . $zip_regex[ $country_code ] . '/i', $zip ) ) {
1308 $ret = true;
1309 }
1310
1311 return apply_filters( 'give_is_zip_valid', $ret, $zip, $country_code );
1312 }
1313
1314 /**
1315 * Validate donation amount and auto set correct donation level id on basis of amount.
1316 *
1317 * 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.
1318 *
1319 * @param array $valid_data List of Valid Data.
1320 *
1321 * @return bool
1322 */
1323 function give_validate_donation_amount( $valid_data ) {
1324
1325 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1326
1327 /* @var Give_Donate_Form $form */
1328 $form = new Give_Donate_Form( $post_data['give-form-id'] );
1329
1330 $donation_level_matched = false;
1331
1332 if ( $form->is_set_type_donation_form() ) {
1333
1334 // Sanitize donation amount.
1335 $post_data['give-amount'] = give_maybe_sanitize_amount( $post_data['give-amount'] );
1336
1337 // Backward compatibility.
1338 if ( $form->is_custom_price( $post_data['give-amount'] ) ) {
1339 $post_data['give-price-id'] = 'custom';
1340 }
1341
1342 $donation_level_matched = true;
1343
1344 } elseif ( $form->is_multi_type_donation_form() ) {
1345
1346 $variable_prices = $form->get_prices();
1347
1348 // Bailout.
1349 if ( ! $variable_prices ) {
1350 return false;
1351 }
1352
1353 // Sanitize donation amount.
1354 $post_data['give-amount'] = give_maybe_sanitize_amount( $post_data['give-amount'] );
1355 $variable_price_option_amount = give_maybe_sanitize_amount( give_get_price_option_amount( $post_data['give-form-id'], $post_data['give-price-id'] ) );
1356
1357 if ( $post_data['give-amount'] === $variable_price_option_amount ) {
1358 return true;
1359 }
1360
1361 if ( $form->is_custom_price( $post_data['give-amount'] ) ) {
1362 $post_data['give-price-id'] = 'custom';
1363 } else {
1364
1365 // Find correct donation level from all donation levels.
1366 foreach ( $variable_prices as $variable_price ) {
1367
1368 // Sanitize level amount.
1369 $variable_price['_give_amount'] = give_maybe_sanitize_amount( $variable_price['_give_amount'] );
1370
1371 // Set first match donation level ID.
1372 if ( $post_data['give-amount'] === $variable_price['_give_amount'] ) {
1373 $post_data['give-price-id'] = $variable_price['_give_id']['level_id'];
1374 break;
1375 }
1376 }
1377 }
1378
1379 // If donation amount is not find in donation levels then check if form has custom donation feature enable or not.
1380 // If yes then set price id to custom if amount is greater then custom minimum amount (if any).
1381 if ( ! empty( $post_data['give-price-id'] ) ) {
1382 $donation_level_matched = true;
1383 }
1384 } // End if().
1385
1386 return ( $donation_level_matched ? true : false );
1387 }
1388
1389 add_action( 'give_checkout_error_checks', 'give_validate_donation_amount', 10, 1 );
1390
1391 /**
1392 * Validate Required Form Fields.
1393 *
1394 * @param int $form_id Form ID.
1395 *
1396 * @since 2.0
1397 */
1398 function give_validate_required_form_fields( $form_id ) {
1399
1400 // Sanitize values submitted with donation form.
1401 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1402
1403 // Loop through required fields and show error messages.
1404 foreach ( give_get_required_fields( $form_id ) as $field_name => $value ) {
1405
1406 // Clean Up Data of the input fields.
1407 $field_value = $post_data[ $field_name ];
1408
1409 // Check whether the required field is empty, then show the error message.
1410 if ( in_array( $value, give_get_required_fields( $form_id ), true ) && empty( $field_value ) ) {
1411 give_set_error( $value['error_id'], $value['error_message'] );
1412 }
1413 }
1414 }
1415
1416 /**
1417 * Validates and checks if name fields are valid or not.
1418 *
1419 * @param array $post_data List of post data.
1420 *
1421 * @since 2.1
1422 *
1423 * @return void
1424 */
1425 function give_donation_form_validate_name_fields( $post_data ) {
1426
1427 $is_alpha_first_name = ( ! is_email( $post_data['give_first'] ) && ! preg_match( '~[0-9]~', $post_data['give_first'] ) );
1428 $is_alpha_last_name = ( ! is_email( $post_data['give_last'] ) && ! preg_match( '~[0-9]~', $post_data['give_last'] ) );
1429
1430 if ( ! $is_alpha_first_name || ( ! empty( $post_data['give_last'] ) && ! $is_alpha_last_name ) ) {
1431 give_set_error( 'invalid_name', esc_html__( 'The First Name and Last Name fields cannot contain an email address or numbers.', 'give' ) );
1432 }
1433 }
1434