PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.6.20
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.6.20
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.20, at includes/users/class-charitable-user.php

1,050 lines 26.2 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 return $verified;
271 }
272
273 /**
274 * Returns the email address of the donor.
275 *
276 * @since 1.0.0
277 *
278 * @return string
279 */
280 public function get_email() {
281 if ( $this->get_donor() ) {
282 $email = $this->get_donor()->email;
283 } else {
284 $email = $this->get( 'user_email' );
285 }
286
287 /**
288 * Filter the user email address.
289 *
290 * @since 1.0.0
291 *
292 * @param string $email The email address.
293 * @param Charitable_User $user This instance of `Charitable_User`.
294 */
295 return apply_filters( 'charitable_user_email', $email, $this );
296 }
297
298 /**
299 * Returns the display name of the user.
300 *
301 * @since 1.0.0
302 *
303 * @return string
304 */
305 public function get_name() {
306 if ( $this->is_donor() ) {
307 $name = rtrim( sprintf( '%s %s', $this->get_donor()->first_name, $this->get_donor()->last_name ) );
308 } else {
309 $name = $this->display_name;
310 }
311
312 if ( ! $name ) {
313 $name = '';
314 }
315
316 return apply_filters( 'charitable_user_name', $name, $this );
317 }
318
319 /**
320 * Returns the first name of the user.
321 *
322 * @since 1.1.0
323 *
324 * @return string
325 */
326 public function get_first_name() {
327 if ( $this->is_donor() && $this->get_donor()->first_name ) {
328 $name = $this->get_donor()->first_name;
329 } else {
330 $name = $this->first_name;
331 }
332
333 return apply_filters( 'charitable_user_first_name', $name, $this );
334 }
335
336 /**
337 * Returns the last name of the user.
338 *
339 * @since 1.1.0
340 *
341 * @return string
342 */
343 public function get_last_name() {
344 if ( $this->is_donor() && $this->get_donor()->last_name ) {
345 $name = $this->get_donor()->last_name;
346 } else {
347 $name = $this->last_name;
348 }
349 return apply_filters( 'charitable_user_last_name', $name, $this );
350 }
351
352 /**
353 * Returns the user's location.
354 *
355 * @since 1.0.0
356 *
357 * @return string
358 */
359 public function get_location() {
360 $city = $this->get( 'donor_city' );
361 $state = $this->get( 'donor_state' );
362 $country = $this->get( 'donor_country' );
363 $location = '';
364
365 if ( strlen( $city ) || strlen( $state ) ) {
366 $region = strlen( $city ) ? $city : $state;
367
368 if ( strlen( $country ) ) {
369 $location = sprintf( '%s, %s', $region, $country );
370 } else {
371 $location = $region;
372 }
373 } elseif ( strlen( $country ) ) {
374 $location = $country;
375 }
376
377 return apply_filters( 'charitable_user_location', $location, $this );
378 }
379
380 /**
381 * Return an array of fields used for the address.
382 *
383 * @since 1.0.0
384 *
385 * @return array
386 */
387 public function get_address_fields() {
388 return apply_filters( 'charitable_user_address_fields', array(
389 'donor_address',
390 'donor_address_2',
391 'donor_city',
392 'donor_state',
393 'donor_postcode',
394 'donor_country',
395 ) );
396 }
397
398 /**
399 * Returns printable address of donor.
400 *
401 * @since 1.0.0
402 *
403 * @param int $donation_id Optional. If set, will return the address provided for the specific donation. Otherwise, returns the current address for the user.
404 * @return string
405 */
406 public function get_address( $donation_id = '' ) {
407 $address_fields = false;
408
409 if ( $donation_id ) {
410
411 $address_fields = get_post_meta( $donation_id, 'donor', true );
412
413 }
414
415 /* If the address fields were not set by the check above, get them from the user meta. */
416 if ( ! is_array( $address_fields ) ) {
417
418 $address_fields = array(
419 'first_name' => $this->get( 'first_name' ),
420 'last_name' => $this->get( 'last_name' ),
421 'company' => $this->get( 'donor_company' ),
422 'address' => $this->get( 'donor_address' ),
423 'address_2' => $this->get( 'donor_address_2' ),
424 'city' => $this->get( 'donor_city' ),
425 'state' => $this->get( 'donor_state' ),
426 'postcode' => $this->get( 'donor_postcode' ),
427 'country' => $this->get( 'donor_country' ),
428 );
429
430 }
431
432 $address_fields = apply_filters( 'charitable_user_address_fields', $address_fields, $this, $donation_id );
433
434 return charitable_get_location_helper()->get_formatted_address( $address_fields );
435 }
436
437 /**
438 * Return all donations made by donor.
439 *
440 * @since 1.0.0
441 *
442 * @param boolean $distinct_donations If true, will only count unique donations.
443 * @return object[]
444 */
445 public function get_donations( $distinct_donations = false ) {
446 return charitable_get_table( 'campaign_donations' )->get_donations_by_donor( $this->get_donor_id(), $distinct_donations );
447 }
448
449 /**
450 * Return the number of donations made by the donor.
451 *
452 * @since 1.0.0
453 *
454 * @param boolean $distinct_donations If true, will only count unique donations.
455 * @return int
456 */
457 public function count_donations( $distinct_donations = false ) {
458 return charitable_get_table( 'campaign_donations' )->count_donations_by_donor( $this->get_donor_id(), $distinct_donations );
459 }
460
461 /**
462 * Return the number of campaigns that the donor has supported.
463 *
464 * @since 1.0.0
465 *
466 * @return int
467 */
468 public function count_campaigns_supported() {
469 return charitable_get_table( 'campaign_donations' )->count_campaigns_supported_by_donor( $this->get_donor_id() );
470 }
471
472 /**
473 * Return the total amount donated by the donor.
474 *
475 * @since 1.0.0
476 *
477 * @param int $campaign_id Optional. If set, returns total donated to this particular campaign.
478 * @return float
479 */
480 public function get_total_donated( $campaign_id = false ) {
481 $amount = wp_cache_get( $this->get_donor_id(), 'charitable_donor_total_donation_amount_' . $campaign_id );
482
483 if ( false === $amount ) {
484
485 $args = apply_filters( 'charitable_user_total_donated_query_args', array(
486 'output' => 'raw',
487 'donor_id' => $this->get_donor_id(),
488 'distinct_donors' => true,
489 'fields' => 'amount',
490 'campaign' => (int) $campaign_id,
491 ), $this );
492
493 $query = new Charitable_Donor_Query( $args );
494
495 $amount = $query->current()->amount;
496
497 wp_cache_set( $this->get_donor_id(), $amount, 'charitable_donor_total_donation_amount_' . $campaign_id );
498 }
499
500 return (float) $amount;
501 }
502
503 /**
504 * Returns the user's avatar as a fully formatted <img> tag.
505 *
506 * By default, this will return the gravatar, but it can
507 * be extended to add support for locally hosted avatars.
508 *
509 * @since 1.0.0
510 *
511 * @param int $size The length and width of the avatar.
512 * @return string
513 */
514 public function get_avatar( $size = 100 ) {
515 /**If you use this filter, return an attachment ID. */
516 $avatar_attachment_id = apply_filters( 'charitable_user_avatar', false, $this );
517
518 /* If we don't have an attachment ID, display the gravatar. */
519 if ( ! $avatar_attachment_id ) {
520 return get_avatar( $this->ID, $size );
521 }
522
523 $img_size = apply_filters( 'charitable_user_avatar_media_size', array( $size, $size ), $size );
524
525 $attachment_src = wp_get_attachment_image_src( $avatar_attachment_id, $img_size );
526
527 /* No image for the given attachment ID? Fall back to the gravatar. */
528 if ( ! $attachment_src ) {
529 return get_avatar( $this->ID, $size );
530 }
531
532 return apply_filters( 'charitable_user_avatar_custom', sprintf( '<img src="%s" alt="%s" class="avatar photo" width="%s" height="%s" />',
533 $attachment_src[0],
534 esc_attr( $this->display_name ),
535 $attachment_src[1],
536 $attachment_src[2]
537 ), $avatar_attachment_id, $size, $this );
538 }
539
540 /**
541 * Return the src of the avatar.
542 *
543 * @since 1.0.0
544 *
545 * @param int $size The length and the width of the avatar.
546 * @return string
547 */
548 public function get_avatar_src( $size = 100 ) {
549 /* If this returns something, we don't need to deal with the gravatar. */
550 $avatar = apply_filters( 'charitable_user_avatar_src', false, $this, $size );
551
552 if ( false === $avatar ) {
553
554 /* The gravatars are returned as fully formatted img tags, so we need to pull out the src. */
555 $gravatar = get_avatar( $this->ID, $size );
556
557 preg_match( "@src='([^']+)'@" , $gravatar, $matches );
558
559 $avatar = array_pop( $matches );
560 }
561
562 return $avatar;
563 }
564
565 /**
566 * Return the campaigns created by the user.
567 *
568 * @since 1.0.0
569 *
570 * @param array $args Optional. Any arguments accepted by WP_Query.
571 * @return WP_Query
572 */
573 public function get_campaigns( $args = array() ) {
574 $defaults = array(
575 'author' => $this->ID,
576 );
577
578 $args = wp_parse_args( $args, $defaults );
579
580 return Charitable_Campaigns::query( $args );
581 }
582
583 /**
584 * Checks whether the user has any current campaigns (i.e. non-expired).
585 *
586 * @since 1.0.0
587 *
588 * @param array $args Query arguments.
589 * @return WP_Query
590 */
591 public function get_current_campaigns( $args = array() ) {
592 $defaults = array(
593 'author' => $this->ID,
594 'meta_query' => array(
595 'relation' => 'OR',
596 array(
597 'key' => '_campaign_end_date',
598 'value' => date( 'Y-m-d H:i:s' ),
599 'compare' => '>=',
600 'type' => 'datetime',
601 ),
602 array(
603 'key' => '_campaign_end_date',
604 'value' => '0',
605 )
606 ),
607 );
608
609 $args = wp_parse_args( $args, $defaults );
610
611 return Charitable_Campaigns::query( $args );
612 }
613
614 /**
615 * Returns all current campaigns by the user.
616 *
617 * @since 1.0.0
618 *
619 * @return WP_Query
620 */
621 public function has_current_campaigns() {
622 return $this->get_current_campaigns()->found_posts;
623 }
624
625 /**
626 * Returns the user's donation and campaign creation activity.
627 *
628 * @see WP_Query
629 * @since 1.0.0
630 *
631 * @param array $args Optional. Any arguments accepted by WP_Query.
632 * @return WP_Query
633 */
634 public function get_activity( $args = array() ) {
635 $defaults = array(
636 'author' => $this->ID,
637 'post_status' => array( 'charitable-completed', 'charitable-preapproved', 'publish' ),
638 'post_type' => array( 'donation', 'campaign' ),
639 'order' => 'DESC',
640 'orderby' => 'date',
641 );
642
643 $args = wp_parse_args( $args, $defaults );
644
645 $args = apply_filters( 'charitable_user_activity_args', $args, $this );
646
647 return new WP_Query( $args );
648 }
649
650 /**
651 * Add a new donor. This may also create a user account for them.
652 *
653 * @since 1.0.0
654 *
655 * @param array $submitted Values submitted by the user.
656 * @return int $donor_id Donor ID.
657 */
658 public function add_donor( $submitted = array() ) {
659 $email = false;
660
661 if ( isset( $submitted['email'] ) ) {
662 $email = $submitted['email'];
663 }
664
665 if ( ! $email && $this->is_logged_in() ) {
666 $email = $this->user_email;
667 }
668
669 /**
670 * Filter whether donors can be added without an email address.
671 *
672 * Prior to Charitable 1.6, this was never permitted. As of Charitable 1.6, donors
673 * without an email address can be added by default, primarily to support manual
674 * donations without an email address. Use this filter to disable that ability.
675 *
676 * NOTE: By default, the public donation form still requires an email address, so this
677 * primarily affects programmatically created donors, or donors created via manual
678 * donations in the admin.
679 *
680 * @see https://github.com/Charitable/Charitable/issues/535
681 *
682 * @since 1.6.0
683 *
684 * @param boolean $permitted Whether donors can be added without an email address.
685 */
686 if ( ! $email && ! charitable_permit_donor_without_email() ) {
687 charitable_get_deprecated()->doing_it_wrong(
688 __METHOD__,
689 __( 'Unable to add donor. Email not set for logged out user.', 'charitable' ),
690 '1.0.0'
691 );
692
693 return 0;
694 }
695
696 /**
697 * Filter the donor values.
698 *
699 * @since 1.0.0
700 *
701 * @param array $donor_values The donor values.
702 * @param Charitable_User $user This instance of `Charitable_User`.
703 * @param array $submitted Submitted values.
704 */
705 $donor_values = apply_filters(
706 'charitable_donor_values',
707 array(
708 'user_id' => $this->ID,
709 'email' => $email,
710 'first_name' => array_key_exists( 'first_name', $submitted ) ? $submitted['first_name'] : $this->first_name,
711 'last_name' => array_key_exists( 'last_name', $submitted ) ? $submitted['last_name'] : $this->last_name,
712 ),
713 $this,
714 $submitted
715 );
716
717 $donor_id = charitable_get_table( 'donors' )->insert( $donor_values );
718
719 /**
720 * If the user is logged in, add the "Donor" role to their account.
721 */
722 if ( $this->is_logged_in() ) {
723 $this->add_role( 'donor' );
724 }
725
726 do_action( 'charitable_after_insert_donor', $donor_id, $this );
727
728 return $donor_id;
729 }
730
731 /**
732 * Insert a new donor with submitted values.
733 *
734 * @since 1.4.0
735 *
736 * @param array $submitted The submitted values.
737 * @param array $keys The keys of fields that are to be updated.
738 * @return int
739 */
740 public static function create_profile( $submitted = array(), $keys = array() ) {
741 $user = new Charitable_User();
742 $user_id = $user->update_profile( $submitted, $keys );
743 return new Charitable_User( $user_id );
744 }
745
746 /**
747 * Update the user's details with submitted values.
748 *
749 * @since 1.0.0
750 *
751 * @param array $submitted The submitted values.
752 * @param array $keys The keys of fields that are to be updated.
753 * @return int
754 */
755 public function update_profile( $submitted = array(), $keys = array() ) {
756 if ( empty( $submitted ) ) {
757 $submitted = $_POST;
758 }
759
760 if ( empty( $keys ) ) {
761 $keys = array_keys( $submitted );
762 }
763
764 $user_id = $this->update_core_user( $submitted );
765
766 /* If there were problems with creating the user, stop here. */
767 if ( ! $user_id ) {
768 return $user_id;
769 }
770
771 /* Create or update the user's donor record. */
772 $this->update_donor_record( $submitted, $keys );
773
774 $this->update_user_meta( $submitted, $keys );
775
776 return $user_id;
777 }
778
779 /**
780 * Create or update a donor record for the current user.
781 *
782 * @since 1.6.2
783 *
784 * @param array $submitted The submitted values.
785 * @param array $keys The keys of fields that are to be updated.
786 * @return int The donor ID, or 0 if none was created or edited.
787 */
788 public function update_donor_record( $submitted, $keys ) {
789 $donor_fields = array_intersect( $keys, charitable_get_donor_keys() );
790
791 if ( array_key_exists( 'user_email', $submitted ) ) {
792 $donor_fields[] = 'email';
793 $submitted['email'] = $submitted['user_email'];
794 }
795
796 if ( empty( $donor_fields ) ) {
797 return 0;
798 }
799
800 $donor_data = array(
801 'user_id' => $this->ID,
802 );
803
804 foreach ( $donor_fields as $field ) {
805 if ( array_key_exists( $field, $submitted ) ) {
806 $value = $submitted[ $field ];
807 } elseif ( 'contact_consent' == $field ) {
808 $value = 0;
809 } else {
810 $value = '';
811 }
812
813 $donor_data[ $field ] = $value;
814 }
815
816 if ( array_key_exists( 'donor_id', $donor_data ) ) {
817 $donor_id = $donor_data['donor_id'];
818 } else {
819 $donor_id = $this->get_donor_id();
820 }
821
822 /* Clear out the cache */
823 wp_cache_delete( $donor_id, 'donors' );
824
825 if ( $donor_id ) {
826 charitable_get_table( 'donors' )->update( $donor_id, $donor_data );
827
828 return $donor_id;
829 }
830
831 return charitable_get_table( 'donors' )->insert( $donor_data );
832 }
833
834 /**
835 * Save core fields of the user (i.e. the wp_users data)
836 *
837 * @uses wp_insert_user
838 *
839 * @since 1.0.0
840 *
841 * @param array $submitted Values submitted by the user.
842 * @return int User ID
843 */
844 public function update_core_user( $submitted ) {
845 $core_fields = array_intersect( array_keys( $submitted ), $this->get_core_keys() );
846
847 if ( empty( $core_fields ) ) {
848 return 0;
849 }
850
851 $values = array();
852
853 /* If we're updating an active user, set the ID */
854 if ( 0 !== $this->ID ) {
855 $values['ID'] = $this->ID;
856 }
857
858 foreach ( $core_fields as $field ) {
859 $values[ $field ] = $submitted[ $field ];
860 }
861
862 /* Set the user's display name based on their name. */
863 $display_name = $this->sanitize_display_name( $values );
864
865 if ( $display_name ) {
866 $values['display_name'] = $display_name;
867 }
868
869 /* Insert the user */
870 if ( 0 == $this->ID ) {
871
872 if ( ! isset( $values['user_pass'] ) || strlen( $values['user_pass'] ) == 0 ) {
873 charitable_get_notices()->add_error( '<strong>ERROR:</strong> Password field is required.' );
874 return false;
875 }
876
877 if ( ! isset( $values['user_login'] ) ) {
878 $values['user_login'] = $values['user_email'];
879 }
880
881 /**
882 * `wp_insert_user` calls `sanitize_user` internally - make the
883 * same call here so `$values['user_login']` matches what is
884 * eventually saved to the database
885 */
886 $values['user_login'] = sanitize_user( $values['user_login'], true );
887
888 $user_id = wp_insert_user( $values );
889
890 if ( is_wp_error( $user_id ) ) {
891 charitable_get_notices()->add_errors_from_wp_error( $user_id );
892 return false;
893 }
894
895 $this->init( self::get_data_by( 'id', $user_id ) );
896
897 $signon = Charitable_User::signon( $values['user_login'], $values['user_pass'] );
898
899 if ( is_wp_error( $signon ) ) {
900 charitable_get_notices()->add_errors_from_wp_error( $signon );
901 return false;
902 }
903
904 do_action( 'charitable_after_insert_user', $user_id, $values );
905
906 } else {
907
908 $values['ID'] = $this->ID;
909
910 $user_id = wp_update_user( $values );
911
912 }//end if
913
914 /* If there was an error when inserting or updating the user, lodge the error. */
915 if ( is_wp_error( $user_id ) ) {
916
917 charitable_get_notices()->add_errors_from_wp_error( $user_id );
918 return false;
919
920 }
921
922 do_action( 'charitable_after_save_user', $user_id, $values );
923
924 return $user_id;
925 }
926
927 /**
928 * Save the user's meta fields.
929 *
930 * @since 1.0.0
931 *
932 * @param array $submitted The submitted values.
933 * @param array $keys The keys of fields that are to be updated.
934 * @return int Number of fields updated.
935 */
936 public function update_user_meta( $submitted, $keys ) {
937 /* Exclude the core keys */
938 $meta_fields = array_diff( $keys, $this->get_core_keys() );
939 $updated = 0;
940
941 foreach ( $meta_fields as $field ) {
942
943 if ( isset( $submitted[ $field ] ) ) {
944 $meta_key = $this->map_key( $field );
945 $meta_value = sanitize_meta( $meta_key, $submitted[ $field ], 'user' );
946
947 update_user_meta( $this->ID, $meta_key, $meta_value );
948
949 $updated++;
950 }
951 }
952
953 return $updated;
954 }
955
956 /**
957 * Log a user is with their username and password.
958 *
959 * @since 1.0.0
960 *
961 * @param string $username The user's username.
962 * @param string $password User password.
963 * @return WP_User|WP_Error|false WP_User on login, WP_Error on failure. False if feature is disabled.
964 */
965 public static function signon( $username, $password ) {
966 if ( ! apply_filters( 'charitable_auto_login_after_registration', true, $username ) ) {
967 return false;
968 }
969
970 if ( is_user_logged_in() ) {
971 return false;
972 }
973
974 $creds = array(
975 'user_login' => $username,
976 'user_password' => $password,
977 'remember' => true,
978 );
979
980 return wp_signon( $creds, false );
981 }
982
983 /**
984 * Return a display name for the user.
985 *
986 * @since 1.5.2
987 *
988 * @param array $values Submitted values.
989 * @return string|false String if we received a display_name
990 * or had a first name or last name.
991 */
992 public function sanitize_display_name( $values ) {
993 if ( array_key_exists( 'display_name', $values ) ) {
994 return $values['display_name'];
995 }
996
997 $first_name = array_key_exists( 'first_name', $values ) ? $values['first_name'] : $this->first_name;
998 $last_name = array_key_exists( 'last_name', $values ) ? $values['last_name'] : $this->last_name;
999 $display = trim( sprintf( '%s %s', $first_name, $last_name ) );
1000
1001 return strlen( $display ) ? $display : false;
1002 }
1003
1004 /**
1005 * Return the array of mapped keys, where the key is mapped to a meta_key in the user meta table.
1006 *
1007 * @since 1.0.0
1008 *
1009 * @return array
1010 */
1011 public function get_mapped_keys() {
1012 if ( ! isset( $this->mapped_keys ) ) {
1013 $this->mapped_keys = charitable_get_user_mapped_keys();
1014 }
1015
1016 return $this->mapped_keys;
1017 }
1018
1019 /**
1020 * Given a key, returns the mapped key or itself if it is not mapped.
1021 *
1022 * @since 1.5.0
1023 *
1024 * @param string $key The key to map.
1025 * @return string
1026 */
1027 public function map_key( $key ) {
1028 $mapped_keys = $this->get_mapped_keys();
1029
1030 return array_key_exists( $key, $mapped_keys ) ? $mapped_keys[ $key ] : $key;
1031 }
1032
1033 /**
1034 * Return the array of core keys.
1035 *
1036 * @since 1.0.0
1037 *
1038 * @return array
1039 */
1040 public function get_core_keys() {
1041 if ( ! isset( $this->core_keys ) ) {
1042 $this->core_keys = charitable_get_user_core_keys();
1043 }
1044
1045 return $this->core_keys;
1046 }
1047 }
1048
1049 endif;
1050