PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.7.0.3
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.7.0.3
1.8.13.1 1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 All 212 releases
charitable / includes / forms / class-charitable-profile-form.php

class-charitable-profile-form.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.7.0.3, at includes/forms/class-charitable-profile-form.php

631 lines 16.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class that manages the display and processing of the profile form.
4 *
5 * @package Charitable/Classes/Charitable_Profile_Form
6 * @author David Bisset
7 * @copyright Copyright (c) 2022, WP Charitable LLC
8 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9 * @since 1.0.0
10 * @version 1.6.51
11 */
12
13 // Exit if accessed directly.
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 if ( ! class_exists( 'Charitable_Profile_Form' ) ) :
19
20 /**
21 * Charitable_Profile_Form
22 *
23 * @since 1.0.0
24 */
25 class Charitable_Profile_Form extends Charitable_Form {
26
27 /**
28 * Shortcode parameters.
29 *
30 * @var array
31 */
32 protected $shortcode_args;
33
34 /**
35 * @var string
36 */
37 protected $nonce_action = 'charitable_user_profile';
38
39 /**
40 * @var string
41 */
42 protected $nonce_name = '_charitable_user_profile_nonce';
43
44 /**
45 * Action to be executed upon form submission.
46 *
47 * @var string
48 */
49 protected $form_action = 'update_profile';
50
51 /**
52 * The current user.
53 *
54 * @var Charitable_User
55 */
56 protected $user;
57
58 /**
59 * Create class object.
60 *
61 * @since 1.0.0
62 *
63 * @param array $args User-defined shortcode attributes.
64 */
65 public function __construct( $args = array() ) {
66 $this->id = uniqid();
67 $this->shortcode_args = $args;
68
69 /* For backwards-compatibility */
70 add_action( 'charitable_form_field', array( $this, 'render_field' ), 10, 6 );
71 }
72
73 /**
74 * Return the current user's Charitable_User object.
75 *
76 * @since 1.0.0
77 *
78 * @return Charitable_User
79 */
80 public function get_user() {
81 if ( ! isset( $this->user ) ) {
82 $this->user = new Charitable_User( wp_get_current_user() );
83 }
84
85 return $this->user;
86 }
87
88 /**
89 * Returns the value of a particular key.
90 *
91 * @since 1.0.0
92 *
93 * @param string $key The key of the data we are searching for.
94 * @param string $default Optional. The value that will be used if none is set.
95 * @return mixed
96 */
97 public function get_user_value( $key, $default = '' ) {
98 if ( isset( $_POST[ $key ] ) ) {
99 return $_POST[ $key ];
100 }
101
102 $value = $this->get_user_prop_or_default( $key, $default );
103
104 /**
105 * Deprecated filter. Use the filter below instead.
106 *
107 * @deprecated 1.8.0
108 *
109 * @since 1.0.0
110 * @since 1.5.7 Deprecated.
111 *
112 * @param string $value The value.
113 * @param string $key The key of the value.
114 * @param Charitable_User $user Instance of `Charitable_User`.
115 */
116 $value = apply_filters( 'charitable_campaign_submission_user_value', $value, $key, $this->get_user() );
117
118 /**
119 * Filter the set value for a particular key.
120 *
121 * @since 1.5.7
122 *
123 * @param string $value The value.
124 * @param string $key The key of the value.
125 * @param Charitable_User $user Instance of `Charitable_User`.
126 */
127 return apply_filters( 'charitable_profile_value', $value, $key, $this->get_user() );
128 }
129
130 /**
131 * Return the core user fields.
132 *
133 * @since 1.0.0
134 *
135 * @return array
136 */
137 public function get_user_fields() {
138 $user_fields = apply_filters( 'charitable_user_fields', array(
139 'username' => array(
140 'type' => 'paragraph',
141 'priority' => '',
142 'content' => sprintf(
143 /* translators: %s: username */
144 __( 'Username: %s.', 'charitable' ),
145 $this->get_user()->user_login
146 ),
147 ),
148 'first_name' => array(
149 'label' => __( 'First name', 'charitable' ),
150 'type' => 'text',
151 'priority' => 4,
152 'required' => true,
153 'value' => $this->get_user_value( 'first_name' ),
154 ),
155 'last_name' => array(
156 'label' => __( 'Last name', 'charitable' ),
157 'type' => 'text',
158 'priority' => 6,
159 'required' => true,
160 'value' => $this->get_user_value( 'last_name' ),
161 ),
162 'user_email' => array(
163 'label' => __( 'Email', 'charitable' ),
164 'type' => 'email',
165 'required' => true,
166 'priority' => 8,
167 'value' => $this->get_user_value( 'user_email' ),
168 ),
169 'organisation' => array(
170 'label' => __( 'Organization', 'charitable' ),
171 'type' => 'text',
172 'priority' => 10,
173 'required' => false,
174 'value' => $this->get_user_value( 'organisation' ),
175 ),
176 'description' => array(
177 'label' => __( 'Bio', 'charitable' ),
178 'type' => 'textarea',
179 'required' => false,
180 'priority' => 12,
181 'value' => $this->get_user_value( 'description' ),
182 ),
183 ), $this );
184
185 uasort( $user_fields, 'charitable_priority_sort' );
186
187 return $user_fields;
188 }
189
190 /**
191 * Return the user's address fields.
192 *
193 * @since 1.0.0
194 *
195 * @return array
196 */
197 public function get_address_fields() {
198 /**
199 * Filter the list of user address fields.
200 *
201 * @since 1.0.0
202 *
203 * @param array $fields The fields in the form.
204 * @param Charitable_Profile_Form $form The profile form.
205 */
206 $address_fields = apply_filters(
207 'charitable_user_address_fields',
208 array(
209 'address' => array(
210 'label' => __( 'Address', 'charitable' ),
211 'type' => 'text',
212 'priority' => 22,
213 'required' => false,
214 'value' => $this->get_user_value( 'donor_address' ),
215 ),
216 'address_2' => array(
217 'label' => __( 'Address 2', 'charitable' ),
218 'type' => 'text',
219 'priority' => 24,
220 'required' => false,
221 'value' => $this->get_user_value( 'donor_address_2' ),
222 ),
223 'city' => array(
224 'label' => __( 'City', 'charitable' ),
225 'type' => 'text',
226 'priority' => 26,
227 'required' => false,
228 'value' => $this->get_user_value( 'donor_city' ),
229 ),
230 'state' => array(
231 'label' => __( 'State', 'charitable' ),
232 'type' => 'text',
233 'priority' => 28,
234 'required' => false,
235 'value' => $this->get_user_value( 'donor_state' ),
236 ),
237 'postcode' => array(
238 'label' => __( 'Postcode / ZIP code', 'charitable' ),
239 'type' => 'text',
240 'priority' => 30,
241 'required' => false,
242 'value' => $this->get_user_value( 'donor_postcode' ),
243 ),
244 'country' => array(
245 'label' => __( 'Country', 'charitable' ),
246 'type' => 'select',
247 'options' => charitable_get_location_helper()->get_countries(),
248 'priority' => 32,
249 'required' => false,
250 'value' => $this->get_user_value( 'donor_country', charitable_get_option( 'country' ) ),
251 ),
252 'phone' => array(
253 'label' => __( 'Phone', 'charitable' ),
254 'type' => 'text',
255 'priority' => 34,
256 'required' => false,
257 'value' => $this->get_user_value( 'donor_phone' ),
258 ),
259 ),
260 $this
261 );
262
263 uasort( $address_fields, 'charitable_priority_sort' );
264
265 return $address_fields;
266 }
267
268 /**
269 * Return the social fields.
270 *
271 * @since 1.0.0
272 *
273 * @return array
274 */
275 public function get_social_fields() {
276 $social_fields = apply_filters( 'charitable_user_social_fields', array(
277 'user_url' => array(
278 'label' => __( 'Your Website', 'charitable' ),
279 'type' => 'url',
280 'priority' => 42,
281 'required' => false,
282 'value' => $this->get_user_value( 'user_url' ),
283 ),
284 'twitter' => array(
285 'label' => __( 'Twitter', 'charitable' ),
286 'type' => 'text',
287 'priority' => 44,
288 'required' => false,
289 'value' => $this->get_user_value( 'twitter' ),
290 ),
291 'facebook' => array(
292 'label' => __( 'Facebook', 'charitable' ),
293 'type' => 'text',
294 'priority' => 46,
295 'required' => false,
296 'value' => $this->get_user_value( 'facebook' ),
297 ),
298 ), $this );
299
300 uasort( $social_fields, 'charitable_priority_sort' );
301
302 return $social_fields;
303 }
304
305 /**
306 * Maybe add communication preferences fields.
307 *
308 * @since 1.6.2
309 *
310 * @param array $fields The existing profile form fields.
311 * @return array
312 */
313 public function maybe_get_communication_preferences_fields( $fields ) {
314 if ( ! charitable_is_contact_consent_activated() ) {
315 return $fields;
316 }
317
318 $donor = $this->get_user()->get_donor();
319
320 if ( array_key_exists( 'contact_consent', $_POST ) ) {
321 $consent = $_POST['contact_consent'];
322 } elseif ( is_null( $donor ) ) {
323 $consent = false;
324 } else {
325 $consent = $donor->contact_consent;
326 }
327
328 /**
329 * Filter the communication preferences fields.
330 *
331 * @since 1.6.2
332 *
333 * @param array $communication_fields List of fields.
334 * @param Charitable_Profile_Form $form Instance of `Charitable_Profile_Form`.
335 */
336 $communication_fields = apply_filters( 'charitable_user_communication_preferences_fields', array(
337 'contact_consent' => array(
338 'type' => 'checkbox',
339 'label' => charitable_get_option( 'contact_consent_label', __( 'Yes, I am happy for you to contact me via email or phone.', 'charitable' ) ),
340 'priority' => 8,
341 'required' => false,
342 'checked' => $consent,
343 ),
344 ), $this );
345
346 if ( empty( $communication_fields ) ) {
347 return $fields;
348 }
349
350 uasort( $fields, 'charitable_priority_sort' );
351
352 return array_merge( $fields, array(
353 'communication_fields' => array(
354 'legend' => __( 'Communication Preferences', 'charitable' ),
355 'type' => 'fieldset',
356 'fields' => $communication_fields,
357 'priority' => 60,
358 ),
359 ) );
360 }
361
362 /**
363 * Profile fields to be displayed.
364 *
365 * @since 1.0.0
366 *
367 * @return array[]
368 */
369 public function get_fields() {
370 $fields = apply_filters( 'charitable_user_profile_fields', array(
371 'user_fields' => array(
372 'legend' => __( 'Your Details', 'charitable' ),
373 'type' => 'fieldset',
374 'fields' => $this->get_user_fields(),
375 'priority' => 0,
376 ),
377 'password_fields' => array(
378 'legend' => __( 'Change Your Password', 'charitable' ),
379 'type' => 'fieldset',
380 'fields' => $this->get_password_fields(),
381 'priority' => 10,
382 ),
383 'address_fields' => array(
384 'legend' => __( 'Your Address', 'charitable' ),
385 'type' => 'fieldset',
386 'fields' => $this->get_address_fields(),
387 'priority' => 20,
388 ),
389 'social_fields' => array(
390 'legend' => __( 'Your Social Profiles', 'charitable' ),
391 'type' => 'fieldset',
392 'fields' => $this->get_social_fields(),
393 'priority' => 40,
394 ),
395 ), $this );
396
397 $fields = $this->maybe_get_communication_preferences_fields( $fields );
398
399 uasort( $fields, 'charitable_priority_sort' );
400
401 return $fields;
402 }
403
404 /**
405 * Retrieve hidden fields.
406 *
407 * @since 1.6.2
408 *
409 * @return array
410 */
411 public function get_hidden_fields() {
412 return array_merge( parent::get_hidden_fields(), array(
413 'current_email' => $this->get_user()->get_email(),
414 ) );
415 }
416
417 /**
418 * The fields displayed on the password form.
419 *
420 * @since 1.4.0
421 *
422 * @return array[]
423 */
424 public function get_password_fields() {
425 $password_fields = apply_filters( 'charitable_user_profile_password_fields', array(
426 'current_pass' => array(
427 'priority' => 2,
428 'type' => 'password',
429 'label' => __( 'Current Password (leave blank to leave unchanged)', 'charitable' ),
430 'value' => '',
431 'required' => false,
432 ),
433 'user_pass' => array(
434 'priority' => 4,
435 'type' => 'password',
436 'label' => __( 'New Password (leave blank to leave unchanged)', 'charitable' ),
437 'required' => false,
438 ),
439 'user_pass_repeat' => array(
440 'priority' => 6,
441 'type' => 'password',
442 'label' => __( 'New Password (again)', 'charitable' ),
443 'required' => false,
444 ),
445 ), $this );
446
447 uasort( $password_fields, 'charitable_priority_sort' );
448
449 return $password_fields;
450 }
451
452 /**
453 * Update profile after form submission.
454 *
455 * @since 1.0.0
456 *
457 * @return void
458 */
459 public static function update_profile() {
460 $form = new Charitable_Profile_Form();
461
462 if ( ! $form->validate_nonce() || ! $form->validate_honeypot() ) {
463 charitable_get_notices()->add_error( __( 'Unfortunately, we were unable to verify your form submission. Please reload the page and try again.', 'charitable' ) );
464 return;
465 }
466
467 $user = $form->get_user();
468
469 /* Verify that the user is logged in. */
470 if ( 0 == $user->ID ) {
471 return;
472 }
473
474 $fields = $form->get_merged_fields();
475
476 /**
477 * Filter the profile values.
478 */
479 $submitted = apply_filters(
480 'charitable_profile_update_values',
481 $form->get_submitted_values(),
482 $fields,
483 $form
484 );
485
486 /* Remove the current_pass and user_pass_repeat fields, if set. */
487 unset(
488 $submitted['current_pass'],
489 $submitted['user_pass_repeat']
490 );
491
492 $valid = $form->check_required_fields( $fields );
493
494 if ( $valid && $form->is_changing_password() ) {
495 $valid = $form->validate_password_change();
496 }
497
498 if ( $valid && $form->is_changing_email() ) {
499 $valid = $form->validate_email_change();
500 }
501
502 if ( $valid ) {
503 $user->update_profile( $submitted, array_keys( $fields ) );
504
505 charitable_get_notices()->add_success( __( 'Your profile has been updated.', 'charitable' ) );
506
507 do_action( 'charitable_profile_updated', $submitted, $fields, $form );
508 }
509 }
510
511 /**
512 * Check whether the password is being changed.
513 *
514 * @since 1.4.0
515 *
516 * @return boolean
517 */
518 public function is_changing_password() {
519 if ( ! isset( $_POST['user_pass'] ) || empty( $_POST['user_pass'] ) ) {
520 return false;
521 }
522
523 if ( ! isset( $_POST['current_pass'] ) || empty( $_POST['current_pass'] ) ) {
524 return false;
525 }
526
527 return true;
528 }
529
530 /**
531 * Changes a password if the current password is correct and the repeat matches the new password.
532 *
533 * @since 1.4.0
534 *
535 * @return boolean
536 */
537 public function validate_password_change() {
538 /* The current password must be correct. */
539 if ( false == wp_check_password( $_POST['current_pass'], $this->get_user()->user_pass ) ) {
540 charitable_get_notices()->add_error( __( 'Current password is incorrect.', 'charitable' ) );
541 return false;
542 }
543
544 /* The new password must match the repeat (if set). */
545 if ( isset( $_POST['user_pass_repeat'] ) && $_POST['user_pass_repeat'] != $_POST['user_pass'] ) {
546 charitable_get_notices()->add_error( __( 'New passwords did not match.', 'charitable' ) );
547 return false;
548 }
549
550 return true;
551 }
552
553 /**
554 * Check whether the email address is being changed.
555 *
556 * @since 1.6.2
557 *
558 * @return boolean
559 */
560 public function is_changing_email() {
561 if ( ! isset( $_POST['user_email'] ) || empty( $_POST['user_email'] ) ) {
562 return false;
563 }
564
565 if ( ! isset( $_POST['current_email'] ) ) {
566 return $_POST['user_email'] != $this->get_user()->get_email();
567 }
568
569 return $_POST['user_email'] != $_POST['current_email'];
570 }
571
572 /**
573 * Validate the email change.
574 *
575 * @since 1.6.2
576 *
577 * @return boolean
578 */
579 public function validate_email_change() {
580 if ( 0 != charitable_get_donor_id_by_email( $_POST['user_email'] ) ) {
581 charitable_get_notices()->add_error(
582 __( 'This email address is already in use.', 'charitable' )
583 );
584 return false;
585 }
586
587 return true;
588 }
589
590 /**
591 * Return a user's set value for a particular value, or return the default value.
592 *
593 * @since 1.5.7
594 *
595 * @param string $key The property we're getting the value for.
596 * @param string $default The fallback value.
597 * @return string
598 */
599 protected function get_user_prop_or_default( $key, $default ) {
600 $user = $this->get_user();
601
602 return $user && $user->has_prop( $key ) ? $user->get( $key ) : $default;
603 }
604
605 /**
606 * Add the charitable_user_profile_after_fields hook but fire off a deprecated notice.
607 *
608 * @deprecated 1.4.0
609 * @since 1.4.0
610 *
611 * @return void
612 */
613 public static function add_deprecated_charitable_user_profile_after_fields_hook( $form ) {
614 if ( ! has_action( 'charitable_user_profile_after_fields' ) ) {
615 return;
616 }
617
618 charitable_get_deprecated()->doing_it_wrong(
619 __METHOD__,
620 __( 'charitable_user_profile_after_fields hook has been removed. Use charitable_form_after_fields instead.', 'charitable' ),
621 '1.4.0'
622 );
623
624 if ( 'Charitable_Profile_Form' == get_class( $form ) ) {
625 do_action( 'charitable_user_profile_after_fields', $form );
626 }
627 }
628 }
629
630 endif;
631