PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.7.0.12
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.7.0.12
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.12, at includes/forms/class-charitable-profile-form.php

713 lines 18.3 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 add_filter( 'charitable_user_fields', array( $this, 'add_avatar_field' ), 10, 2 );
73 add_filter( 'charitable_profile_update_values', array( $this, 'save_avatar' ), 10, 3 );
74 }
75
76 /**
77 * Return the current user's Charitable_User object.
78 *
79 * @since 1.0.0
80 *
81 * @return Charitable_User
82 */
83 public function get_user() {
84 if ( ! isset( $this->user ) ) {
85 $this->user = new Charitable_User( wp_get_current_user() );
86 }
87
88 return $this->user;
89 }
90
91 /**
92 * Returns the value of a particular key.
93 *
94 * @since 1.0.0
95 *
96 * @param string $key The key of the data we are searching for.
97 * @param string $default Optional. The value that will be used if none is set.
98 * @return mixed
99 */
100 public function get_user_value( $key, $default = '' ) {
101 if ( isset( $_POST[ $key ] ) ) {
102 return $_POST[ $key ];
103 }
104
105 $value = $this->get_user_prop_or_default( $key, $default );
106
107 /**
108 * Deprecated filter. Use the filter below instead.
109 *
110 * @deprecated 1.8.0
111 *
112 * @since 1.0.0
113 * @since 1.5.7 Deprecated.
114 *
115 * @param string $value The value.
116 * @param string $key The key of the value.
117 * @param Charitable_User $user Instance of `Charitable_User`.
118 */
119 $value = apply_filters( 'charitable_campaign_submission_user_value', $value, $key, $this->get_user() );
120
121 /**
122 * Filter the set value for a particular key.
123 *
124 * @since 1.5.7
125 *
126 * @param string $value The value.
127 * @param string $key The key of the value.
128 * @param Charitable_User $user Instance of `Charitable_User`.
129 */
130 return apply_filters( 'charitable_profile_value', $value, $key, $this->get_user() );
131 }
132
133 /**
134 * Return the core user fields.
135 *
136 * @since 1.0.0
137 *
138 * @return array
139 */
140 public function get_user_fields() {
141 $user_fields = apply_filters( 'charitable_user_fields', array(
142 'username' => array(
143 'type' => 'paragraph',
144 'priority' => '',
145 'content' => sprintf(
146 /* translators: %s: username */
147 __( 'Username: %s.', 'charitable' ),
148 $this->get_user()->user_login
149 ),
150 ),
151 'first_name' => array(
152 'label' => __( 'First name', 'charitable' ),
153 'type' => 'text',
154 'priority' => 4,
155 'required' => true,
156 'value' => $this->get_user_value( 'first_name' ),
157 ),
158 'last_name' => array(
159 'label' => __( 'Last name', 'charitable' ),
160 'type' => 'text',
161 'priority' => 6,
162 'required' => true,
163 'value' => $this->get_user_value( 'last_name' ),
164 ),
165 'user_email' => array(
166 'label' => __( 'Email', 'charitable' ),
167 'type' => 'email',
168 'required' => true,
169 'priority' => 8,
170 'value' => $this->get_user_value( 'user_email' ),
171 ),
172 'organisation' => array(
173 'label' => __( 'Organization', 'charitable' ),
174 'type' => 'text',
175 'priority' => 10,
176 'required' => false,
177 'value' => $this->get_user_value( 'organisation' ),
178 ),
179 'description' => array(
180 'label' => __( 'Bio', 'charitable' ),
181 'type' => 'textarea',
182 'required' => false,
183 'priority' => 12,
184 'value' => $this->get_user_value( 'description' ),
185 ),
186 ), $this );
187
188 uasort( $user_fields, 'charitable_priority_sort' );
189
190 return $user_fields;
191 }
192
193 /**
194 * Return the user's address fields.
195 *
196 * @since 1.0.0
197 *
198 * @return array
199 */
200 public function get_address_fields() {
201 /**
202 * Filter the list of user address fields.
203 *
204 * @since 1.0.0
205 *
206 * @param array $fields The fields in the form.
207 * @param Charitable_Profile_Form $form The profile form.
208 */
209 $address_fields = apply_filters(
210 'charitable_user_address_fields',
211 array(
212 'address' => array(
213 'label' => __( 'Address', 'charitable' ),
214 'type' => 'text',
215 'priority' => 22,
216 'required' => false,
217 'value' => $this->get_user_value( 'donor_address' ),
218 ),
219 'address_2' => array(
220 'label' => __( 'Address 2', 'charitable' ),
221 'type' => 'text',
222 'priority' => 24,
223 'required' => false,
224 'value' => $this->get_user_value( 'donor_address_2' ),
225 ),
226 'city' => array(
227 'label' => __( 'City', 'charitable' ),
228 'type' => 'text',
229 'priority' => 26,
230 'required' => false,
231 'value' => $this->get_user_value( 'donor_city' ),
232 ),
233 'state' => array(
234 'label' => __( 'State', 'charitable' ),
235 'type' => 'text',
236 'priority' => 28,
237 'required' => false,
238 'value' => $this->get_user_value( 'donor_state' ),
239 ),
240 'postcode' => array(
241 'label' => __( 'Postcode / ZIP code', 'charitable' ),
242 'type' => 'text',
243 'priority' => 30,
244 'required' => false,
245 'value' => $this->get_user_value( 'donor_postcode' ),
246 ),
247 'country' => array(
248 'label' => __( 'Country', 'charitable' ),
249 'type' => 'select',
250 'options' => charitable_get_location_helper()->get_countries(),
251 'priority' => 32,
252 'required' => false,
253 'value' => $this->get_user_value( 'donor_country', charitable_get_option( 'country' ) ),
254 ),
255 'phone' => array(
256 'label' => __( 'Phone', 'charitable' ),
257 'type' => 'text',
258 'priority' => 34,
259 'required' => false,
260 'value' => $this->get_user_value( 'donor_phone' ),
261 ),
262 ),
263 $this
264 );
265
266 uasort( $address_fields, 'charitable_priority_sort' );
267
268 return $address_fields;
269 }
270
271 /**
272 * Return the social fields.
273 *
274 * @since 1.0.0
275 *
276 * @return array
277 */
278 public function get_social_fields() {
279 $social_fields = apply_filters( 'charitable_user_social_fields', array(
280 'user_url' => array(
281 'label' => __( 'Your Website', 'charitable' ),
282 'type' => 'url',
283 'priority' => 42,
284 'required' => false,
285 'value' => $this->get_user_value( 'user_url' ),
286 ),
287 'twitter' => array(
288 'label' => __( 'Twitter', 'charitable' ),
289 'type' => 'text',
290 'priority' => 44,
291 'required' => false,
292 'value' => $this->get_user_value( 'twitter' ),
293 ),
294 'facebook' => array(
295 'label' => __( 'Facebook', 'charitable' ),
296 'type' => 'text',
297 'priority' => 46,
298 'required' => false,
299 'value' => $this->get_user_value( 'facebook' ),
300 ),
301 ), $this );
302
303 uasort( $social_fields, 'charitable_priority_sort' );
304
305 return $social_fields;
306 }
307
308 /**
309 * Maybe add communication preferences fields.
310 *
311 * @since 1.6.2
312 *
313 * @param array $fields The existing profile form fields.
314 * @return array
315 */
316 public function maybe_get_communication_preferences_fields( $fields ) {
317 if ( ! charitable_is_contact_consent_activated() ) {
318 return $fields;
319 }
320
321 $donor = $this->get_user()->get_donor();
322
323 if ( array_key_exists( 'contact_consent', $_POST ) ) {
324 $consent = $_POST['contact_consent'];
325 } elseif ( is_null( $donor ) ) {
326 $consent = false;
327 } else {
328 $consent = $donor->contact_consent;
329 }
330
331 /**
332 * Filter the communication preferences fields.
333 *
334 * @since 1.6.2
335 *
336 * @param array $communication_fields List of fields.
337 * @param Charitable_Profile_Form $form Instance of `Charitable_Profile_Form`.
338 */
339 $communication_fields = apply_filters( 'charitable_user_communication_preferences_fields', array(
340 'contact_consent' => array(
341 'type' => 'checkbox',
342 'label' => charitable_get_option( 'contact_consent_label', __( 'Yes, I am happy for you to contact me via email or phone.', 'charitable' ) ),
343 'priority' => 8,
344 'required' => false,
345 'checked' => $consent,
346 ),
347 ), $this );
348
349 if ( empty( $communication_fields ) ) {
350 return $fields;
351 }
352
353 uasort( $fields, 'charitable_priority_sort' );
354
355 return array_merge( $fields, array(
356 'communication_fields' => array(
357 'legend' => __( 'Communication Preferences', 'charitable' ),
358 'type' => 'fieldset',
359 'fields' => $communication_fields,
360 'priority' => 60,
361 ),
362 ) );
363 }
364
365 /**
366 * Profile fields to be displayed.
367 *
368 * @since 1.0.0
369 *
370 * @return array[]
371 */
372 public function get_fields() {
373 $fields = apply_filters( 'charitable_user_profile_fields', array(
374 'user_fields' => array(
375 'legend' => __( 'Your Details', 'charitable' ),
376 'type' => 'fieldset',
377 'fields' => $this->get_user_fields(),
378 'priority' => 0,
379 ),
380 'password_fields' => array(
381 'legend' => __( 'Change Your Password', 'charitable' ),
382 'type' => 'fieldset',
383 'fields' => $this->get_password_fields(),
384 'priority' => 10,
385 ),
386 'address_fields' => array(
387 'legend' => __( 'Your Address', 'charitable' ),
388 'type' => 'fieldset',
389 'fields' => $this->get_address_fields(),
390 'priority' => 20,
391 ),
392 'social_fields' => array(
393 'legend' => __( 'Your Social Profiles', 'charitable' ),
394 'type' => 'fieldset',
395 'fields' => $this->get_social_fields(),
396 'priority' => 40,
397 ),
398 ), $this );
399
400 $fields = $this->maybe_get_communication_preferences_fields( $fields );
401
402 uasort( $fields, 'charitable_priority_sort' );
403
404 return $fields;
405 }
406
407 /**
408 * Retrieve hidden fields.
409 *
410 * @since 1.6.2
411 *
412 * @return array
413 */
414 public function get_hidden_fields() {
415 return array_merge( parent::get_hidden_fields(), array(
416 'current_email' => $this->get_user()->get_email(),
417 ) );
418 }
419
420 /**
421 * The fields displayed on the password form.
422 *
423 * @since 1.4.0
424 *
425 * @return array[]
426 */
427 public function get_password_fields() {
428 $password_fields = apply_filters( 'charitable_user_profile_password_fields', array(
429 'current_pass' => array(
430 'priority' => 2,
431 'type' => 'password',
432 'label' => __( 'Current Password (leave blank to leave unchanged)', 'charitable' ),
433 'value' => '',
434 'required' => false,
435 ),
436 'user_pass' => array(
437 'priority' => 4,
438 'type' => 'password',
439 'label' => __( 'New Password (leave blank to leave unchanged)', 'charitable' ),
440 'required' => false,
441 ),
442 'user_pass_repeat' => array(
443 'priority' => 6,
444 'type' => 'password',
445 'label' => __( 'New Password (again)', 'charitable' ),
446 'required' => false,
447 ),
448 ), $this );
449
450 uasort( $password_fields, 'charitable_priority_sort' );
451
452 return $password_fields;
453 }
454
455 /**
456 * Update profile after form submission.
457 *
458 * @since 1.0.0
459 *
460 * @return void
461 */
462 public static function update_profile() {
463 $form = new Charitable_Profile_Form();
464
465 if ( ! $form->validate_nonce() || ! $form->validate_honeypot() ) {
466 charitable_get_notices()->add_error( __( 'Unfortunately, we were unable to verify your form submission. Please reload the page and try again.', 'charitable' ) );
467 return;
468 }
469
470 $user = $form->get_user();
471
472 /* Verify that the user is logged in. */
473 if ( 0 == $user->ID ) {
474 return;
475 }
476
477 $fields = $form->get_merged_fields();
478
479 /**
480 * Filter the profile values.
481 */
482 $submitted = apply_filters(
483 'charitable_profile_update_values',
484 $form->get_submitted_values(),
485 $fields,
486 $form
487 );
488
489 /* Remove the current_pass and user_pass_repeat fields, if set. */
490 unset(
491 $submitted['current_pass'],
492 $submitted['user_pass_repeat']
493 );
494
495 $valid = $form->check_required_fields( $fields );
496
497 if ( $valid && $form->is_changing_password() ) {
498 $valid = $form->validate_password_change();
499 }
500
501 if ( $valid && $form->is_changing_email() ) {
502 $valid = $form->validate_email_change();
503 }
504
505 if ( $valid ) {
506 $user->update_profile( $submitted, array_keys( $fields ) );
507
508 charitable_get_notices()->add_success( __( 'Your profile has been updated.', 'charitable' ) );
509
510 do_action( 'charitable_profile_updated', $submitted, $fields, $form );
511 }
512 }
513
514 /**
515 * Check whether the password is being changed.
516 *
517 * @since 1.4.0
518 *
519 * @return boolean
520 */
521 public function is_changing_password() {
522 if ( ! isset( $_POST['user_pass'] ) || empty( $_POST['user_pass'] ) ) {
523 return false;
524 }
525
526 if ( ! isset( $_POST['current_pass'] ) || empty( $_POST['current_pass'] ) ) {
527 return false;
528 }
529
530 return true;
531 }
532
533 /**
534 * Changes a password if the current password is correct and the repeat matches the new password.
535 *
536 * @since 1.4.0
537 *
538 * @return boolean
539 */
540 public function validate_password_change() {
541 /* The current password must be correct. */
542 if ( false == wp_check_password( $_POST['current_pass'], $this->get_user()->user_pass ) ) {
543 charitable_get_notices()->add_error( __( 'Current password is incorrect.', 'charitable' ) );
544 return false;
545 }
546
547 /* The new password must match the repeat (if set). */
548 if ( isset( $_POST['user_pass_repeat'] ) && $_POST['user_pass_repeat'] != $_POST['user_pass'] ) {
549 charitable_get_notices()->add_error( __( 'New passwords did not match.', 'charitable' ) );
550 return false;
551 }
552
553 return true;
554 }
555
556 /**
557 * Check whether the email address is being changed.
558 *
559 * @since 1.6.2
560 *
561 * @return boolean
562 */
563 public function is_changing_email() {
564 if ( ! isset( $_POST['user_email'] ) || empty( $_POST['user_email'] ) ) {
565 return false;
566 }
567
568 if ( ! isset( $_POST['current_email'] ) ) {
569 return $_POST['user_email'] != $this->get_user()->get_email();
570 }
571
572 return $_POST['user_email'] != $_POST['current_email'];
573 }
574
575 /**
576 * Validate the email change.
577 *
578 * @since 1.6.2
579 *
580 * @return boolean
581 */
582 public function validate_email_change() {
583 if ( 0 != charitable_get_donor_id_by_email( $_POST['user_email'] ) ) {
584 charitable_get_notices()->add_error(
585 __( 'This email address is already in use.', 'charitable' )
586 );
587 return false;
588 }
589
590 return true;
591 }
592
593 /**
594 * Return a user's set value for a particular value, or return the default value.
595 *
596 * @since 1.5.7
597 *
598 * @param string $key The property we're getting the value for.
599 * @param string $default The fallback value.
600 * @return string
601 */
602 protected function get_user_prop_or_default( $key, $default ) {
603 $user = $this->get_user();
604
605 return $user && $user->has_prop( $key ) ? $user->get( $key ) : $default;
606 }
607
608 /**
609 * Add the charitable_user_profile_after_fields hook but fire off a deprecated notice.
610 *
611 * @deprecated 1.4.0
612 * @since 1.4.0
613 *
614 * @return void
615 */
616 public static function add_deprecated_charitable_user_profile_after_fields_hook( $form ) {
617 if ( ! has_action( 'charitable_user_profile_after_fields' ) ) {
618 return;
619 }
620
621 charitable_get_deprecated()->doing_it_wrong(
622 __METHOD__,
623 __( 'charitable_user_profile_after_fields hook has been removed. Use charitable_form_after_fields instead.', 'charitable' ),
624 '1.4.0'
625 );
626
627 if ( 'Charitable_Profile_Form' == get_class( $form ) ) {
628 do_action( 'charitable_user_profile_after_fields', $form );
629 }
630 }
631
632 /**
633 * Add avatar section to user profile form.
634 *
635 * @param array[] $fields
636 * @param Charitable_Profile_Form $form
637 * @return array[]
638 * @access public
639 * @since 1.0.0
640 */
641 public function add_avatar_field( $fields, $form ) {
642 $user = $form->get_user();
643 $user_avatar = new Charitable_User_Avatar();
644 $avatar = $user_avatar->get_user_avatar( false, $user );
645
646 if ( ! $avatar && charitable_user_has_gravatar( $user->user_email ) ) {
647 $avatar = get_avatar( $user->ID, 100 );
648 }
649
650 $fields['avatar'] = apply_filters( 'charitable_user_avatar_field_args', array(
651 'label' => __( 'Your Profile Photo', 'charitable-user-avatar' ),
652 'type' => 'picture',
653 'uploader' => true,
654 'size' => 100,
655 'value' => $avatar,
656 'priority' => 14,
657 'fullwidth' => true,
658 ) );
659
660 return $fields;
661 }
662
663 /**
664 * Upload avatar and add file fields to the submitted fields.
665 *
666 * @param array $submitted The values submitted by the user.
667 * @param array[] $fields The fields in the form.
668 * @param Charitable_Profile_Form $form The profile form object.
669 * @return array
670 * @access public
671 * @since 1.0.0
672 */
673 public function save_avatar( $submitted, $fields, $form ) {
674 if ( isset( $_FILES ) && isset( $_FILES['avatar'] ) ) {
675
676 $attachment_id = $form->upload_post_attachment( 'avatar', 0 );
677
678 if ( ! is_wp_error( $attachment_id ) ) {
679
680 $submitted['avatar'] = $attachment_id;
681
682 /* Delete the previously upload avatar. */
683 $old_avatar = get_user_meta( $form->get_user()->ID, 'avatar', true );
684
685 if ( ! empty( $old_avatar ) ) {
686
687 wp_delete_attachment( $old_avatar );
688
689 }
690
691 update_user_meta( $form->get_user()->ID, 'avatar', $attachment_id );
692
693 } else {
694 /**
695 * Handle image upload error.
696 *
697 * @todo
698 */
699 }//end if
700 } elseif ( ! array_key_exists( 'avatar', $submitted ) ) {
701
702 /* The picture has been removed. */
703 $submitted['avatar'] = '';
704
705 }//end if
706
707 return $submitted;
708 }
709
710 }
711
712 endif;
713