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

848 lines 20.9 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) 2015, Studio 164a
15 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
16 */
17
18 if ( ! defined( 'ABSPATH' ) ) { exit; } // Exit if accessed directly.
19
20 if ( ! class_exists( 'Charitable_User' ) ) :
21
22 /**
23 * Charitable_User
24 *
25 * @since 1.0.0
26 */
27 class Charitable_User extends WP_User {
28
29 /**
30 * The donor ID.
31 *
32 * NOTE: This is not the same as the user ID.
33 *
34 * @var int
35 * @access protected
36 * @since 1.0.0
37 */
38 protected $donor_id;
39
40 /**
41 * A mapping of user keys.
42 *
43 * @var string[]
44 * @access protected
45 * @since 1.4.0
46 */
47 protected $mapped_keys;
48
49 /**
50 * Core keys.
51 *
52 * @var string[]
53 * @access protected
54 * @since 1.4.0
55 */
56 protected $core_keys;
57
58 /**
59 * Create class object.
60 *
61 * @param int|string|stdClass|WP_User $id User's ID, a WP_User object, or a user object from the DB.
62 * @param string $name Optional. User's username
63 * @param int $blog_id Optional Blog ID, defaults to current blog.
64 * @return void
65 * @access public
66 * @since 1.0.0
67 */
68 public function __construct( $id = 0, $name = '', $blog_id = '' ) {
69 parent::__construct( $id, $name, $blog_id );
70 }
71
72 /**
73 * Create object using a donor ID.
74 *
75 * @param int $donor_id
76 * @return Charitable_user
77 * @access public
78 * @static
79 * @since 1.0.0
80 */
81 public static function init_with_donor( $donor_id ) {
82 $user_id = charitable_get_table( 'donors' )->get_user_id( $donor_id );
83 $user = charitable_get_user( $user_id );
84 $user->set_donor_id( $donor_id );
85 return $user;
86 }
87
88 /**
89 * Magic getter method. Looks for the specified key in the mapped keys before using WP_User's __get method.
90 *
91 * @return mixed
92 * @access public
93 * @since 1.0.0
94 */
95 public function __get( $key ) {
96 $mapped_keys = $this->get_mapped_keys();
97
98 if ( array_key_exists( $key, $mapped_keys ) ) {
99 $key = $mapped_keys[ $key ];
100 }
101
102 return parent::__get( $key );
103 }
104
105 /**
106 * Display the donor name when printing the object.
107 *
108 * @return string
109 * @access public
110 * @since 1.0.0
111 */
112 public function __toString() {
113 return $this->get_name();
114 }
115
116 /**
117 * Returns whether the user is logged in.
118 *
119 * @return boolean
120 * @access public
121 * @since 1.0.0
122 */
123 public function is_logged_in() {
124 return 0 !== $this->ID;
125 }
126
127 /**
128 * Set the donor ID of this user.
129 *
130 * @param int $donor_id
131 * @return void
132 * @access public
133 * @since 1.0.0
134 */
135 public function set_donor_id( $donor_id ) {
136 $this->donor_id = $donor_id;
137 }
138
139 /**
140 * Return the donor ID of this user.
141 *
142 * @return int|false $donor_id
143 * @access public
144 * @since 1.0.0
145 */
146 public function get_donor_id() {
147 if ( isset( $this->donor_id ) || ! is_null( $this->get_donor() ) ) {
148 return $this->donor_id;
149 }
150
151 return false;
152 }
153
154 /**
155 * Return the donor record.
156 *
157 * @return Object|null Object if a donor record could be matched. null if user is logged out or no donor record found.
158 * @access public
159 * @since 1.0.0
160 */
161 public function get_donor() {
162 if ( ! $this->is_logged_in() && ! isset( $this->donor_id ) ) {
163 return null;
164 }
165
166 if ( isset( $this->donor_id ) ) {
167
168 $donor = wp_cache_get( $this->donor_id, 'donors' );
169
170 if ( is_object( $donor ) ) {
171 return $donor;
172 }
173
174 $donor = charitable_get_table( 'donors' )->get( $this->donor_id );
175
176 } else {
177
178 $donor = charitable_get_table( 'donors' )->get_by( 'user_id', $this->ID );
179
180 if ( ! is_object( $donor ) ) {
181 return null;
182 }
183
184 $this->donor_id = $donor->donor_id;
185
186 }
187
188 wp_cache_add( $this->donor_id, $donor, 'donors' );
189
190 return $donor;
191 }
192
193 /**
194 * Returns whether the user has ever made a donation.
195 *
196 * @return boolean
197 * @access public
198 * @since 1.0.0
199 */
200 public function is_donor() {
201 return ! is_null( $this->get_donor() );
202 }
203
204 /**
205 * Returns the email address of the donor.
206 *
207 * @return string
208 * @access public
209 * @since 1.0.0
210 */
211 public function get_email() {
212 if ( $this->get_donor() ) {
213 $email = $this->get_donor()->email;
214 } else {
215 $email = $this->get( 'user_email' );
216 }
217
218 return apply_filters( 'charitable_user_email', $email, $this );
219 }
220
221 /**
222 * Returns the display name of the user.
223 *
224 * @return string
225 * @access public
226 * @since 1.0.0
227 */
228 public function get_name() {
229 if ( $this->is_donor() ) {
230 $name = rtrim( sprintf( '%s %s', $this->get_donor()->first_name, $this->get_donor()->last_name ) );
231 } else {
232 $name = $this->display_name;
233 }
234
235 if ( ! $name ) {
236 $name = '';
237 }
238
239 return apply_filters( 'charitable_user_name', $name, $this );
240 }
241
242 /**
243 * Returns the first name of the user.
244 *
245 * @return string
246 * @access public
247 * @since 1.1.0
248 */
249 public function get_first_name() {
250 if ( $this->is_donor() && $this->get_donor()->first_name ) {
251 $name = $this->get_donor()->first_name;
252 } else {
253 $name = $this->first_name;
254 }
255
256 return apply_filters( 'charitable_user_first_name', $name, $this );
257 }
258
259 /**
260 * Returns the last name of the user.
261 *
262 * @return string
263 * @access public
264 * @since 1.1.0
265 */
266 public function get_last_name() {
267 if ( $this->is_donor() && $this->get_donor()->last_name ) {
268 $name = $this->get_donor()->last_name;
269 } else {
270 $name = $this->last_name;
271 }
272 return apply_filters( 'charitable_user_last_name', $name, $this );
273 }
274
275 /**
276 * Returns the user's location.
277 *
278 * @return string
279 * @access public
280 * @since 1.0.0
281 */
282 public function get_location() {
283 $city = $this->get( 'donor_city' );
284 $state = $this->get( 'donor_state' );
285 $country = $this->get( 'donor_country' );
286 $location = '';
287
288 if ( strlen( $city ) || strlen( $state ) ) {
289 $region = strlen( $city ) ? $city : $state;
290
291 if ( strlen( $country ) ) {
292 $location = sprintf( '%s, %s', $region, $country );
293 } else {
294 $location = $region;
295 }
296 } elseif ( strlen( $country ) ) {
297 $location = $country;
298 }
299
300 return apply_filters( 'charitable_user_location', $location, $this );
301 }
302
303 /**
304 * Return an array of fields used for the address.
305 *
306 * @return array
307 * @access public
308 * @since 1.0.0
309 */
310 public function get_address_fields() {
311 return apply_filters( 'charitable_user_address_fields', array(
312 'donor_address',
313 'donor_address_2',
314 'donor_city',
315 'donor_state',
316 'donor_postcode',
317 'donor_country',
318 ) );
319 }
320
321 /**
322 * Returns printable address of donor.
323 *
324 * @param $donation_id Optional. If set, will return the address provided for the specific donation. Otherwise, returns the current address for the user.
325 * @return string
326 * @access public
327 * @since 1.0.0
328 */
329 public function get_address( $donation_id = '' ) {
330 $address_fields = false;
331
332 if ( $donation_id ) {
333
334 $address_fields = get_post_meta( $donation_id, 'donor', true );
335
336 }
337
338 /* If the address fields were not set by the check above, get them from the user meta. */
339 if ( ! is_array( $address_fields ) ) {
340
341 $address_fields = array(
342 'first_name' => $this->get( 'first_name' ),
343 'last_name' => $this->get( 'last_name' ),
344 'company' => $this->get( 'donor_company' ),
345 'address' => $this->get( 'donor_address' ),
346 'address_2' => $this->get( 'donor_address_2' ),
347 'city' => $this->get( 'donor_city' ),
348 'state' => $this->get( 'donor_state' ),
349 'postcode' => $this->get( 'donor_postcode' ),
350 'country' => $this->get( 'donor_country' ),
351 );
352
353 }
354
355 $address_fields = apply_filters( 'charitable_user_address_fields', $address_fields, $this, $donation_id );
356
357 return charitable_get_location_helper()->get_formatted_address( $address_fields );
358 }
359
360 /**
361 * Return all donations made by donor.
362 *
363 * @param boolean $distinct_donations If true, will only count unique donations.
364 * @return object[]
365 * @access public
366 * @since 1.0.0
367 */
368 public function get_donations( $distinct_donations = false ) {
369 return charitable_get_table( 'campaign_donations' )->get_donations_by_donor( $this->get_donor_id(), $distinct_donations );
370 }
371
372 /**
373 * Return the number of donations made by the donor.
374 *
375 * @param boolean $distinct_donations If true, will only count unique donations.
376 * @return int
377 * @access public
378 * @since 1.0.0
379 */
380 public function count_donations( $distinct_donations = false ) {
381 return charitable_get_table( 'campaign_donations' )->count_donations_by_donor( $this->get_donor_id(), $distinct_donations );
382 }
383
384 /**
385 * Return the number of campaigns that the donor has supported.
386 *
387 * @return int
388 * @access public
389 * @since 1.0.0
390 */
391 public function count_campaigns_supported() {
392 return charitable_get_table( 'campaign_donations' )->count_campaigns_supported_by_donor( $this->get_donor_id() );
393 }
394
395 /**
396 * Return the total amount donated by the donor.
397 *
398 * @param int $campaign_id Optional. If set, returns total donated to this particular campaign.
399 * @return float
400 * @access public
401 * @since 1.0.0
402 */
403 public function get_total_donated( $campaign_id = false ) {
404 $amount = wp_cache_get( $this->get_donor_id(), 'charitable_donor_total_donation_amount_' . $campaign_id );
405
406 if ( false === $amount ) {
407
408 $args = apply_filters( 'charitable_user_total_donated_query_args', array(
409 'output' => 'raw',
410 'donor_id' => $this->get_donor_id(),
411 'distinct_donors' => true,
412 'fields' => 'amount',
413 'campaign' => (int) $campaign_id,
414 ), $this );
415
416 $query = new Charitable_Donor_Query( $args );
417
418 $amount = $query->current()->amount;
419
420 wp_cache_set( $this->get_donor_id(), $amount, 'charitable_donor_total_donation_amount_' . $campaign_id );
421 }
422
423 return (float) $amount;
424 }
425
426 /**
427 * Returns the user's avatar as a fully formatted <img> tag.
428 *
429 * By default, this will return the gravatar, but it can
430 * be extended to add support for locally hosted avatars.
431 *
432 * @param int $size
433 * @return string
434 * @access public
435 * @since 1.0.0
436 */
437 public function get_avatar( $size = 100 ) {
438 /** If you use this filter, return an attachment ID. */
439 $avatar_attachment_id = apply_filters( 'charitable_user_avatar', false, $this );
440
441 /* If we don't have an attachment ID, display the gravatar. */
442 if ( ! $avatar_attachment_id ) {
443 return get_avatar( $this->ID, $size );
444 }
445
446 $img_size = apply_filters( 'charitable_user_avatar_media_size', array( $size, $size ), $size );
447
448 $attachment_src = wp_get_attachment_image_src( $avatar_attachment_id, $img_size );
449
450 /* No image for the given attachment ID? Fall back to the gravatar. */
451 if ( ! $attachment_src ) {
452 return get_avatar( $this->ID, $size );
453 }
454
455 return apply_filters( 'charitable_user_avatar_custom', sprintf( '<img src="%s" alt="%s" class="avatar photo" width="%s" height="%s" />',
456 $attachment_src[0] ,
457 esc_attr( $this->display_name ),
458 $attachment_src[1],
459 $attachment_src[2]
460 ), $avatar_attachment_id, $size, $this );
461 }
462
463 /**
464 * Return the src of the avatar.
465 *
466 * @param int $size
467 * @return string
468 * @access public
469 * @since 1.0.0
470 */
471 public function get_avatar_src( $size = 100 ) {
472 /* If this returns something, we don't need to deal with the gravatar. */
473 $avatar = apply_filters( 'charitable_user_avatar_src', false, $this, $size );
474
475 if ( false === $avatar ) {
476
477 /* The gravatars are returned as fully formatted img tags, so we need to pull out the src. */
478 $gravatar = get_avatar( $this->ID, $size );
479
480 preg_match( "@src='([^']+)'@" , $gravatar, $matches );
481
482 $avatar = array_pop( $matches );
483 }
484
485 return $avatar;
486 }
487
488 /**
489 * Return the campaigns created by the user.
490 *
491 * @param array $args Optional. Any arguments accepted by WP_Query.
492 * @return WP_Query
493 * @access public
494 * @since 1.0.0
495 */
496 public function get_campaigns( $args = array() ) {
497 $defaults = array(
498 'author' => $this->ID,
499 );
500
501 $args = wp_parse_args( $args, $defaults );
502
503 return Charitable_Campaigns::query( $args );
504 }
505
506 /**
507 * Checks whether the user has any current campaigns (i.e. non-expired).
508 *
509 * @return WP_Query
510 * @access public
511 * @since 1.0.0
512 */
513 public function get_current_campaigns( $args = array() ) {
514 $defaults = array(
515 'author' => $this->ID,
516 'meta_query' => array(
517 'relation' => 'OR',
518 array(
519 'key' => '_campaign_end_date',
520 'value' => date( 'Y-m-d H:i:s' ),
521 'compare' => '>=',
522 'type' => 'datetime',
523 ),
524 array(
525 'key' => '_campaign_end_date',
526 'value' => '0',
527 )
528 ),
529 );
530
531 $args = wp_parse_args( $args, $defaults );
532
533 return Charitable_Campaigns::query( $args );
534 }
535
536 /**
537 * Returns all current campaigns by the user.
538 *
539 * @return WP_Query
540 * @access public
541 * @since 1.0.0
542 */
543 public function has_current_campaigns() {
544 return $this->get_current_campaigns()->found_posts;
545 }
546
547 /**
548 * Returns the user's donation and campaign creation activity.
549 *
550 * @see WP_Query
551 * @param array $args Optional. Any arguments accepted by WP_Query.
552 * @return WP_Query
553 * @access public
554 * @since 1.0.0
555 */
556 public function get_activity( $args = array() ) {
557 $defaults = array(
558 'author' => $this->ID,
559 'post_status' => array( 'charitable-completed', 'charitable-preapproved', 'publish' ),
560 'post_type' => array( 'donation', 'campaign' ),
561 'order' => 'DESC',
562 'orderby' => 'date',
563 );
564
565 $args = wp_parse_args( $args, $defaults );
566
567 $args = apply_filters( 'charitable_user_activity_args', $args, $this );
568
569 return new WP_Query( $args );
570 }
571
572 /**
573 * Add a new donor. This may also create a user account for them.
574 *
575 * @param array $submitted
576 * @return int $donor_id
577 * @access public
578 * @since 1.0.0
579 */
580 public function add_donor( $submitted = array() ) {
581 $email = false;
582
583 if ( isset( $submitted['email'] ) ) {
584 $email = $submitted['email'];
585 }
586
587 if ( ! $email && $this->is_logged_in() ) {
588 $email = $this->user_email;
589 }
590
591 /**
592 * Still no email? We're going to have to call an end
593 * to this party right now then.
594 */
595 if ( ! $email ) {
596
597 charitable_get_deprecated()->doing_it_wrong(
598 __METHOD__,
599 __( 'Unable to add donor. Email not set for logged out user.', 'charitable' ),
600 '1.0.0'
601 );
602
603 return 0;
604
605 }
606
607 $donor_values = apply_filters( 'charitable_donor_values', array(
608 'user_id' => $this->ID,
609 'email' => $email,
610 'first_name' => isset( $submitted['first_name'] ) ? $submitted['first_name'] : $this->first_name,
611 'last_name' => isset( $submitted['last_name'] ) ? $submitted['last_name'] : $this->last_name,
612 ), $this, $submitted );
613
614 $donor_id = charitable_get_table( 'donors' )->insert( $donor_values );
615
616 do_action( 'charitable_after_insert_donor', $donor_id, $this );
617
618 return $donor_id;
619 }
620
621 /**
622 * Insert a new donor with submitted values.
623 *
624 * @param array $submitted The submitted values.
625 * @param array $keys The keys of fields that are to be updated.
626 * @return int
627 * @access public
628 * @since 1.4.0
629 */
630 public static function create_profile( $submitted = array(), $keys = array() ) {
631 $user = new Charitable_User();
632 $user_id = $user->update_profile( $submitted, $keys );
633 return new Charitable_User( $user_id );
634 }
635
636 /**
637 * Update the user's details with submitted values.
638 *
639 * @param array $submitted The submitted values.
640 * @param array $keys The keys of fields that are to be updated.
641 * @return int
642 * @access public
643 * @since 1.0.0
644 */
645 public function update_profile( $submitted = array(), $keys = array() ) {
646 if ( empty( $submitted ) ) {
647 $submitted = $_POST;
648 }
649
650 if ( empty( $keys ) ) {
651 $keys = array_keys( $submitted );
652 }
653
654 $user_id = $this->update_core_user( $submitted );
655
656 /* If there were problems with creating the user, stop here. */
657 if ( ! $user_id ) {
658 return $user_id;
659 }
660
661 $this->update_user_meta( $submitted, $keys );
662
663 return $user_id;
664 }
665
666 /**
667 * Save core fields of the user (i.e. the wp_users data)
668 *
669 * @uses wp_insert_user
670 * @param array $submitted
671 * @return int User ID
672 * @access public
673 * @since 1.0.0
674 */
675 public function update_core_user( $submitted ) {
676 $core_fields = array_intersect( array_keys( $submitted ), $this->get_core_keys() );
677
678 if ( empty( $core_fields ) ) {
679 return 0;
680 }
681
682 $values = array();
683
684 /* If we're updating an active user, set the ID */
685 if ( 0 !== $this->ID ) {
686
687 $values['ID'] = $this->ID;
688
689 }
690
691 foreach ( $core_fields as $field ) {
692
693 $values[ $field ] = $submitted[ $field ];
694
695 }
696
697 /* Insert the user */
698 if ( 0 == $this->ID ) {
699
700 if ( ! isset( $values['user_pass'] ) || strlen( $values['user_pass'] ) == 0 ) {
701 charitable_get_notices()->add_error( '<strong>ERROR:</strong> Password field is required.' );
702 return false;
703 }
704
705 if ( ! isset( $values['user_login'] ) ) {
706 $values['user_login'] = $values['user_email'];
707 }
708
709 /**
710 * `wp_insert_user` calls `sanitize_user` internally - make the
711 * same call here so `$values[ 'user_login' ]` matches what is
712 * eventually saved to the database
713 */
714 $values['user_login'] = sanitize_user( $values['user_login'], true );
715
716 $user_id = wp_insert_user( $values );
717
718 if ( is_wp_error( $user_id ) ) {
719 charitable_get_notices()->add_errors_from_wp_error( $user_id );
720 return false;
721 }
722
723 $this->init( self::get_data_by( 'id', $user_id ) );
724
725 $signon = Charitable_User::signon( $values['user_login'], $values['user_pass'] );
726
727 if ( is_wp_error( $signon ) ) {
728 charitable_get_notices()->add_errors_from_wp_error( $signon );
729 return false;
730 }
731
732 do_action( 'charitable_after_insert_user', $user_id, $values );
733
734 } else {
735
736 $values['ID'] = $this->ID;
737
738 $user_id = wp_update_user( $values );
739
740 }
741
742 /* If there was an error when inserting or updating the user, lodge the error. */
743 if ( is_wp_error( $user_id ) ) {
744
745 charitable_get_notices()->add_errors_from_wp_error( $user_id );
746 return false;
747
748 }
749
750 do_action( 'charitable_after_save_user', $user_id, $values );
751
752 return $user_id;
753 }
754
755 /**
756 * Save the user's meta fields.
757 *
758 * @param array $submitted The submitted values.
759 * @param array $keys The keys of fields that are to be updated.
760 * @return int Number of fields updated.
761 * @access public
762 * @since 1.0.0
763 */
764 public function update_user_meta( $submitted, $keys ) {
765 /* Exclude the core keys */
766 $mapped_keys = $this->get_mapped_keys();
767 $meta_fields = array_diff( $keys, $this->get_core_keys() );
768 $updated = 0;
769
770 foreach ( $meta_fields as $field ) {
771
772 if ( isset( $submitted[ $field ] ) ) {
773
774 $meta_key = array_key_exists( $field, $mapped_keys ) ? $mapped_keys[ $field ] : $field;
775
776 $meta_value = sanitize_meta( $meta_key, $submitted[ $field ], 'user' );
777
778 update_user_meta( $this->ID, $meta_key, $meta_value );
779
780 $updated++;
781
782 }
783 }
784
785 return $updated;
786 }
787
788 /**
789 * Log a user is with their username and password.
790 *
791 * @param string $username
792 * @param string $password
793 * @return WP_User|WP_Error|false WP_User on login, WP_Error on failure. False if feature is disabled.
794 * @access public
795 * @static
796 * @since 1.0.0
797 */
798 public static function signon( $username, $password ) {
799 if ( ! apply_filters( 'charitable_auto_login_after_registration', true, $username ) ) {
800 return false;
801 }
802
803 if ( is_user_logged_in() ) {
804 return false;
805 }
806
807 $creds = array(
808 'user_login' => $username,
809 'user_password' => $password,
810 'remember' => true,
811 );
812
813 return wp_signon( $creds, false );
814 }
815
816 /**
817 * Return the array of mapped keys, where the key is mapped to a meta_key in the user meta table.
818 *
819 * @return array
820 * @access public
821 * @since 1.0.0
822 */
823 public function get_mapped_keys() {
824 if ( ! isset( $this->mapped_keys ) ) {
825 $this->mapped_keys = charitable_get_user_mapped_keys();
826 }
827
828 return $this->mapped_keys;
829 }
830
831 /**
832 * Return the array of core keys.
833 *
834 * @return array
835 * @access public
836 * @since 1.0.0
837 */
838 public function get_core_keys() {
839 if ( ! isset( $this->core_keys ) ) {
840 $this->core_keys = charitable_get_user_core_keys();
841 }
842
843 return $this->core_keys;
844 }
845 }
846
847 endif; // End class_exists check
848