PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.1.5
GiveWP – Donation Plugin and Fundraising Platform v2.1.5
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-readme-parser.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
1450 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 = isset( $post_data['give-price-id'] ) ? absint( $post_data['give-price-id'] ) : '';
469
470 $variable_prices = give_has_variable_prices( $form_id );
471 $price_ids = array_map( 'absint', give_get_variable_price_ids( $form_id ) );
472 $verified_stat = false;
473
474 if ( $variable_prices && in_array( $price_id, $price_ids, true ) ) {
475
476 $price_level_amount = give_get_price_option_amount( $form_id, $price_id );
477
478 if ( $price_level_amount == $amount ) {
479 $verified_stat = true;
480 }
481 }
482
483 if ( ! $verified_stat ) {
484 switch ( $amount_range ) {
485 case 'minimum' :
486 $verified_stat = ( give_get_form_minimum_price( $form_id ) > $amount ) ? false : true;
487 break;
488 case 'maximum' :
489 $verified_stat = ( give_get_form_maximum_price( $form_id ) < $amount ) ? false : true;
490 break;
491 }
492 }
493
494 /**
495 * Filter the verify amount
496 *
497 * @since 2.1.3
498 *
499 * @param bool $verified_stat Was verification passed or not?
500 * @param string $amount_range Type of the amount.
501 * @param integer $form_id Give Donation Form ID.
502 */
503 return apply_filters( 'give_verify_minimum_maximum_price', $verified_stat, $amount_range, $form_id );
504 }
505
506 /**
507 * Donation form validate agree to "Terms and Conditions".
508 *
509 * @access private
510 * @since 1.0
511 *
512 * @return void
513 */
514 function give_donation_form_validate_agree_to_terms() {
515
516 $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.
517
518 // Proceed only, if donor agreed to terms.
519 if ( ! $agree_to_terms ) {
520
521 // User did not agree.
522 give_set_error( 'agree_to_terms', apply_filters( 'give_agree_to_terms_text', __( 'You must agree to the terms and conditions.', 'give' ) ) );
523 }
524 }
525
526 /**
527 * Donation Form Required Fields.
528 *
529 * @access private
530 * @since 1.0
531 *
532 * @param int $form_id Donation Form ID.
533 *
534 * @return array
535 */
536 function give_get_required_fields( $form_id ) {
537
538 $payment_mode = give_get_chosen_gateway( $form_id );
539
540 $required_fields = array(
541 'give_email' => array(
542 'error_id' => 'invalid_email',
543 'error_message' => __( 'Please enter a valid email address.', 'give' ),
544 ),
545 'give_first' => array(
546 'error_id' => 'invalid_first_name',
547 'error_message' => __( 'Please enter your first name.', 'give' ),
548 ),
549 );
550
551 $require_address = give_require_billing_address( $payment_mode );
552
553 if ( $require_address ) {
554 $required_fields['card_address'] = array(
555 'error_id' => 'invalid_card_address',
556 'error_message' => __( 'Please enter your primary billing address.', 'give' ),
557 );
558 $required_fields['card_zip'] = array(
559 'error_id' => 'invalid_zip_code',
560 'error_message' => __( 'Please enter your zip / postal code.', 'give' ),
561 );
562 $required_fields['card_city'] = array(
563 'error_id' => 'invalid_city',
564 'error_message' => __( 'Please enter your billing city.', 'give' ),
565 );
566 $required_fields['billing_country'] = array(
567 'error_id' => 'invalid_country',
568 'error_message' => __( 'Please select your billing country.', 'give' ),
569 );
570
571
572 $required_fields['card_state'] = array(
573 'error_id' => 'invalid_state',
574 'error_message' => __( 'Please enter billing state / province / County.', 'give' ),
575 );
576
577 $country = ! empty( $_POST['billing_country'] ) ? give_clean( $_POST['billing_country'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
578
579 // Check if billing country already exists.
580 if ( $country ) {
581
582 // Get the country list that does not required any states init.
583 $states_country = give_states_not_required_country_list();
584
585 // Check if states is empty or not.
586 if ( array_key_exists( $country, $states_country ) ) {
587 // If states is empty remove the required fields of state in billing cart.
588 unset( $required_fields['card_state'] );
589 }
590 }
591 } // End if().
592
593 if ( give_is_company_field_enabled( $form_id ) ) {
594 $form_option = give_get_meta( $form_id, '_give_company_field', true );
595 $global_setting = give_get_option( 'company_field' );
596
597 $is_company_field_required = false;
598
599 if ( ! empty( $form_option ) && give_is_setting_enabled( $form_option, array( 'required' ) ) ) {
600 $is_company_field_required = true;
601
602 } elseif ( 'global' === $form_option && give_is_setting_enabled( $global_setting, array( 'required' ) ) ) {
603 $is_company_field_required = true;
604
605 } elseif ( empty( $form_option ) && give_is_setting_enabled( $global_setting, array( 'required' ) ) ) {
606 $is_company_field_required = true;
607
608 }
609
610 if ( $is_company_field_required ) {
611 $required_fields['give_company_name'] = array(
612 'error_id' => 'invalid_company',
613 'error_message' => __( 'Please enter Company Name.', 'give' ),
614 );
615 }
616 }
617
618 /**
619 * Filters the donation form required field.
620 *
621 * @since 1.7
622 */
623 $required_fields = apply_filters( 'give_donation_form_required_fields', $required_fields, $form_id );
624
625 return $required_fields;
626
627 }
628
629 /**
630 * Check if the Billing Address is required
631 *
632 * @since 1.0.1
633 *
634 * @param string $payment_mode Payment Mode.
635 *
636 * @return bool
637 */
638 function give_require_billing_address( $payment_mode ) {
639
640 $return = false;
641 $billing_country = ! empty( $_POST['billing_country'] ) ? give_clean( $_POST['billing_country'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
642
643 if ( $billing_country || did_action( "give_{$payment_mode}_cc_form" ) || did_action( 'give_cc_form' ) ) {
644 $return = true;
645 }
646
647 // Let payment gateways and other extensions determine if address fields should be required.
648 return apply_filters( 'give_require_billing_address', $return );
649
650 }
651
652 /**
653 * Donation Form Validate Logged In User.
654 *
655 * @access private
656 * @since 1.0
657 *
658 * @return array
659 */
660 function give_donation_form_validate_logged_in_user() {
661
662 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
663 $user_id = get_current_user_id();
664 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
665
666 // Start empty array to collect valid user data.
667 $valid_user_data = array(
668
669 // Assume there will be errors.
670 'user_id' => - 1,
671 );
672
673 // Proceed on;y, if valid $user_id found.
674 if ( $user_id > 0 ) {
675
676 // Get the logged in user data.
677 $user_data = get_userdata( $user_id );
678
679 // Validate Required Form Fields.
680 give_validate_required_form_fields( $form_id );
681
682 // Verify data.
683 if ( is_object( $user_data ) && $user_data->ID > 0 ) {
684
685 // Collected logged in user data.
686 $valid_user_data = array(
687 'user_id' => $user_id,
688 'user_email' => ! empty( $post_data['give_email'] ) ? sanitize_email( $post_data['give_email'] ) : $user_data->user_email,
689 'user_first' => ! empty( $post_data['give_first'] ) ? $post_data['give_first'] : $user_data->first_name,
690 'user_last' => ! empty( $post_data['give_last'] ) ? $post_data['give_last'] : $user_data->last_name,
691 );
692
693 // Validate essential form fields.
694 give_donation_form_validate_name_fields( $post_data );
695
696 if ( ! is_email( $valid_user_data['user_email'] ) ) {
697 give_set_error( 'email_invalid', esc_html__( 'Invalid email.', 'give' ) );
698 }
699 } else {
700
701 // Set invalid user information error.
702 give_set_error( 'invalid_user', esc_html__( 'The user information is invalid.', 'give' ) );
703 }
704 }
705
706 // Return user data.
707 return $valid_user_data;
708 }
709
710 /**
711 * Donate Form Validate New User
712 *
713 * @access private
714 * @since 1.0
715 *
716 * @return array
717 */
718 function give_donation_form_validate_new_user() {
719
720 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
721 $nonce = ! empty( $post_data['give-form-user-register-hash'] ) ? $post_data['give-form-user-register-hash'] : '';
722
723 // Validate user creation nonce.
724 if ( ! wp_verify_nonce( $nonce, 'give_form_create_user_nonce' ) ) {
725 give_set_error( 'invalid_nonce', __( 'Nonce verification has failed.', 'give' ) );
726 }
727
728 $auto_generated_password = wp_generate_password();
729
730 // Default user data.
731 $default_user_data = array(
732 'give-form-id' => '',
733 'user_id' => - 1, // Assume there will be errors.
734 'user_first' => '',
735 'user_last' => '',
736 'give_user_login' => false,
737 'give_email' => false,
738 'give_user_pass' => $auto_generated_password,
739 'give_user_pass_confirm' => $auto_generated_password,
740 );
741
742 // Get user data.
743 $user_data = wp_parse_args( $post_data, $default_user_data );
744 $registering_new_user = false;
745 $form_id = absint( $user_data['give-form-id'] );
746
747 give_donation_form_validate_name_fields( $user_data );
748
749 // Start an empty array to collect valid user data.
750 $valid_user_data = array(
751
752 // Assume there will be errors.
753 'user_id' => - 1,
754
755 // Get first name.
756 'user_first' => $user_data['give_first'],
757
758 // Get last name.
759 'user_last' => $user_data['give_last'],
760
761 // Get Password.
762 'user_pass' => $user_data['give_user_pass'],
763 );
764
765 // Validate Required Form Fields.
766 give_validate_required_form_fields( $form_id );
767
768 // Set Email as Username.
769 $valid_user_data['user_login'] = $user_data['give_email'];
770
771 // Check if we have an email to verify.
772 if ( give_validate_user_email( $user_data['give_email'], $registering_new_user ) ) {
773 $valid_user_data['user_email'] = $user_data['give_email'];
774 }
775
776 return $valid_user_data;
777 }
778
779 /**
780 * Donation Form Validate User Login
781 *
782 * @access private
783 * @since 1.0
784 *
785 * @return array
786 */
787 function give_donation_form_validate_user_login() {
788
789 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
790
791 // Start an array to collect valid user data.
792 $valid_user_data = array(
793
794 // Assume there will be errors.
795 'user_id' => - 1,
796 );
797
798 // Bailout, if Username is empty.
799 if ( empty( $post_data['give_user_login'] ) ) {
800 give_set_error( 'must_log_in', __( 'You must register or login to complete your donation.', 'give' ) );
801
802 return $valid_user_data;
803 }
804
805 // Get the user by login.
806 $user_data = get_user_by( 'login', strip_tags( $post_data['give_user_login'] ) );
807
808 // Check if user exists.
809 if ( $user_data ) {
810
811 // Get password.
812 $user_pass = ! empty( $post_data['give_user_pass'] ) ? $post_data['give_user_pass'] : false;
813
814 // Check user_pass.
815 if ( $user_pass ) {
816
817 // Check if password is valid.
818 if ( ! wp_check_password( $user_pass, $user_data->user_pass, $user_data->ID ) ) {
819
820 $current_page_url = site_url() . '/' . get_page_uri();
821
822 // Incorrect password.
823 give_set_error(
824 'password_incorrect',
825 sprintf(
826 '%1$s <a href="%2$s">%3$s</a>',
827 __( 'The password you entered is incorrect.', 'give' ),
828 wp_lostpassword_url( $current_page_url ),
829 __( 'Reset Password', 'give' )
830 )
831 );
832
833 } else {
834
835 // Repopulate the valid user data array.
836 $valid_user_data = array(
837 'user_id' => $user_data->ID,
838 'user_login' => $user_data->user_login,
839 'user_email' => $user_data->user_email,
840 'user_first' => $user_data->first_name,
841 'user_last' => $user_data->last_name,
842 'user_pass' => $user_pass,
843 );
844 }
845 } else {
846 // Empty password.
847 give_set_error( 'password_empty', __( 'Enter a password.', 'give' ) );
848 }
849 } else {
850 // No username.
851 give_set_error( 'username_incorrect', __( 'The username you entered does not exist.', 'give' ) );
852 } // End if().
853
854 return $valid_user_data;
855 }
856
857 /**
858 * Donation Form Validate Guest User
859 *
860 * @access private
861 * @since 1.0
862 *
863 * @return array
864 */
865 function give_donation_form_validate_guest_user() {
866
867 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
868 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
869
870 // Start an array to collect valid user data.
871 $valid_user_data = array(
872 // Set a default id for guests.
873 'user_id' => 0,
874 );
875
876 // Validate name fields.
877 give_donation_form_validate_name_fields( $post_data );
878
879 // Validate Required Form Fields.
880 give_validate_required_form_fields( $form_id );
881
882 // Get the guest email.
883 $guest_email = ! empty( $post_data['give_email'] ) ? $post_data['give_email'] : false;
884
885 // Check email.
886 if ( $guest_email && strlen( $guest_email ) > 0 ) {
887
888 // Validate email.
889 if ( ! is_email( $guest_email ) ) {
890
891 // Invalid email.
892 give_set_error( 'email_invalid', __( 'Invalid email.', 'give' ) );
893
894 } else {
895
896 // All is good to go.
897 $valid_user_data['user_email'] = $guest_email;
898
899 // Get user_id from donor if exist.
900 $donor = new Give_Donor( $guest_email );
901
902 if ( $donor->id && $donor->user_id ) {
903 $valid_user_data['user_id'] = $donor->user_id;
904 }
905 }
906 } else {
907 // No email.
908 give_set_error( 'email_empty', __( 'Enter an email.', 'give' ) );
909 }
910
911 return $valid_user_data;
912 }
913
914 /**
915 * Register And Login New User
916 *
917 * @param array $user_data User Data.
918 *
919 * @access private
920 * @since 1.0
921 *
922 * @return integer
923 */
924 function give_register_and_login_new_user( $user_data = array() ) {
925 // Verify the array.
926 if ( empty( $user_data ) ) {
927 return - 1;
928 }
929
930 if ( give_get_errors() ) {
931 return - 1;
932 }
933
934 $user_args = apply_filters( 'give_insert_user_args', array(
935 'user_login' => isset( $user_data['user_login'] ) ? $user_data['user_login'] : '',
936 'user_pass' => isset( $user_data['user_pass'] ) ? $user_data['user_pass'] : '',
937 'user_email' => isset( $user_data['user_email'] ) ? $user_data['user_email'] : '',
938 'first_name' => isset( $user_data['user_first'] ) ? $user_data['user_first'] : '',
939 'last_name' => isset( $user_data['user_last'] ) ? $user_data['user_last'] : '',
940 'user_registered' => date( 'Y-m-d H:i:s' ),
941 'role' => give_get_option( 'donor_default_user_role', 'give_donor' ),
942 ), $user_data );
943
944 // Insert new user.
945 $user_id = wp_insert_user( $user_args );
946
947 // Validate inserted user.
948 if ( is_wp_error( $user_id ) ) {
949 return - 1;
950 }
951
952 // Allow themes and plugins to filter the user data.
953 $user_data = apply_filters( 'give_insert_user_data', $user_data, $user_args );
954
955 /**
956 * Fires after inserting user.
957 *
958 * @since 1.0
959 *
960 * @param int $user_id User id.
961 * @param array $user_data Array containing user data.
962 */
963 do_action( 'give_insert_user', $user_id, $user_data );
964
965 /**
966 * Filter allow user to alter if user when to login or not when user is register for the first time.
967 *
968 * @since 1.8.13
969 *
970 * return bool True if login with registration and False if only want to register.
971 */
972 if ( true === (bool) apply_filters( 'give_log_user_in_on_register', true ) ) {
973 // Login new user.
974 give_log_user_in( $user_id, $user_data['user_login'], $user_data['user_pass'] );
975 }
976
977 // Return user id.
978 return $user_id;
979 }
980
981 /**
982 * Get Donation Form User
983 *
984 * @param array $valid_data Valid Data.
985 *
986 * @access private
987 * @since 1.0
988 *
989 * @return array|bool
990 */
991 function give_get_donation_form_user( $valid_data = array() ) {
992
993 // Initialize user.
994 $user = false;
995 $is_ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
996 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
997
998 if ( $is_ajax ) {
999
1000 // Do not create or login the user during the ajax submission (check for errors only).
1001 return true;
1002 } elseif ( is_user_logged_in() ) {
1003
1004 // Set the valid user as the logged in collected data.
1005 $user = $valid_data['logged_in_user'];
1006 } elseif ( true === $valid_data['need_new_user'] || true === $valid_data['need_user_login'] ) {
1007
1008 // New user registration.
1009 if ( true === $valid_data['need_new_user'] ) {
1010
1011 // Set user.
1012 $user = $valid_data['new_user_data'];
1013
1014 // Register and login new user.
1015 $user['user_id'] = give_register_and_login_new_user( $user );
1016
1017 } elseif ( true === $valid_data['need_user_login'] && ! $is_ajax ) {
1018
1019 /**
1020 * The login form is now processed in the give_process_donation_login() function.
1021 * This is still here for backwards compatibility.
1022 * This also allows the old login process to still work if a user removes the checkout login submit button.
1023 *
1024 * 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.
1025 */
1026 $user = $valid_data['login_user_data'];
1027
1028 // Login user.
1029 give_log_user_in( $user['user_id'], $user['user_login'], $user['user_pass'] );
1030 }
1031 } // End if().
1032
1033 // Check guest checkout.
1034 if ( false === $user && false === give_logged_in_only( $post_data['give-form-id'] ) ) {
1035
1036 // Set user.
1037 $user = $valid_data['guest_user_data'];
1038 }
1039
1040 // Verify we have an user.
1041 if ( false === $user || empty( $user ) ) {
1042 return false;
1043 }
1044
1045 // Get user first name.
1046 if ( ! isset( $user['user_first'] ) || strlen( trim( $user['user_first'] ) ) < 1 ) {
1047 $user['user_first'] = isset( $post_data['give_first'] ) ? strip_tags( trim( $post_data['give_first'] ) ) : '';
1048 }
1049
1050 // Get user last name.
1051 if ( ! isset( $user['user_last'] ) || strlen( trim( $user['user_last'] ) ) < 1 ) {
1052 $user['user_last'] = isset( $post_data['give_last'] ) ? strip_tags( trim( $post_data['give_last'] ) ) : '';
1053 }
1054
1055 // Get the user's billing address details.
1056 $user['address'] = array();
1057 $user['address']['line1'] = ! empty( $post_data['card_address'] ) ? $post_data['card_address'] : false;
1058 $user['address']['line2'] = ! empty( $post_data['card_address_2'] ) ? $post_data['card_address_2'] : false;
1059 $user['address']['city'] = ! empty( $post_data['card_city'] ) ? $post_data['card_city'] : false;
1060 $user['address']['state'] = ! empty( $post_data['card_state'] ) ? $post_data['card_state'] : false;
1061 $user['address']['zip'] = ! empty( $post_data['card_zip'] ) ? $post_data['card_zip'] : false;
1062 $user['address']['country'] = ! empty( $post_data['billing_country'] ) ? $post_data['billing_country'] : false;
1063
1064 if ( empty( $user['address']['country'] ) ) {
1065 $user['address'] = false;
1066 } // End if().
1067
1068 // Return valid user.
1069 return $user;
1070 }
1071
1072 /**
1073 * Validates the credit card info.
1074 *
1075 * @access private
1076 * @since 1.0
1077 *
1078 * @return array
1079 */
1080 function give_donation_form_validate_cc() {
1081
1082 $card_data = give_get_donation_cc_info();
1083
1084 // Validate the card zip.
1085 if ( ! empty( $card_data['card_zip'] ) ) {
1086 if ( ! give_donation_form_validate_cc_zip( $card_data['card_zip'], $card_data['card_country'] ) ) {
1087 give_set_error( 'invalid_cc_zip', __( 'The zip / postal code you entered for your billing address is invalid.', 'give' ) );
1088 }
1089 }
1090
1091 // Ensure no spaces.
1092 if ( ! empty( $card_data['card_number'] ) ) {
1093 $card_data['card_number'] = str_replace( '+', '', $card_data['card_number'] ); // no "+" signs.
1094 $card_data['card_number'] = str_replace( ' ', '', $card_data['card_number'] ); // No spaces.
1095 }
1096
1097 // This should validate card numbers at some point too.
1098 return $card_data;
1099 }
1100
1101 /**
1102 * Get credit card info.
1103 *
1104 * @access private
1105 * @since 1.0
1106 *
1107 * @return array
1108 */
1109 function give_get_donation_cc_info() {
1110
1111 // Sanitize the values submitted with donation form.
1112 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1113
1114 $cc_info = array();
1115 $cc_info['card_name'] = ! empty( $post_data['card_name'] ) ? $post_data['card_name'] : '';
1116 $cc_info['card_number'] = ! empty( $post_data['card_number'] ) ? $post_data['card_number'] : '';
1117 $cc_info['card_cvc'] = ! empty( $post_data['card_cvc'] ) ? $post_data['card_cvc'] : '';
1118 $cc_info['card_exp_month'] = ! empty( $post_data['card_exp_month'] ) ? $post_data['card_exp_month'] : '';
1119 $cc_info['card_exp_year'] = ! empty( $post_data['card_exp_year'] ) ? $post_data['card_exp_year'] : '';
1120 $cc_info['card_address'] = ! empty( $post_data['card_address'] ) ? $post_data['card_address'] : '';
1121 $cc_info['card_address_2'] = ! empty( $post_data['card_address_2'] ) ? $post_data['card_address_2'] : '';
1122 $cc_info['card_city'] = ! empty( $post_data['card_city'] ) ? $post_data['card_city'] : '';
1123 $cc_info['card_state'] = ! empty( $post_data['card_state'] ) ? $post_data['card_state'] : '';
1124 $cc_info['card_country'] = ! empty( $post_data['billing_country'] ) ? $post_data['billing_country'] : '';
1125 $cc_info['card_zip'] = ! empty( $post_data['card_zip'] ) ? $post_data['card_zip'] : '';
1126
1127 // Return cc info.
1128 return $cc_info;
1129 }
1130
1131 /**
1132 * Validate zip code based on country code
1133 *
1134 * @since 1.0
1135 *
1136 * @param int $zip ZIP Code.
1137 * @param string $country_code Country Code.
1138 *
1139 * @return bool|mixed
1140 */
1141 function give_donation_form_validate_cc_zip( $zip = 0, $country_code = '' ) {
1142 $ret = false;
1143
1144 if ( empty( $zip ) || empty( $country_code ) ) {
1145 return $ret;
1146 }
1147
1148 $country_code = strtoupper( $country_code );
1149
1150 $zip_regex = array(
1151 'AD' => 'AD\d{3}',
1152 'AM' => '(37)?\d{4}',
1153 'AR' => '^([A-Z]{1}\d{4}[A-Z]{3}|[A-Z]{1}\d{4}|\d{4})$',
1154 'AS' => '96799',
1155 'AT' => '\d{4}',
1156 '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})$',
1157 'AX' => '22\d{3}',
1158 'AZ' => '\d{4}',
1159 'BA' => '\d{5}',
1160 'BB' => '(BB\d{5})?',
1161 'BD' => '\d{4}',
1162 'BE' => '^[1-9]{1}[0-9]{3}$',
1163 'BG' => '\d{4}',
1164 'BH' => '((1[0-2]|[2-9])\d{2})?',
1165 'BM' => '[A-Z]{2}[ ]?[A-Z0-9]{2}',
1166 'BN' => '[A-Z]{2}[ ]?\d{4}',
1167 'BR' => '\d{5}[\-]?\d{3}',
1168 'BY' => '\d{6}',
1169 'CA' => '^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$',
1170 'CC' => '6799',
1171 'CH' => '^[1-9][0-9][0-9][0-9]$',
1172 'CK' => '\d{4}',
1173 'CL' => '\d{7}',
1174 'CN' => '\d{6}',
1175 'CR' => '\d{4,5}|\d{3}-\d{4}',
1176 'CS' => '\d{5}',
1177 'CV' => '\d{4}',
1178 'CX' => '6798',
1179 'CY' => '\d{4}',
1180 'CZ' => '\d{3}[ ]?\d{2}',
1181 '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',
1182 'DK' => '^([D-d][K-k])?( |-)?[1-9]{1}[0-9]{3}$',
1183 'DO' => '\d{5}',
1184 'DZ' => '\d{5}',
1185 'EC' => '([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?',
1186 'EE' => '\d{5}',
1187 'EG' => '\d{5}',
1188 'ES' => '^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$',
1189 'ET' => '\d{4}',
1190 'FI' => '\d{5}',
1191 'FK' => 'FIQQ 1ZZ',
1192 'FM' => '(9694[1-4])([ \-]\d{4})?',
1193 'FO' => '\d{3}',
1194 'FR' => '^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$',
1195 'GE' => '\d{4}',
1196 'GF' => '9[78]3\d{2}',
1197 'GL' => '39\d{2}',
1198 'GN' => '\d{3}',
1199 'GP' => '9[78][01]\d{2}',
1200 'GR' => '\d{3}[ ]?\d{2}',
1201 'GS' => 'SIQQ 1ZZ',
1202 'GT' => '\d{5}',
1203 'GU' => '969[123]\d([ \-]\d{4})?',
1204 'GW' => '\d{4}',
1205 'HM' => '\d{4}',
1206 'HN' => '(?:\d{5})?',
1207 'HR' => '\d{5}',
1208 'HT' => '\d{4}',
1209 'HU' => '\d{4}',
1210 'ID' => '\d{5}',
1211 'IE' => '((D|DUBLIN)?([1-9]|6[wW]|1[0-8]|2[024]))?',
1212 'IL' => '\d{5}',
1213 'IN' => '^[1-9][0-9][0-9][0-9][0-9][0-9]$', // India.
1214 'IO' => 'BBND 1ZZ',
1215 'IQ' => '\d{5}',
1216 'IS' => '\d{3}',
1217 'IT' => '^(V-|I-)?[0-9]{5}$',
1218 'JO' => '\d{5}',
1219 'JP' => '\d{3}-\d{4}',
1220 'KE' => '\d{5}',
1221 'KG' => '\d{6}',
1222 'KH' => '\d{5}',
1223 'KR' => '\d{3}[\-]\d{3}',
1224 'KW' => '\d{5}',
1225 'KZ' => '\d{6}',
1226 'LA' => '\d{5}',
1227 'LB' => '(\d{4}([ ]?\d{4})?)?',
1228 'LI' => '(948[5-9])|(949[0-7])',
1229 'LK' => '\d{5}',
1230 'LR' => '\d{4}',
1231 'LS' => '\d{3}',
1232 'LT' => '\d{5}',
1233 'LU' => '\d{4}',
1234 'LV' => '\d{4}',
1235 'MA' => '\d{5}',
1236 'MC' => '980\d{2}',
1237 'MD' => '\d{4}',
1238 'ME' => '8\d{4}',
1239 'MG' => '\d{3}',
1240 'MH' => '969[67]\d([ \-]\d{4})?',
1241 'MK' => '\d{4}',
1242 'MN' => '\d{6}',
1243 'MP' => '9695[012]([ \-]\d{4})?',
1244 'MQ' => '9[78]2\d{2}',
1245 'MT' => '[A-Z]{3}[ ]?\d{2,4}',
1246 'MU' => '(\d{3}[A-Z]{2}\d{3})?',
1247 'MV' => '\d{5}',
1248 'MX' => '\d{5}',
1249 'MY' => '\d{5}',
1250 'NC' => '988\d{2}',
1251 'NE' => '\d{4}',
1252 'NF' => '2899',
1253 'NG' => '(\d{6})?',
1254 'NI' => '((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?',
1255 'NL' => '^[1-9][0-9]{3}\s?([a-zA-Z]{2})?$',
1256 'NO' => '\d{4}',
1257 'NP' => '\d{5}',
1258 'NZ' => '\d{4}',
1259 'OM' => '(PC )?\d{3}',
1260 'PF' => '987\d{2}',
1261 'PG' => '\d{3}',
1262 'PH' => '\d{4}',
1263 'PK' => '\d{5}',
1264 'PL' => '\d{2}-\d{3}',
1265 'PM' => '9[78]5\d{2}',
1266 'PN' => 'PCRN 1ZZ',
1267 'PR' => '00[679]\d{2}([ \-]\d{4})?',
1268 'PT' => '\d{4}([\-]\d{3})?',
1269 'PW' => '96940',
1270 'PY' => '\d{4}',
1271 'RE' => '9[78]4\d{2}',
1272 'RO' => '\d{6}',
1273 'RS' => '\d{5}',
1274 'RU' => '\d{6}',
1275 'SA' => '\d{5}',
1276 'SE' => '^(s-|S-){0,1}[0-9]{3}\s?[0-9]{2}$',
1277 'SG' => '\d{6}',
1278 'SH' => '(ASCN|STHL) 1ZZ',
1279 'SI' => '\d{4}',
1280 'SJ' => '\d{4}',
1281 'SK' => '\d{3}[ ]?\d{2}',
1282 'SM' => '4789\d',
1283 'SN' => '\d{5}',
1284 'SO' => '\d{5}',
1285 'SZ' => '[HLMS]\d{3}',
1286 'TC' => 'TKCA 1ZZ',
1287 'TH' => '\d{5}',
1288 'TJ' => '\d{6}',
1289 'TM' => '\d{6}',
1290 'TN' => '\d{4}',
1291 'TR' => '\d{5}',
1292 'TW' => '\d{3}(\d{2})?',
1293 'UA' => '\d{5}',
1294 'UK' => '^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$',
1295 'US' => '^\d{5}([\-]?\d{4})?$',
1296 'UY' => '\d{5}',
1297 'UZ' => '\d{6}',
1298 'VA' => '00120',
1299 'VE' => '\d{4}',
1300 'VI' => '008(([0-4]\d)|(5[01]))([ \-]\d{4})?',
1301 'WF' => '986\d{2}',
1302 'YT' => '976\d{2}',
1303 'YU' => '\d{5}',
1304 'ZA' => '\d{4}',
1305 'ZM' => '\d{5}',
1306 );
1307
1308 if ( ! isset( $zip_regex[ $country_code ] ) || preg_match( '/' . $zip_regex[ $country_code ] . '/i', $zip ) ) {
1309 $ret = true;
1310 }
1311
1312 return apply_filters( 'give_is_zip_valid', $ret, $zip, $country_code );
1313 }
1314
1315 /**
1316 * Validate donation amount and auto set correct donation level id on basis of amount.
1317 *
1318 * 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.
1319 *
1320 * @param array $valid_data List of Valid Data.
1321 *
1322 * @return bool
1323 */
1324 function give_validate_donation_amount( $valid_data ) {
1325
1326 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1327
1328 /* @var Give_Donate_Form $form */
1329 $form = new Give_Donate_Form( $post_data['give-form-id'] );
1330
1331 // Get the form currency.
1332 $form_currency = give_get_currency( $post_data['give-form-id'] );
1333
1334 $donation_level_matched = false;
1335
1336 if ( $form->is_set_type_donation_form() ) {
1337
1338 // Sanitize donation amount.
1339 $post_data['give-amount'] = give_maybe_sanitize_amount( $post_data['give-amount'], array( 'currency' => $form_currency ) );
1340
1341 // Backward compatibility.
1342 if ( $form->is_custom_price( $post_data['give-amount'] ) ) {
1343 $post_data['give-price-id'] = 'custom';
1344 }
1345
1346 $donation_level_matched = true;
1347
1348 } elseif ( $form->is_multi_type_donation_form() ) {
1349
1350 $variable_prices = $form->get_prices();
1351
1352 // Bailout.
1353 if ( ! $variable_prices ) {
1354 return false;
1355 }
1356
1357 // Sanitize donation amount.
1358 $post_data['give-amount'] = give_maybe_sanitize_amount( $post_data['give-amount'], array( 'currency' => $form_currency ) );
1359 $variable_price_option_amount = give_maybe_sanitize_amount( give_get_price_option_amount( $post_data['give-form-id'], $post_data['give-price-id'] ), array( 'currency' => $form_currency ) );
1360 $new_price_id = '';
1361
1362 if ( $post_data['give-amount'] === $variable_price_option_amount ) {
1363 return true;
1364 }
1365
1366 if ( $form->is_custom_price( $post_data['give-amount'] ) ) {
1367 $new_price_id = 'custom';
1368 } else {
1369
1370 // Find correct donation level from all donation levels.
1371 foreach ( $variable_prices as $variable_price ) {
1372
1373 // Sanitize level amount.
1374 $variable_price['_give_amount'] = give_maybe_sanitize_amount( $variable_price['_give_amount'] );
1375
1376 // Set first match donation level ID.
1377 if ( $post_data['give-amount'] === $variable_price['_give_amount'] ) {
1378 $new_price_id = $variable_price['_give_id']['level_id'];
1379 break;
1380 }
1381 }
1382 }
1383
1384 // If donation amount is not find in donation levels then check if form has custom donation feature enable or not.
1385 // If yes then set price id to custom if amount is greater then custom minimum amount (if any).
1386 if ( $post_data['give-price-id'] === $new_price_id ) {
1387 $donation_level_matched = true;
1388 }
1389 } // End if().
1390
1391 if ( ! $donation_level_matched ) {
1392 give_set_error(
1393 'invalid_donation_amount',
1394 sprintf(
1395 /* translators: %s: invalid donation amount */
1396 __( 'Donation amount %s is invalid.', 'give' ),
1397 give_currency_filter(
1398 give_format_amount( $post_data['give-amount'], array( 'sanitize' => false, ) )
1399 )
1400 )
1401 );
1402 }
1403 }
1404
1405 add_action( 'give_checkout_error_checks', 'give_validate_donation_amount', 10, 1 );
1406
1407 /**
1408 * Validate Required Form Fields.
1409 *
1410 * @param int $form_id Form ID.
1411 *
1412 * @since 2.0
1413 */
1414 function give_validate_required_form_fields( $form_id ) {
1415
1416 // Sanitize values submitted with donation form.
1417 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1418
1419 // Loop through required fields and show error messages.
1420 foreach ( give_get_required_fields( $form_id ) as $field_name => $value ) {
1421
1422 // Clean Up Data of the input fields.
1423 $field_value = $post_data[ $field_name ];
1424
1425 // Check whether the required field is empty, then show the error message.
1426 if ( in_array( $value, give_get_required_fields( $form_id ), true ) && empty( $field_value ) ) {
1427 give_set_error( $value['error_id'], $value['error_message'] );
1428 }
1429 }
1430 }
1431
1432 /**
1433 * Validates and checks if name fields are valid or not.
1434 *
1435 * @param array $post_data List of post data.
1436 *
1437 * @since 2.1
1438 *
1439 * @return void
1440 */
1441 function give_donation_form_validate_name_fields( $post_data ) {
1442
1443 $is_alpha_first_name = ( ! is_email( $post_data['give_first'] ) && ! preg_match( '~[0-9]~', $post_data['give_first'] ) );
1444 $is_alpha_last_name = ( ! is_email( $post_data['give_last'] ) && ! preg_match( '~[0-9]~', $post_data['give_last'] ) );
1445
1446 if ( ! $is_alpha_first_name || ( ! empty( $post_data['give_last'] ) && ! $is_alpha_last_name ) ) {
1447 give_set_error( 'invalid_name', esc_html__( 'The First Name and Last Name fields cannot contain an email address or numbers.', 'give' ) );
1448 }
1449 }
1450