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

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