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