PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.6.28
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.6.28
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 1.7.0.9 1.8.0 All 210 releases
charitable / includes / users / class-charitable-user.php

class-charitable-user.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.6.28, at includes/users/class-charitable-user.php

1,070 lines 26.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Contains the class that models users in Charitable.
4 *
5 * There are several different user roles in Charitable, and one user
6 * may be more than one. People who make donations get the "donor" role;
7 * people who create campaigns (via Charitable Ambassadors) get
8 * the "campaign_creator" role; people who create fundraisers for campaigns
9 * get the "fundraiser" role.
10 *
11 * @version 1.0.0
12 * @package Charitable/Classes/Charitable_User
13 * @author Eric Daams
14 * @copyright Copyright (c) 2019, Studio 164a
15 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
16 */
17
18 // Exit if accessed directly.
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit;
21 }
22
23 if ( ! class_exists( 'Charitable_User' ) ) :
24
25 /**
26 * Charitable_User
27 *
28 * @since 1.0.0
29 *
30 * @property string $nickname
31 * @property string $description
32 * @property string $user_description
33 * @property string $first_name
34 * @property string $user_firstname
35 * @property string $last_name
36 * @property string $user_lastname
37 * @property string $user_login
38 * @property string $user_pass
39 * @property string $user_nicename
40 * @property string $user_email
41 * @property string $user_url
42 * @property string $user_registered
43 * @property string $user_activation_key
44 * @property string $user_status
45 * @property int $user_level
46 * @property string $display_name
47 * @property string $spam
48 * @property string $deleted
49 * @property string $locale
50 */
51 class Charitable_User extends WP_User {
52
53 /**
54 * The donor ID.
55 *
56 * NOTE: This is not the same as the user ID.
57 *
58 * @since 1.0.0
59 *
60 * @var int
61 */
62 protected $donor_id;
63
64 /**
65 * A mapping of user keys.
66 *
67 * @since 1.4.0
68 *
69 * @var string[]
70 */
71 protected $mapped_keys;
72
73 /**
74 * Core keys.
75 *
76 * @since 1.4.0
77 *
78 * @var string[]
79 */
80 protected $core_keys;
81
82 /**
83 * Create class object.
84 *
85 * @since 1.0.0
86 *
87 * @param int|string|stdClass|WP_User $id User's ID, a WP_User object, or a user object from the DB.
88 * @param string $name Optional. User's username.
89 * @param int $blog_id Optional Blog ID, defaults to current blog.
90 * @return void
91 */
92 public function __construct( $id = 0, $name = '', $blog_id = '' ) {
93 parent::__construct( $id, $name, $blog_id );
94 }
95
96 /**
97 * Create object using a donor ID.
98 *
99 * @since 1.0.0
100 *
101 * @param int $donor_id The donor ID.
102 * @return Charitable_user
103 */
104 public static function init_with_donor( $donor_id ) {
105 $user_id = charitable_get_table( 'donors' )->get_user_id( $donor_id );
106 $user = charitable_get_user( $user_id );
107 $user->set_donor_id( $donor_id );
108 return $user;
109 }
110
111 /**
112 * Magic getter method. Looks for the specified key in the mapped keys before using WP_User's __get method.
113 *
114 * @since 1.0.0
115 *
116 * @param string $key The key to retrieve.
117 * @return mixed
118 */
119 public function __get( $key ) {
120 return parent::__get( $this->map_key( $key ) );
121 }
122
123 /**
124 * Display the donor name when printing the object.
125 *
126 * @since 1.0.0
127 *
128 * @return string
129 */
130 public function __toString() {
131 return $this->get_name();
132 }
133
134 /**
135 * Determine whether a property or meta key is set
136 *
137 * Consults the users and usermeta tables.
138 *
139 * @since 1.5.0
140 *
141 * @param string $key Property.
142 * @return boolean
143 */
144 public function has_prop( $key ) {
145 return parent::has_prop( $this->map_key( $key ) );
146 }
147
148 /**
149 * Returns whether the user is logged in.
150 *
151 * @since 1.0.0
152 *
153 * @return boolean
154 */
155 public function is_logged_in() {
156 return 0 !== $this->ID;
157 }
158
159 /**
160 * Set the donor ID of this user.
161 *
162 * @since 1.0.0
163 *
164 * @param int $donor_id The Donor ID.
165 * @return void
166 */
167 public function set_donor_id( $donor_id ) {
168 $this->donor_id = $donor_id;
169 }
170
171 /**
172 * Return the donor ID of this user.
173 *
174 * @since 1.0.0
175 *
176 * @return int|false $donor_id
177 */
178 public function get_donor_id() {
179 if ( isset( $this->donor_id ) || ! is_null( $this->get_donor() ) ) {
180 return $this->donor_id;
181 }
182
183 return false;
184 }
185
186 /**
187 * Return the donor record.
188 *
189 * @since 1.0.0
190 *
191 * @return Object|null Object if a donor record could be matched. null if user is logged out or no donor record found.
192 */
193 public function get_donor() {
194 if ( ! $this->is_logged_in() && ! isset( $this->donor_id ) ) {
195 return null;
196 }
197
198 if ( isset( $this->donor_id ) ) {
199
200 $donor = wp_cache_get( $this->donor_id, 'donors' );
201
202 if ( is_object( $donor ) ) {
203 return $donor;
204 }
205
206 $donor = charitable_get_table( 'donors' )->get( $this->donor_id );
207
208 } else {
209
210 $donor = charitable_get_table( 'donors' )->get_by( 'email', $this->get( 'user_email' ) );
211
212 if ( ! is_object( $donor ) ) {
213 return null;
214 }
215
216 $this->donor_id = $donor->donor_id;
217
218 }//end if
219
220 wp_cache_add( $this->donor_id, $donor, 'donors' );
221
222 return $donor;
223 }
224
225 /**
226 * Returns whether the user has ever made a donation.
227 *
228 * @since 1.0.0
229 *
230 * @return boolean
231 */
232 public function is_donor() {
233 return ! is_null( $this->get_donor() );
234 }
235
236 /**
237 * Returns whether the user has verified their email address.
238 *
239 * @since 1.5.0
240 *
241 * @return int If verified, return 1. Otherwise return 0.
242 */
243 public function is_verified() {
244 return absint( get_user_meta( $this->ID, '_charitable_user_verified', true ) );
245 }
246
247 /**
248 * Mark a user as verified.
249 *
250 * @since 1.5.0
251 *
252 * @param boolean $verified Whether the user is verified.
253 * @return int|boolean Meta ID if the key didn't exist, true on successful update, false on failure.
254 */
255 public function mark_as_verified( $verified ) {
256 $verified = update_user_meta( $this->ID, '_charitable_user_verified', $verified );
257
258 if ( ! $verified ) {
259 return $verified;
260 }
261
262 /* Check for an existing donor account. */
263 $donor_id = $this->get_donor_id();
264
265 if ( $donor_id ) {
266 $donor = new Charitable_Donor( $donor_id );
267 $donor->set_user_id( $this->ID );
268 }
269
270 /**
271 * Do something when a user is verified.
272 *
273 * @since 1.6.23
274 *
275 * @param Charitable_User $user The user object.
276 */
277 do_action( 'charitable_user_verified', $this );
278
279 return $verified;
280 }
281
282 /**
283 * Returns the email address of the donor.
284 *
285 * @since 1.0.0
286 *
287 * @return string
288 */
289 public function get_email() {
290 if ( $this->get_donor() ) {
291 $email = $this->get_donor()->email;
292 } else {
293 $email = $this->get( 'user_email' );
294 }
295
296 /**
297 * Filter the user email address.
298 *
299 * @since 1.0.0
300 *
301 * @param string $email The email address.
302 * @param Charitable_User $user This instance of `Charitable_User`.
303 */
304 return apply_filters( 'charitable_user_email', $email, $this );
305 }
306
307 /**
308 * Returns the display name of the user.
309 *
310 * @since 1.0.0
311 *
312 * @return string
313 */
314 public function get_name() {
315 if ( $this->is_donor() ) {
316 $name = rtrim( sprintf( '%s %s', $this->get_donor()->first_name, $this->get_donor()->last_name ) );
317 } else {
318 $name = $this->display_name;
319 }
320
321 if ( ! $name ) {
322 $name = '';
323 }
324
325 return apply_filters( 'charitable_user_name', $name, $this );
326 }
327
328 /**
329 * Returns the first name of the user.
330 *
331 * @since 1.1.0
332 *
333 * @return string
334 */
335 public function get_first_name() {
336 if ( $this->is_donor() && $this->get_donor()->first_name ) {
337 $name = $this->get_donor()->first_name;
338 } else {
339 $name = $this->first_name;
340 }
341
342 return apply_filters( 'charitable_user_first_name', $name, $this );
343 }
344
345 /**
346 * Returns the last name of the user.
347 *
348 * @since 1.1.0
349 *
350 * @return string
351 */
352 public function get_last_name() {
353 if ( $this->is_donor() && $this->get_donor()->last_name ) {
354 $name = $this->get_donor()->last_name;
355 } else {
356 $name = $this->last_name;
357 }
358 return apply_filters( 'charitable_user_last_name', $name, $this );
359 }
360
361 /**
362 * Returns the user's location.
363 *
364 * @since 1.0.0
365 *
366 * @return string
367 */
368 public function get_location() {
369 $city = $this->get( 'donor_city' );
370 $state = $this->get( 'donor_state' );
371 $country = $this->get( 'donor_country' );
372 $location = '';
373
374 if ( strlen( $city ) || strlen( $state ) ) {
375 $region = strlen( $city ) ? $city : $state;
376
377 if ( strlen( $country ) ) {
378 $location = sprintf( '%s, %s', $region, $country );
379 } else {
380 $location = $region;
381 }
382 } elseif ( strlen( $country ) ) {
383 $location = $country;
384 }
385
386 return apply_filters( 'charitable_user_location', $location, $this );
387 }
388
389 /**
390 * Return an array of fields used for the address.
391 *
392 * @since 1.0.0
393 *
394 * @return array
395 */
396 public function get_address_fields() {
397 return apply_filters( 'charitable_user_address_fields', array(
398 'donor_address',
399 'donor_address_2',
400 'donor_city',
401 'donor_state',
402 'donor_postcode',
403 'donor_country',
404 ) );
405 }
406
407 /**
408 * Returns printable address of donor.
409 *
410 * @since 1.0.0
411 *
412 * @param int $donation_id Optional. If set, will return the address provided for the specific donation. Otherwise, returns the current address for the user.
413 * @return string
414 */
415 public function get_address( $donation_id = '' ) {
416 $address_fields = false;
417
418 if ( $donation_id ) {
419
420 $address_fields = get_post_meta( $donation_id, 'donor', true );
421
422 }
423
424 /* If the address fields were not set by the check above, get them from the user meta. */
425 if ( ! is_array( $address_fields ) ) {
426
427 $address_fields = array(
428 'first_name' => $this->get( 'first_name' ),
429 'last_name' => $this->get( 'last_name' ),
430 'company' => $this->get( 'donor_company' ),
431 'address' => $this->get( 'donor_address' ),
432 'address_2' => $this->get( 'donor_address_2' ),
433 'city' => $this->get( 'donor_city' ),
434 'state' => $this->get( 'donor_state' ),
435 'postcode' => $this->get( 'donor_postcode' ),
436 'country' => $this->get( 'donor_country' ),
437 );
438
439 }
440
441 $address_fields = apply_filters( 'charitable_user_address_fields', $address_fields, $this, $donation_id );
442
443 return charitable_get_location_helper()->get_formatted_address( $address_fields );
444 }
445
446 /**
447 * Return all donations made by donor.
448 *
449 * @since 1.0.0
450 *
451 * @param boolean $distinct_donations If true, will only count unique donations.
452 * @return object[]
453 */
454 public function get_donations( $distinct_donations = false ) {
455 return charitable_get_table( 'campaign_donations' )->get_donations_by_donor( $this->get_donor_id(), $distinct_donations );
456 }
457
458 /**
459 * Return the number of donations made by the donor.
460 *
461 * @since 1.0.0
462 *
463 * @param boolean $distinct_donations If true, will only count unique donations.
464 * @return int
465 */
466 public function count_donations( $distinct_donations = false ) {
467 return charitable_get_table( 'campaign_donations' )->count_donations_by_donor( $this->get_donor_id(), $distinct_donations );
468 }
469
470 /**
471 * Return the number of campaigns that the donor has supported.
472 *
473 * @since 1.0.0
474 *
475 * @return int
476 */
477 public function count_campaigns_supported() {
478 return charitable_get_table( 'campaign_donations' )->count_campaigns_supported_by_donor( $this->get_donor_id() );
479 }
480
481 /**
482 * Return the total amount donated by the donor.
483 *
484 * @since 1.0.0
485 *
486 * @param int $campaign_id Optional. If set, returns total donated to this particular campaign.
487 * @return float
488 */
489 public function get_total_donated( $campaign_id = false ) {
490 $amount = wp_cache_get( $this->get_donor_id(), 'charitable_donor_total_donation_amount_' . $campaign_id );
491
492 if ( false === $amount ) {
493
494 $args = apply_filters( 'charitable_user_total_donated_query_args', array(
495 'output' => 'raw',
496 'donor_id' => $this->get_donor_id(),
497 'distinct_donors' => true,
498 'fields' => 'amount',
499 'campaign' => (int) $campaign_id,
500 ), $this );
501
502 $query = new Charitable_Donor_Query( $args );
503
504 $amount = $query->current()->amount;
505
506 wp_cache_set( $this->get_donor_id(), $amount, 'charitable_donor_total_donation_amount_' . $campaign_id );
507 }
508
509 return (float) $amount;
510 }
511
512 /**
513 * Returns the user's avatar as a fully formatted <img> tag.
514 *
515 * By default, this will return the gravatar, but it can
516 * be extended to add support for locally hosted avatars.
517 *
518 * @since 1.0.0
519 *
520 * @param int $size The length and width of the avatar.
521 * @return string
522 */
523 public function get_avatar( $size = 100 ) {
524 /**If you use this filter, return an attachment ID. */
525 $avatar_attachment_id = apply_filters( 'charitable_user_avatar', false, $this );
526
527 /* If we don't have an attachment ID, display the gravatar. */
528 if ( ! $avatar_attachment_id ) {
529 return get_avatar( $this->ID, $size );
530 }
531
532 $img_size = apply_filters( 'charitable_user_avatar_media_size', array( $size, $size ), $size );
533
534 $attachment_src = wp_get_attachment_image_src( $avatar_attachment_id, $img_size );
535
536 /* No image for the given attachment ID? Fall back to the gravatar. */
537 if ( ! $attachment_src ) {
538 return get_avatar( $this->ID, $size );
539 }
540
541 return apply_filters( 'charitable_user_avatar_custom', sprintf( '<img src="%s" alt="%s" class="avatar photo" width="%s" height="%s" />',
542 $attachment_src[0],
543 esc_attr( $this->display_name ),
544 $attachment_src[1],
545 $attachment_src[2]
546 ), $avatar_attachment_id, $size, $this );
547 }
548
549 /**
550 * Return the src of the avatar.
551 *
552 * @since 1.0.0
553 *
554 * @param int $size The length and the width of the avatar.
555 * @return string
556 */
557 public function get_avatar_src( $size = 100 ) {
558 /* If this returns something, we don't need to deal with the gravatar. */
559 $avatar = apply_filters( 'charitable_user_avatar_src', false, $this, $size );
560
561 if ( false === $avatar ) {
562
563 /* The gravatars are returned as fully formatted img tags, so we need to pull out the src. */
564 $gravatar = get_avatar( $this->ID, $size );
565
566 preg_match( "@src='([^']+)'@" , $gravatar, $matches );
567
568 $avatar = array_pop( $matches );
569 }
570
571 return $avatar;
572 }
573
574 /**
575 * Return the campaigns created by the user.
576 *
577 * @since 1.0.0
578 *
579 * @param array $args Optional. Any arguments accepted by WP_Query.
580 * @return WP_Query
581 */
582 public function get_campaigns( $args = array() ) {
583 $defaults = array(
584 'author' => $this->ID,
585 );
586
587 $args = wp_parse_args( $args, $defaults );
588
589 return Charitable_Campaigns::query( $args );
590 }
591
592 /**
593 * Checks whether the user has any current campaigns (i.e. non-expired).
594 *
595 * @since 1.0.0
596 *
597 * @param array $args Query arguments.
598 * @return WP_Query
599 */
600 public function get_current_campaigns( $args = array() ) {
601 $defaults = array(
602 'author' => $this->ID,
603 'meta_query' => array(
604 'relation' => 'OR',
605 array(
606 'key' => '_campaign_end_date',
607 'value' => date( 'Y-m-d H:i:s' ),
608 'compare' => '>=',
609 'type' => 'datetime',
610 ),
611 array(
612 'key' => '_campaign_end_date',
613 'value' => '0',
614 )
615 ),
616 );
617
618 $args = wp_parse_args( $args, $defaults );
619
620 return Charitable_Campaigns::query( $args );
621 }
622
623 /**
624 * Returns all current campaigns by the user.
625 *
626 * @since 1.0.0
627 *
628 * @return WP_Query
629 */
630 public function has_current_campaigns() {
631 return $this->get_current_campaigns()->found_posts;
632 }
633
634 /**
635 * Returns the user's donation and campaign creation activity.
636 *
637 * @see WP_Query
638 * @since 1.0.0
639 *
640 * @param array $args Optional. Any arguments accepted by WP_Query.
641 * @return WP_Query
642 */
643 public function get_activity( $args = array() ) {
644 $defaults = array(
645 'author' => $this->ID,
646 'post_status' => array( 'charitable-completed', 'charitable-preapproved', 'publish' ),
647 'post_type' => array( 'donation', 'campaign' ),
648 'order' => 'DESC',
649 'orderby' => 'date',
650 );
651
652 $args = wp_parse_args( $args, $defaults );
653
654 $args = apply_filters( 'charitable_user_activity_args', $args, $this );
655
656 return new WP_Query( $args );
657 }
658
659 /**
660 * Add a new donor. This may also create a user account for them.
661 *
662 * @since 1.0.0
663 *
664 * @param array $submitted Values submitted by the user.
665 * @return int $donor_id Donor ID.
666 */
667 public function add_donor( $submitted = array() ) {
668 $email = false;
669
670 if ( isset( $submitted['email'] ) ) {
671 $email = $submitted['email'];
672 }
673
674 if ( ! $email && $this->is_logged_in() ) {
675 $email = $this->user_email;
676 }
677
678 /**
679 * Filter whether donors can be added without an email address.
680 *
681 * Prior to Charitable 1.6, this was never permitted. As of Charitable 1.6, donors
682 * without an email address can be added by default, primarily to support manual
683 * donations without an email address. Use this filter to disable that ability.
684 *
685 * NOTE: By default, the public donation form still requires an email address, so this
686 * primarily affects programmatically created donors, or donors created via manual
687 * donations in the admin.
688 *
689 * @see https://github.com/Charitable/Charitable/issues/535
690 *
691 * @since 1.6.0
692 *
693 * @param boolean $permitted Whether donors can be added without an email address.
694 */
695 if ( ! $email && ! charitable_permit_donor_without_email() ) {
696 charitable_get_deprecated()->doing_it_wrong(
697 __METHOD__,
698 __( 'Unable to add donor. Email not set for logged out user.', 'charitable' ),
699 '1.0.0'
700 );
701
702 return 0;
703 }
704
705 /**
706 * Filter the donor values.
707 *
708 * @since 1.0.0
709 *
710 * @param array $donor_values The donor values.
711 * @param Charitable_User $user This instance of `Charitable_User`.
712 * @param array $submitted Submitted values.
713 */
714 $donor_values = apply_filters(
715 'charitable_donor_values',
716 array(
717 'user_id' => $this->ID,
718 'email' => $email,
719 'first_name' => array_key_exists( 'first_name', $submitted ) ? $submitted['first_name'] : $this->first_name,
720 'last_name' => array_key_exists( 'last_name', $submitted ) ? $submitted['last_name'] : $this->last_name,
721 ),
722 $this,
723 $submitted
724 );
725
726 $donor_id = charitable_get_table( 'donors' )->insert( $donor_values );
727
728 /**
729 * If the user is logged in, add the "Donor" role to their account.
730 */
731 if ( $this->is_logged_in() ) {
732 $this->add_role( 'donor' );
733 }
734
735 do_action( 'charitable_after_insert_donor', $donor_id, $this );
736
737 return $donor_id;
738 }
739
740 /**
741 * Insert a new donor with submitted values.
742 *
743 * @since 1.4.0
744 *
745 * @param array $submitted The submitted values.
746 * @param array $keys The keys of fields that are to be updated.
747 * @return int
748 */
749 public static function create_profile( $submitted = array(), $keys = array() ) {
750 $user = new Charitable_User();
751 $user_id = $user->update_profile( $submitted, $keys );
752 return new Charitable_User( $user_id );
753 }
754
755 /**
756 * Update the user's details with submitted values.
757 *
758 * @since 1.0.0
759 *
760 * @param array $submitted The submitted values.
761 * @param array $keys The keys of fields that are to be updated.
762 * @return int
763 */
764 public function update_profile( $submitted = array(), $keys = array() ) {
765 if ( empty( $submitted ) ) {
766 $submitted = $_POST;
767 }
768
769 if ( empty( $keys ) ) {
770 $keys = array_keys( $submitted );
771 }
772
773 $user_id = $this->update_core_user( $submitted );
774
775 /* If there were problems with creating the user, stop here. */
776 if ( ! $user_id ) {
777 return $user_id;
778 }
779
780 /* Create or update the user's donor record. */
781 $this->update_donor_record( $submitted, $keys );
782
783 $this->update_user_meta( $submitted, $keys );
784
785 return $user_id;
786 }
787
788 /**
789 * Create or update a donor record for the current user.
790 *
791 * @since 1.6.2
792 *
793 * @param array $submitted The submitted values.
794 * @param array $keys The keys of fields that are to be updated.
795 * @return int The donor ID, or 0 if none was created or edited.
796 */
797 public function update_donor_record( $submitted, $keys ) {
798 $donor_fields = array_intersect( $keys, charitable_get_donor_keys() );
799
800 if ( array_key_exists( 'user_email', $submitted ) ) {
801 $donor_fields[] = 'email';
802 $submitted['email'] = $submitted['user_email'];
803 }
804
805 if ( empty( $donor_fields ) ) {
806 return 0;
807 }
808
809 $donor_data = array(
810 'user_id' => $this->ID,
811 );
812
813 foreach ( $donor_fields as $field ) {
814 if ( array_key_exists( $field, $submitted ) ) {
815 $value = $submitted[ $field ];
816 } elseif ( 'contact_consent' == $field ) {
817 $value = 0;
818 } else {
819 $value = '';
820 }
821
822 $donor_data[ $field ] = $value;
823 }
824
825 if ( array_key_exists( 'donor_id', $donor_data ) ) {
826 $donor_id = $donor_data['donor_id'];
827 } else {
828 $donor_id = $this->get_donor_id();
829 }
830
831 /* Clear out the cache */
832 wp_cache_delete( $donor_id, 'donors' );
833
834 if ( $donor_id ) {
835 charitable_get_table( 'donors' )->update( $donor_id, $donor_data );
836
837 return $donor_id;
838 }
839
840 return charitable_get_table( 'donors' )->insert( $donor_data );
841 }
842
843 /**
844 * Save core fields of the user (i.e. the wp_users data)
845 *
846 * @uses wp_insert_user
847 *
848 * @since 1.0.0
849 *
850 * @param array $submitted Values submitted by the user.
851 * @return int User ID
852 */
853 public function update_core_user( $submitted ) {
854 $core_fields = array_intersect( array_keys( $submitted ), $this->get_core_keys() );
855
856 if ( empty( $core_fields ) ) {
857 return 0;
858 }
859
860 $values = array();
861
862 /* If we're updating an active user, set the ID */
863 if ( 0 !== $this->ID ) {
864 $values['ID'] = $this->ID;
865 }
866
867 foreach ( $core_fields as $field ) {
868 $values[ $field ] = $submitted[ $field ];
869 }
870
871 /* Set the user's display name based on their name. */
872 $display_name = $this->sanitize_display_name( $values );
873
874 if ( $display_name ) {
875 $values['display_name'] = $display_name;
876 }
877
878 /* Insert the user */
879 if ( 0 == $this->ID ) {
880
881 if ( ! isset( $values['user_pass'] ) || strlen( $values['user_pass'] ) == 0 ) {
882 charitable_get_notices()->add_error( '<strong>ERROR:</strong> Password field is required.' );
883 return false;
884 }
885
886 if ( ! isset( $values['user_login'] ) ) {
887 $values['user_login'] = $values['user_email'];
888 }
889
890 /**
891 * `wp_insert_user` calls `sanitize_user` internally - make the
892 * same call here so `$values['user_login']` matches what is
893 * eventually saved to the database
894 */
895 $values['user_login'] = sanitize_user( $values['user_login'], true );
896
897 $user_id = wp_insert_user( $values );
898
899 if ( is_wp_error( $user_id ) ) {
900 charitable_get_notices()->add_errors_from_wp_error( $user_id );
901 return false;
902 }
903
904 $this->init( self::get_data_by( 'id', $user_id ) );
905
906 $signon = Charitable_User::signon( $values['user_login'], $values['user_pass'] );
907
908 if ( is_wp_error( $signon ) ) {
909 charitable_get_notices()->add_errors_from_wp_error( $signon );
910 return false;
911 }
912
913 /**
914 * Do something after a user has been registered.
915 *
916 * @since 1.0.0
917 *
918 * @param int $user_id The new user's ID.
919 * @param array $values Values submitted to register user.
920 */
921 do_action( 'charitable_after_insert_user', $user_id, $values );
922
923 } else {
924 $values['ID'] = $this->ID;
925 $user_id = wp_update_user( $values );
926 }//end if
927
928 /* If there was an error when inserting or updating the user, lodge the error. */
929 if ( is_wp_error( $user_id ) ) {
930 charitable_get_notices()->add_errors_from_wp_error( $user_id );
931 return false;
932 }
933
934 /**
935 * Do something after a user's account has been updated or created.
936 *
937 * @since 1.0.0
938 *
939 * @param int $user_id The user's ID.
940 * @param array $values Values submitted to save user.
941 */
942 do_action( 'charitable_after_save_user', $user_id, $values );
943
944 return $user_id;
945 }
946
947 /**
948 * Save the user's meta fields.
949 *
950 * @since 1.0.0
951 *
952 * @param array $submitted The submitted values.
953 * @param array $keys The keys of fields that are to be updated.
954 * @return int Number of fields updated.
955 */
956 public function update_user_meta( $submitted, $keys ) {
957 /* Exclude the core keys */
958 $meta_fields = array_diff( $keys, $this->get_core_keys() );
959 $updated = 0;
960
961 foreach ( $meta_fields as $field ) {
962
963 if ( isset( $submitted[ $field ] ) ) {
964 $meta_key = $this->map_key( $field );
965 $meta_value = sanitize_meta( $meta_key, $submitted[ $field ], 'user' );
966
967 update_user_meta( $this->ID, $meta_key, $meta_value );
968
969 $updated++;
970 }
971 }
972
973 return $updated;
974 }
975
976 /**
977 * Log a user is with their username and password.
978 *
979 * @since 1.0.0
980 *
981 * @param string $username The user's username.
982 * @param string $password User password.
983 * @return WP_User|WP_Error|false WP_User on login, WP_Error on failure. False if feature is disabled.
984 */
985 public static function signon( $username, $password ) {
986 if ( ! apply_filters( 'charitable_auto_login_after_registration', true, $username ) ) {
987 return false;
988 }
989
990 if ( is_user_logged_in() ) {
991 return false;
992 }
993
994 $creds = array(
995 'user_login' => $username,
996 'user_password' => $password,
997 'remember' => true,
998 );
999
1000 return wp_signon( $creds, false );
1001 }
1002
1003 /**
1004 * Return a display name for the user.
1005 *
1006 * @since 1.5.2
1007 *
1008 * @param array $values Submitted values.
1009 * @return string|false String if we received a display_name
1010 * or had a first name or last name.
1011 */
1012 public function sanitize_display_name( $values ) {
1013 if ( array_key_exists( 'display_name', $values ) ) {
1014 return $values['display_name'];
1015 }
1016
1017 $first_name = array_key_exists( 'first_name', $values ) ? $values['first_name'] : $this->first_name;
1018 $last_name = array_key_exists( 'last_name', $values ) ? $values['last_name'] : $this->last_name;
1019 $display = trim( sprintf( '%s %s', $first_name, $last_name ) );
1020
1021 return strlen( $display ) ? $display : false;
1022 }
1023
1024 /**
1025 * Return the array of mapped keys, where the key is mapped to a meta_key in the user meta table.
1026 *
1027 * @since 1.0.0
1028 *
1029 * @return array
1030 */
1031 public function get_mapped_keys() {
1032 if ( ! isset( $this->mapped_keys ) ) {
1033 $this->mapped_keys = charitable_get_user_mapped_keys();
1034 }
1035
1036 return $this->mapped_keys;
1037 }
1038
1039 /**
1040 * Given a key, returns the mapped key or itself if it is not mapped.
1041 *
1042 * @since 1.5.0
1043 *
1044 * @param string $key The key to map.
1045 * @return string
1046 */
1047 public function map_key( $key ) {
1048 $mapped_keys = $this->get_mapped_keys();
1049
1050 return array_key_exists( $key, $mapped_keys ) ? $mapped_keys[ $key ] : $key;
1051 }
1052
1053 /**
1054 * Return the array of core keys.
1055 *
1056 * @since 1.0.0
1057 *
1058 * @return array
1059 */
1060 public function get_core_keys() {
1061 if ( ! isset( $this->core_keys ) ) {
1062 $this->core_keys = charitable_get_user_core_keys();
1063 }
1064
1065 return $this->core_keys;
1066 }
1067 }
1068
1069 endif;
1070