PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13
1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 1.7.0.9 All 211 releases
← All changes | includes/users/class-charitable-user.php +199 -88 1.6.8 → 1.8.13 View file →
@@ -7,13 +7,14 @@
7 7 * people who create campaigns (via Charitable Ambassadors) get
8 8 * the "campaign_creator" role; people who create fundraisers for campaigns
9 9 * get the "fundraiser" role.
10 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
11 + * @package Charitable/Classes/Charitable_User
12 + * @author David Bisset
13 + * @copyright Copyright (c) 2023, WP Charitable LLC
14 + * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
15 + * @since 1.0.0
16 + * @version 1.8.9.1
16 17 */
17 18
18 19 // Exit if accessed directly.
19 20 if ( ! defined( 'ABSPATH' ) ) {
@@ -54,10 +55,11 @@
54 55 * The donor ID.
55 56 *
56 57 * NOTE: This is not the same as the user ID.
57 58 *
58 - * @var int
59 - * @since 1.0.0
59 + * @since 1.0.0
60 + *
61 + * @var int
60 62 */
61 63 protected $donor_id;
62 64
63 65 /**
@@ -62,10 +64,11 @@
62 64
63 65 /**
64 66 * A mapping of user keys.
65 67 *
66 - * @var string[]
67 - * @since 1.4.0
68 + * @since 1.4.0
69 + *
70 + * @var string[]
68 71 */
69 72 protected $mapped_keys;
70 73
71 74 /**
@@ -70,10 +73,11 @@
70 73
71 74 /**
72 75 * Core keys.
73 76 *
74 - * @var string[]
75 77 * @since 1.4.0
78 + *
79 + * @var string[]
76 80 */
77 81 protected $core_keys;
78 82
79 83 /**
@@ -85,9 +89,9 @@
85 89 * @param string $name Optional. User's username.
86 90 * @param int $blog_id Optional Blog ID, defaults to current blog.
87 91 * @return void
88 92 */
89 - public function __construct( $id = 0, $name = '', $blog_id = '' ) {
93 + public function __construct( $id = 0, $name = '', $blog_id = '' ) { // phpcs:ignore
90 94 parent::__construct( $id, $name, $blog_id );
91 95 }
92 96
93 97 /**
@@ -255,8 +259,14 @@
255 259 if ( ! $verified ) {
256 260 return $verified;
257 261 }
258 262
263 + /* Delete the time that the verification email was sent. */
264 + delete_user_meta( $this->ID, '_charitable_email_verification_email_send_time' );
265 +
266 + /* Check for a notice about having sent a verification email and remove it. */
267 + charitable_get_notices()->clear_notice( "/We have sent you an email to confirm your email address. Haven\'t received the email\?/" );
268 +
259 269 /* Check for an existing donor account. */
260 270 $donor_id = $this->get_donor_id();
261 271
262 272 if ( $donor_id ) {
@@ -263,8 +273,17 @@
263 273 $donor = new Charitable_Donor( $donor_id );
264 274 $donor->set_user_id( $this->ID );
265 275 }
266 276
277 + /**
278 + * Do something when a user is verified.
279 + *
280 + * @since 1.6.23
281 + *
282 + * @param Charitable_User $user The user object.
283 + */
284 + do_action( 'charitable_user_verified', $this );
285 +
267 286 return $verified;
268 287 }
269 288
270 289 /**
@@ -374,26 +393,8 @@
374 393 return apply_filters( 'charitable_user_location', $location, $this );
375 394 }
376 395
377 396 /**
378 - * Return an array of fields used for the address.
379 - *
380 - * @since 1.0.0
381 - *
382 - * @return array
383 - */
384 - public function get_address_fields() {
385 - return apply_filters( 'charitable_user_address_fields', array(
386 - 'donor_address',
387 - 'donor_address_2',
388 - 'donor_city',
389 - 'donor_state',
390 - 'donor_postcode',
391 - 'donor_country',
392 - ) );
393 - }
394 -
395 - /**
396 397 * Returns printable address of donor.
397 398 *
398 399 * @since 1.0.0
399 400 *
@@ -400,20 +401,18 @@
400 401 * @param int $donation_id Optional. If set, will return the address provided for the specific donation. Otherwise, returns the current address for the user.
401 402 * @return string
402 403 */
403 404 public function get_address( $donation_id = '' ) {
404 - $address_fields = false;
405 + $address_details = false;
405 406
406 407 if ( $donation_id ) {
407 -
408 - $address_fields = get_post_meta( $donation_id, 'donor', true );
409 -
408 + $address_details = get_post_meta( $donation_id, 'donor', true );
410 409 }
411 410
412 411 /* If the address fields were not set by the check above, get them from the user meta. */
413 - if ( ! is_array( $address_fields ) ) {
412 + if ( ! is_array( $address_details ) ) {
414 413
415 - $address_fields = array(
414 + $address_details = array(
416 415 'first_name' => $this->get( 'first_name' ),
417 416 'last_name' => $this->get( 'last_name' ),
418 417 'company' => $this->get( 'donor_company' ),
419 418 'address' => $this->get( 'donor_address' ),
@@ -425,11 +424,23 @@
425 424 );
426 425
427 426 }
428 427
429 - $address_fields = apply_filters( 'charitable_user_address_fields', $address_fields, $this, $donation_id );
428 + /**
429 + * Filter the address details for the current user.
430 + *
431 + * Please note that prior to 1.6.44, the hook used here was `charitable_user_address_fields`,
432 + * which is used elsewhere in a different context and thus resulted in unexpected results.
433 + *
434 + * @since 1.6.44
435 + *
436 + * @param array $address_details The address details.
437 + * @param Charitable_User $user The user object.
438 + * @param int $donation_id The donation ID.
439 + */
440 + $address_details = apply_filters( 'charitable_user_address_details', $address_details, $this, $donation_id );
430 441
431 - return charitable_get_location_helper()->get_formatted_address( $address_fields );
442 + return charitable_get_location_helper()->get_formatted_address( $address_details );
432 443 }
433 444
434 445 /**
435 446 * Return all donations made by donor.
@@ -468,9 +479,10 @@
468 479
469 480 /**
470 481 * Return the total amount donated by the donor.
471 482 *
472 - * @since 1.0.0
483 + * @since 1.0.0
484 + * @version 1.8.1
473 485 *
474 486 * @param int $campaign_id Optional. If set, returns total donated to this particular campaign.
475 487 * @return float
476 488 */
@@ -478,21 +490,29 @@
478 490 $amount = wp_cache_get( $this->get_donor_id(), 'charitable_donor_total_donation_amount_' . $campaign_id );
479 491
480 492 if ( false === $amount ) {
481 493
482 - $args = apply_filters( 'charitable_user_total_donated_query_args', array(
483 - 'output' => 'raw',
484 - 'donor_id' => $this->get_donor_id(),
485 - 'distinct_donors' => true,
486 - 'fields' => 'amount',
487 - 'campaign' => (int) $campaign_id,
488 - ), $this );
494 + $args = apply_filters(
495 + 'charitable_user_total_donated_query_args',
496 + array(
497 + 'output' => 'raw',
498 + 'donor_id' => $this->get_donor_id(),
499 + 'distinct_donors' => true,
500 + 'fields' => 'amount',
501 + 'campaign' => (int) $campaign_id,
502 + ),
503 + $this
504 + );
489 505
490 506 $query = new Charitable_Donor_Query( $args );
491 507
492 - $amount = $query->current()->amount;
508 + if ( is_object( $query->current() ) ) { // test to see if it's an object.
493 509
494 - wp_cache_set( $this->get_donor_id(), $amount, 'charitable_donor_total_donation_amount_' . $campaign_id );
510 + $amount = $query->current()->amount;
511 +
512 + wp_cache_set( $this->get_donor_id(), $amount, 'charitable_donor_total_donation_amount_' . $campaign_id );
513 +
514 + }
495 515 }
496 516
497 517 return (float) $amount;
498 518 }
@@ -505,14 +525,18 @@
505 525 *
506 526 * @since 1.0.0
507 527 *
508 528 * @param int $size The length and width of the avatar.
529 + * @param int $donor_id Optional. The donor ID.
509 530 * @return string
510 531 */
511 - public function get_avatar( $size = 100 ) {
532 + public function get_avatar( $size = 100, $donor_id = false ) {
512 533 /**If you use this filter, return an attachment ID. */
513 - $avatar_attachment_id = apply_filters( 'charitable_user_avatar', false, $this );
514 534
535 + $avatar_attachment_id = get_user_meta( $this->ID, 'avatar', true );
536 +
537 + $avatar_attachment_id = apply_filters( 'charitable_user_avatar', $avatar_attachment_id, $this );
538 +
515 539 /* If we don't have an attachment ID, display the gravatar. */
516 540 if ( ! $avatar_attachment_id ) {
517 541 return get_avatar( $this->ID, $size );
518 542 }
@@ -525,14 +549,21 @@
525 549 if ( ! $attachment_src ) {
526 550 return get_avatar( $this->ID, $size );
527 551 }
528 552
529 - return apply_filters( 'charitable_user_avatar_custom', sprintf( '<img src="%s" alt="%s" class="avatar photo" width="%s" height="%s" />',
530 - $attachment_src[0],
531 - esc_attr( $this->display_name ),
532 - $attachment_src[1],
533 - $attachment_src[2]
534 - ), $avatar_attachment_id, $size, $this );
553 + return apply_filters(
554 + 'charitable_user_avatar_custom',
555 + sprintf(
556 + '<img src="%s" alt="%s" class="avatar photo" width="%s" height="%s" />',
557 + $attachment_src[0],
558 + esc_attr( $this->display_name ),
559 + $attachment_src[1],
560 + $attachment_src[2]
561 + ),
562 + $avatar_attachment_id,
563 + $size,
564 + $this
565 + );
535 566 }
536 567
537 568 /**
538 569 * Return the src of the avatar.
@@ -550,9 +581,9 @@
550 581
551 582 /* The gravatars are returned as fully formatted img tags, so we need to pull out the src. */
552 583 $gravatar = get_avatar( $this->ID, $size );
553 584
554 - preg_match( "@src='([^']+)'@" , $gravatar, $matches );
585 + preg_match( "@src='([^']+)'@", $gravatar, $matches );
555 586
556 587 $avatar = array_pop( $matches );
557 588 }
558 589
@@ -568,9 +599,9 @@
568 599 * @return WP_Query
569 600 */
570 601 public function get_campaigns( $args = array() ) {
571 602 $defaults = array(
572 - 'author' => $this->ID,
603 + 'author' => $this->ID,
573 604 );
574 605
575 606 $args = wp_parse_args( $args, $defaults );
576 607
@@ -580,27 +611,28 @@
580 611 /**
581 612 * Checks whether the user has any current campaigns (i.e. non-expired).
582 613 *
583 614 * @since 1.0.0
615 + * @version 1.8.9.1
584 616 *
585 - * @param array $args Query arguments.
617 + * @param array $args Query arguments.
586 618 * @return WP_Query
587 619 */
588 620 public function get_current_campaigns( $args = array() ) {
589 621 $defaults = array(
590 - 'author' => $this->ID,
591 - 'meta_query' => array(
592 - 'relation' => 'OR',
622 + 'author' => $this->ID,
623 + 'meta_query' => array(
624 + 'relation' => 'OR',
593 625 array(
594 - 'key' => '_campaign_end_date',
595 - 'value' => date( 'Y-m-d H:i:s' ),
596 - 'compare' => '>=',
597 - 'type' => 'datetime',
626 + 'key' => '_campaign_end_date',
627 + 'value' => date( 'Y-m-d H:i:s' ), // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
628 + 'compare' => '>=',
629 + 'type' => 'datetime',
598 630 ),
599 631 array(
600 - 'key' => '_campaign_end_date',
601 - 'value' => '0',
602 - )
632 + 'key' => '_campaign_end_date',
633 + 'value' => '0',
634 + ),
603 635 ),
604 636 );
605 637
606 638 $args = wp_parse_args( $args, $defaults );
@@ -698,14 +730,19 @@
698 730 * @param array $donor_values The donor values.
699 731 * @param Charitable_User $user This instance of `Charitable_User`.
700 732 * @param array $submitted Submitted values.
701 733 */
702 - $donor_values = apply_filters( 'charitable_donor_values', array(
703 - 'user_id' => $this->ID,
704 - 'email' => $email,
705 - 'first_name' => array_key_exists( 'first_name', $submitted ) ? $submitted['first_name'] : $this->first_name,
706 - 'last_name' => array_key_exists( 'last_name', $submitted ) ? $submitted['last_name'] : $this->last_name,
707 - ), $this, $submitted );
734 + $donor_values = apply_filters(
735 + 'charitable_donor_values',
736 + array(
737 + 'user_id' => $this->ID,
738 + 'email' => $email,
739 + 'first_name' => array_key_exists( 'first_name', $submitted ) ? $submitted['first_name'] : $this->first_name,
740 + 'last_name' => array_key_exists( 'last_name', $submitted ) ? $submitted['last_name'] : $this->last_name,
741 + ),
742 + $this,
743 + $submitted
744 + );
708 745
709 746 $donor_id = charitable_get_table( 'donors' )->insert( $donor_values );
710 747
711 748 /**
@@ -723,8 +760,9 @@
723 760 /**
724 761 * Insert a new donor with submitted values.
725 762 *
726 763 * @since 1.4.0
764 + * @version 1.8.1.15
727 765 *
728 766 * @param array $submitted The submitted values.
729 767 * @param array $keys The keys of fields that are to be updated.
730 768 * @return int
@@ -729,9 +767,16 @@
729 767 * @param array $keys The keys of fields that are to be updated.
730 768 * @return int
731 769 */
732 770 public static function create_profile( $submitted = array(), $keys = array() ) {
733 - $user = new Charitable_User();
771 + $user = new Charitable_User();
772 +
773 + // Ensure that an ID isn't being submitted.
774 + // Adding here but this function might be deprecated or not in use (outside of tests).
775 + if ( array_key_exists( 'ID', $submitted ) ) {
776 + unset( $submitted['ID'] );
777 + }
778 +
734 779 $user_id = $user->update_profile( $submitted, $keys );
735 780 return new Charitable_User( $user_id );
736 781 }
737 782
@@ -745,9 +790,9 @@
745 790 * @return int
746 791 */
747 792 public function update_profile( $submitted = array(), $keys = array() ) {
748 793 if ( empty( $submitted ) ) {
749 - $submitted = $_POST;
794 + $submitted = $_POST; // phpcs:ignore
750 795 }
751 796
752 797 if ( empty( $keys ) ) {
753 798 $keys = array_keys( $submitted );
@@ -795,9 +840,9 @@
795 840
796 841 foreach ( $donor_fields as $field ) {
797 842 if ( array_key_exists( $field, $submitted ) ) {
798 843 $value = $submitted[ $field ];
799 - } elseif ( 'contact_consent' == $field ) {
844 + } elseif ( 'contact_consent' === $field ) {
800 845 $value = 0;
801 846 } else {
802 847 $value = '';
803 848 }
@@ -810,10 +855,21 @@
810 855 } else {
811 856 $donor_id = $this->get_donor_id();
812 857 }
813 858
814 - /* Clear out the cache */
815 - wp_cache_delete( $donor_id, 'donors' );
859 + /*
860 + * Clear out the cache.
861 + *
862 + * Only when there is actually an ID. get_donor_id() returns false for a donor who does not
863 + * exist yet, which is the normal path into the insert() below - and the `if ( $donor_id )`
864 + * immediately after this already accounts for that. Passing false as a cache key trips
865 + * WP 6.1+'s "Cache key must be an integer or a non-empty string" _doing_it_wrong notice on
866 + * every new-donor save. Deleting the key false was a no-op regardless, so guarding it
867 + * changes no behaviour.
868 + */
869 + if ( $donor_id ) {
870 + wp_cache_delete( $donor_id, 'donors' );
871 + }
816 872
817 873 if ( $donor_id ) {
818 874 charitable_get_table( 'donors' )->update( $donor_id, $donor_data );
819 875
@@ -847,8 +903,10 @@
847 903 $values['ID'] = $this->ID;
848 904 }
849 905
850 906 foreach ( $core_fields as $field ) {
907 + if ( $field === 'role' ) {
908 + continue; }
851 909 $values[ $field ] = $submitted[ $field ];
852 910 }
853 911
854 912 /* Set the user's display name based on their name. */
@@ -858,9 +916,9 @@
858 916 $values['display_name'] = $display_name;
859 917 }
860 918
861 919 /* Insert the user */
862 - if ( 0 == $this->ID ) {
920 + if ( 0 === $this->ID ) {
863 921
864 922 if ( ! isset( $values['user_pass'] ) || strlen( $values['user_pass'] ) == 0 ) {
865 923 charitable_get_notices()->add_error( '<strong>ERROR:</strong> Password field is required.' );
866 924 return false;
@@ -885,9 +943,9 @@
885 943 }
886 944
887 945 $this->init( self::get_data_by( 'id', $user_id ) );
888 946
889 - $signon = Charitable_User::signon( $values['user_login'], $values['user_pass'] );
947 + $signon = self::signon( $values['user_login'], $values['user_pass'] );
890 948
891 949 if ( is_wp_error( $signon ) ) {
892 950 charitable_get_notices()->add_errors_from_wp_error( $signon );
893 951 return false;
@@ -892,26 +950,37 @@
892 950 charitable_get_notices()->add_errors_from_wp_error( $signon );
893 951 return false;
894 952 }
895 953
954 + /**
955 + * Do something after a user has been registered.
956 + *
957 + * @since 1.0.0
958 + *
959 + * @param int $user_id The new user's ID.
960 + * @param array $values Values submitted to register user.
961 + */
896 962 do_action( 'charitable_after_insert_user', $user_id, $values );
897 963
898 964 } else {
899 -
900 965 $values['ID'] = $this->ID;
901 -
902 - $user_id = wp_update_user( $values );
903 -
966 + $user_id = wp_update_user( $values );
904 967 }//end if
905 968
906 969 /* If there was an error when inserting or updating the user, lodge the error. */
907 970 if ( is_wp_error( $user_id ) ) {
908 -
909 971 charitable_get_notices()->add_errors_from_wp_error( $user_id );
910 972 return false;
911 -
912 973 }
913 974
975 + /**
976 + * Do something after a user's account has been updated or created.
977 + *
978 + * @since 1.0.0
979 + *
980 + * @param int $user_id The user's ID.
981 + * @param array $values Values submitted to save user.
982 + */
914 983 do_action( 'charitable_after_save_user', $user_id, $values );
915 984
916 985 return $user_id;
917 986 }
@@ -937,9 +1006,9 @@
937 1006 $meta_value = sanitize_meta( $meta_key, $submitted[ $field ], 'user' );
938 1007
939 1008 update_user_meta( $this->ID, $meta_key, $meta_value );
940 1009
941 - $updated++;
1010 + ++$updated;
942 1011 }
943 1012 }
944 1013
945 1014 return $updated;
@@ -1034,8 +1103,50 @@
1034 1103 $this->core_keys = charitable_get_user_core_keys();
1035 1104 }
1036 1105
1037 1106 return $this->core_keys;
1107 + }
1108 +
1109 + /**
1110 + * Deprecated function.
1111 + *
1112 + * Return an array of fields used for the address.
1113 + *
1114 + * @deprecated 2.2.0
1115 + *
1116 + * @since 1.0.0
1117 + * @since 1.6.44 Deprecated.
1118 + *
1119 + * @return array
1120 + */
1121 + public function get_address_fields() {
1122 + charitable_get_deprecated()->deprecated_function(
1123 + __METHOD__,
1124 + '1.6.44',
1125 + ''
1126 + );
1127 +
1128 + /**
1129 + * Deprecated filter in deprecated method.
1130 + *
1131 + * Please note that prior to 1.6.44, the hook used here was `charitable_user_address_fields`,
1132 + * which is used elsewhere in a different context and thus resulted in unexpected results.
1133 + *
1134 + * @since 1.6.44
1135 + *
1136 + * @param array $address_fields The address fields.
1137 + */
1138 + return apply_filters(
1139 + 'charitable_user_address_fields_deprecated',
1140 + array(
1141 + 'donor_address',
1142 + 'donor_address_2',
1143 + 'donor_city',
1144 + 'donor_state',
1145 + 'donor_postcode',
1146 + 'donor_country',
1147 + )
1148 + );
1038 1149 }
1039 1150 }
1040 1151
1041 1152 endif;