PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.1.2
GiveWP – Donation Plugin and Fundraising Platform v2.1.2
4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / includes / class-give-donor.php
give / includes Last commit date
admin 8 years ago api 8 years ago deprecated 8 years ago donors 8 years ago emails 8 years ago forms 8 years ago gateways 8 years ago libraries 8 years ago payments 8 years ago actions.php 8 years ago ajax-functions.php 8 years ago class-give-async-process.php 8 years ago class-give-background-updater.php 8 years ago class-give-cache.php 8 years ago class-give-cli-commands.php 8 years ago class-give-cron.php 8 years ago class-give-db-donor-meta.php 8 years ago class-give-db-donors.php 8 years ago class-give-db-form-meta.php 8 years ago class-give-db-logs-meta.php 8 years ago class-give-db-logs.php 8 years ago class-give-db-meta.php 8 years ago class-give-db-payment-meta.php 8 years ago class-give-db-sequential-ordering.php 8 years ago class-give-db.php 8 years ago class-give-donate-form.php 8 years ago class-give-donor.php 8 years ago class-give-email-access.php 8 years ago class-give-gravatars.php 8 years ago class-give-html-elements.php 8 years ago class-give-license-handler.php 8 years ago class-give-logging.php 8 years ago class-give-roles.php 8 years ago class-give-scripts.php 8 years ago class-give-session.php 8 years ago class-give-stats.php 8 years ago class-give-template-loader.php 8 years ago class-give-tooltips.php 8 years ago class-give-translation.php 8 years ago class-notices.php 8 years ago country-functions.php 8 years ago currency-functions.php 8 years ago error-tracking.php 8 years ago filters.php 8 years ago formatting.php 8 years ago import-functions.php 8 years ago install.php 8 years ago login-register.php 8 years ago misc-functions.php 8 years ago plugin-compatibility.php 8 years ago post-types.php 8 years ago price-functions.php 8 years ago process-donation.php 8 years ago shortcodes.php 8 years ago template-functions.php 8 years ago user-functions.php 8 years ago
class-give-donor.php
1582 lines
1 <?php
2 /**
3 * Donor
4 *
5 * @package Give
6 * @subpackage Classes/Give_Donor
7 * @copyright Copyright (c) 2016, WordImpress
8 * @license https://opensource.org/licenses/gpl-license GNU Public License
9 * @since 1.0
10 */
11
12 // Exit if accessed directly.
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 /**
18 * Give_Donor Class
19 *
20 * This class handles customers.
21 *
22 * @since 1.0
23 */
24 class Give_Donor {
25
26 /**
27 * The donor ID
28 *
29 * @since 1.0
30 * @access public
31 *
32 * @var int
33 */
34 public $id = 0;
35
36 /**
37 * The donor's donation count.
38 *
39 * @since 1.0
40 * @access public
41 *
42 * @var int
43 */
44 public $purchase_count = 0;
45
46 /**
47 * The donor's lifetime value.
48 *
49 * @since 1.0
50 * @access public
51 *
52 * @var int
53 */
54 public $purchase_value = 0;
55
56 /**
57 * The donor's email.
58 *
59 * @since 1.0
60 * @access public
61 *
62 * @var string
63 */
64 public $email;
65
66 /**
67 * The donor's emails.
68 *
69 * @since 1.7
70 * @access public
71 *
72 * @var array
73 */
74 public $emails;
75
76 /**
77 * The donor's name.
78 *
79 * @since 1.0
80 * @access public
81 *
82 * @var string
83 */
84 public $name;
85
86 /**
87 * The donor creation date.
88 *
89 * @since 1.0
90 * @access public
91 *
92 * @var string
93 */
94 public $date_created;
95
96 /**
97 * The payment IDs associated with the donor.
98 *
99 * @since 1.0
100 * @access public
101 *
102 * @var string
103 */
104 public $payment_ids;
105
106 /**
107 * The user ID associated with the donor.
108 *
109 * @since 1.0
110 * @access public
111 *
112 * @var int
113 */
114 public $user_id;
115
116 /**
117 * Donor notes saved by admins.
118 *
119 * @since 1.0
120 * @access public
121 *
122 * @var array
123 */
124 public $notes;
125
126 /**
127 * Donor address.
128 *
129 * @since 1.0
130 * @access public
131 *
132 * @var array
133 */
134 public $address = array();
135
136 /**
137 * The Database Abstraction
138 *
139 * @since 1.0
140 * @access protected
141 *
142 * @var Give_DB_Donors
143 */
144 protected $db;
145
146 /**
147 * Give_Donor constructor.
148 *
149 * @param int|bool $_id_or_email
150 * @param bool $by_user_id
151 */
152 public function __construct( $_id_or_email = false, $by_user_id = false ) {
153
154 $this->db = Give()->donors;
155
156 if (
157 false === $_id_or_email
158 || ( is_numeric( $_id_or_email ) && (int) $_id_or_email !== absint( $_id_or_email ) )
159 ) {
160 return false;
161 }
162
163 $by_user_id = is_bool( $by_user_id ) ? $by_user_id : false;
164
165 if ( is_numeric( $_id_or_email ) ) {
166 $field = $by_user_id ? 'user_id' : 'id';
167 } else {
168 $field = 'email';
169 }
170
171 $donor = $this->db->get_donor_by( $field, $_id_or_email );
172
173 if ( empty( $donor ) || ! is_object( $donor ) ) {
174 return false;
175 }
176
177 $this->setup_donor( $donor );
178
179 }
180
181 /**
182 * Setup Donor
183 *
184 * Set donor variables.
185 *
186 * @since 1.0
187 * @access private
188 *
189 * @param object $donor The Donor Object.
190 *
191 * @return bool If the setup was successful or not.
192 */
193 private function setup_donor( $donor ) {
194
195 if ( ! is_object( $donor ) ) {
196 return false;
197 }
198
199 // Get cached donors.
200 $donor_vars = Give_Cache::get_group( $donor->id, 'give-donors' );
201
202 if( is_null( $donor_vars ) ){
203 foreach ( $donor as $key => $value ) {
204
205 switch ( $key ) {
206
207 case 'notes':
208 $this->$key = $this->get_notes();
209 break;
210
211 default:
212 $this->$key = $value;
213 break;
214
215 }
216 }
217
218 // Get donor's all email including primary email.
219 $this->emails = (array) $this->get_meta( 'additional_email', false );
220 $this->emails = array( 'primary' => $this->email ) + $this->emails;
221
222 $this->setup_address();
223
224 Give_Cache::set_group( $donor->id, get_object_vars( $this ), 'give-donors' );
225 } else{
226 foreach ( $donor_vars as $donor_var => $value ) {
227 $this->$donor_var = $value;
228 }
229 }
230
231 // Donor ID and email are the only things that are necessary, make sure they exist.
232 if ( ! empty( $this->id ) && ! empty( $this->email ) ) {
233 return true;
234 }
235
236 return false;
237
238 }
239
240
241 /**
242 * Setup donor address.
243 *
244 * @since 2.0
245 * @access public
246 */
247 public function setup_address() {
248 global $wpdb;
249 $meta_type = Give()->donor_meta->meta_type;
250
251 $addresses = $wpdb->get_results(
252 $wpdb->prepare(
253 "
254 SELECT meta_key, meta_value FROM {$wpdb->donormeta}
255 WHERE meta_key
256 LIKE '%%%s%%'
257 AND {$meta_type}_id=%d
258 ",
259 'give_donor_address',
260 $this->id
261 ),
262 ARRAY_N
263 );
264
265 if ( empty( $addresses ) ) {
266 return $this->address;
267 }
268
269 foreach ( $addresses as $address ) {
270 $address[0] = str_replace( '_give_donor_address_', '', $address[0] );
271 $address[0] = explode( '_', $address[0] );
272
273 if ( 3 === count( $address[0] ) ) {
274 $this->address[ $address[0][0] ][ $address[0][2] ][ $address[0][1] ] = $address[1];
275 } else {
276 $this->address[ $address[0][0] ][ $address[0][1] ] = $address[1];
277 }
278 }
279 }
280
281 /**
282 * Magic __get function to dispatch a call to retrieve a private property.
283 *
284 * @since 1.0
285 * @access public
286 * @param $key
287 *
288 * @return mixed|\WP_Error
289 */
290 public function __get( $key ) {
291
292 if ( method_exists( $this, 'get_' . $key ) ) {
293
294 return call_user_func( array( $this, 'get_' . $key ) );
295
296 } else {
297
298 /* translators: %s: property key */
299 return new WP_Error( 'give-donor-invalid-property', sprintf( esc_html__( 'Can\'t get property %s.', 'give' ), $key ) );
300
301 }
302
303 }
304
305 /**
306 * Creates a donor.
307 *
308 * @since 1.0
309 * @access public
310 *
311 * @param array $data Array of attributes for a donor.
312 *
313 * @return bool|int False if not a valid creation, donor ID if user is found or valid creation.
314 */
315 public function create( $data = array() ) {
316
317 if ( $this->id != 0 || empty( $data ) ) {
318 return false;
319 }
320
321 $defaults = array(
322 'payment_ids' => '',
323 );
324
325 $args = wp_parse_args( $data, $defaults );
326 $args = $this->sanitize_columns( $args );
327
328 if ( empty( $args['email'] ) || ! is_email( $args['email'] ) ) {
329 return false;
330 }
331
332 if ( ! empty( $args['payment_ids'] ) && is_array( $args['payment_ids'] ) ) {
333 $args['payment_ids'] = implode( ',', array_unique( array_values( $args['payment_ids'] ) ) );
334 }
335
336 /**
337 * Fires before creating donors.
338 *
339 * @since 1.0
340 *
341 * @param array $args Donor attributes.
342 */
343 do_action( 'give_donor_pre_create', $args );
344
345 $created = false;
346
347 // The DB class 'add' implies an update if the donor being asked to be created already exists
348 if ( $this->db->add( $data ) ) {
349
350 // We've successfully added/updated the donor, reset the class vars with the new data
351 $donor = $this->db->get_donor_by( 'email', $args['email'] );
352
353 // Setup the donor data with the values from DB
354 $this->setup_donor( $donor );
355
356 $created = $this->id;
357 }
358
359 /**
360 * Fires after creating donors.
361 *
362 * @since 1.0
363 *
364 * @param bool|int $created False if not a valid creation, donor ID if user is found or valid creation.
365 * @param array $args Customer attributes.
366 */
367 do_action( 'give_donor_post_create', $created, $args );
368
369 return $created;
370
371 }
372
373 /**
374 * Updates a donor record.
375 *
376 * @since 1.0
377 * @access public
378 *
379 * @param array $data Array of data attributes for a donor (checked via whitelist).
380 *
381 * @return bool If the update was successful or not.
382 */
383 public function update( $data = array() ) {
384
385 if ( empty( $data ) ) {
386 return false;
387 }
388
389 $data = $this->sanitize_columns( $data );
390
391 /**
392 * Fires before updating donors.
393 *
394 * @since 1.0
395 *
396 * @param int $donor_id Donor id.
397 * @param array $data Donor attributes.
398 */
399 do_action( 'give_donor_pre_update', $this->id, $data );
400
401 $updated = false;
402
403 if ( $this->db->update( $this->id, $data ) ) {
404
405 $donor = $this->db->get_donor_by( 'id', $this->id );
406
407 $this->setup_donor( $donor );
408
409 $updated = true;
410 }
411
412 /**
413 * Fires after updating donors.
414 *
415 * @since 1.0
416 *
417 * @param bool $updated If the update was successful or not.
418 * @param int $donor_id Donor id.
419 * @param array $data Donor attributes.
420 */
421 do_action( 'give_donor_post_update', $updated, $this->id, $data );
422
423 return $updated;
424 }
425
426 /**
427 * Attach Payment
428 *
429 * Attach payment to the donor then triggers increasing stats.
430 *
431 * @since 1.0
432 * @access public
433 *
434 * @param int $payment_id The payment ID to attach to the donor.
435 * @param bool $update_stats For backwards compatibility, if we should increase the stats or not.
436 *
437 * @return bool If the attachment was successfully.
438 */
439 public function attach_payment( $payment_id = 0, $update_stats = true ) {
440
441 if ( empty( $payment_id ) ) {
442 return false;
443 }
444
445 if ( empty( $this->payment_ids ) ) {
446
447 $new_payment_ids = $payment_id;
448
449 } else {
450
451 $payment_ids = array_map( 'absint', explode( ',', $this->payment_ids ) );
452
453 if ( in_array( $payment_id, $payment_ids ) ) {
454 $update_stats = false;
455 }
456
457 $payment_ids[] = $payment_id;
458
459 $new_payment_ids = implode( ',', array_unique( array_values( $payment_ids ) ) );
460
461 }
462
463 /**
464 * Fires before attaching payments to customers.
465 *
466 * @since 1.0
467 *
468 * @param int $payment_id Payment id.
469 * @param int $donor_id Customer id.
470 */
471 do_action( 'give_donor_pre_attach_payment', $payment_id, $this->id );
472
473 $payment_added = $this->update( array( 'payment_ids' => $new_payment_ids ) );
474
475 if ( $payment_added ) {
476
477 $this->payment_ids = $new_payment_ids;
478
479 // We added this payment successfully, increment the stats
480 if ( $update_stats ) {
481 $payment_amount = give_donation_amount( $payment_id, array( 'type' => 'stats' ) );
482
483 if ( ! empty( $payment_amount ) ) {
484 $this->increase_value( $payment_amount );
485 }
486
487 $this->increase_purchase_count();
488 }
489 }
490
491 /**
492 * Fires after attaching payments to the donor.
493 *
494 * @since 1.0
495 *
496 * @param bool $payment_added If the attachment was successfully.
497 * @param int $payment_id Payment id.
498 * @param int $donor_id Donor id.
499 */
500 do_action( 'give_donor_post_attach_payment', $payment_added, $payment_id, $this->id );
501
502 return $payment_added;
503 }
504
505 /**
506 * Remove Payment
507 *
508 * Remove a payment from this donor, then triggers reducing stats.
509 *
510 * @since 1.0
511 * @access public
512 *
513 * @param int $payment_id The Payment ID to remove.
514 * @param bool $update_stats For backwards compatibility, if we should increase the stats or not.
515 *
516 * @return boolean If the removal was successful.
517 */
518 public function remove_payment( $payment_id = 0, $update_stats = true ) {
519
520 if ( empty( $payment_id ) ) {
521 return false;
522 }
523
524 $payment = new Give_Payment( $payment_id );
525
526 if ( 'publish' !== $payment->status && 'revoked' !== $payment->status ) {
527 $update_stats = false;
528 }
529
530 $new_payment_ids = '';
531
532 if ( ! empty( $this->payment_ids ) ) {
533
534 $payment_ids = array_map( 'absint', explode( ',', $this->payment_ids ) );
535
536 $pos = array_search( $payment_id, $payment_ids );
537 if ( false === $pos ) {
538 return false;
539 }
540
541 unset( $payment_ids[ $pos ] );
542 $payment_ids = array_filter( $payment_ids );
543
544 $new_payment_ids = implode( ',', array_unique( array_values( $payment_ids ) ) );
545
546 }
547
548 /**
549 * Fires before removing payments from customers.
550 *
551 * @since 1.0
552 *
553 * @param int $payment_id Payment id.
554 * @param int $donor_id Customer id.
555 */
556 do_action( 'give_donor_pre_remove_payment', $payment_id, $this->id );
557
558 $payment_removed = $this->update( array( 'payment_ids' => $new_payment_ids ) );
559
560 if ( $payment_removed ) {
561
562 $this->payment_ids = $new_payment_ids;
563
564 if ( $update_stats ) {
565 // We removed this payment successfully, decrement the stats
566 $payment_amount = give_donation_amount( $payment_id );
567
568 if ( ! empty( $payment_amount ) ) {
569 $this->decrease_value( $payment_amount );
570 }
571
572 $this->decrease_donation_count();
573 }
574 }
575
576 /**
577 * Fires after removing payments from donors.
578 *
579 * @since 1.0
580 *
581 * @param bool $payment_removed If the removal was successfully.
582 * @param int $payment_id Payment id.
583 * @param int $donor_id Donor id.
584 */
585 do_action( 'give_donor_post_remove_payment', $payment_removed, $payment_id, $this->id );
586
587 return $payment_removed;
588
589 }
590
591 /**
592 * Increase the donation count of a donor.
593 *
594 * @since 1.0
595 * @access public
596 *
597 * @param int $count The number to increase by.
598 *
599 * @return int The donation count.
600 */
601 public function increase_purchase_count( $count = 1 ) {
602
603 // Make sure it's numeric and not negative.
604 if ( ! is_numeric( $count ) || $count != absint( $count ) ) {
605 return false;
606 }
607
608 $new_total = (int) $this->purchase_count + (int) $count;
609
610 /**
611 * Fires before increasing the donor's donation count.
612 *
613 * @since 1.0
614 *
615 * @param int $count The number to increase by.
616 * @param int $donor_id Donor id.
617 */
618 do_action( 'give_donor_pre_increase_donation_count', $count, $this->id );
619
620 if ( $this->update( array( 'purchase_count' => $new_total ) ) ) {
621 $this->purchase_count = $new_total;
622 }
623
624 /**
625 * Fires after increasing the donor's donation count.
626 *
627 * @since 1.0
628 *
629 * @param int $purchase_count Donor donation count.
630 * @param int $count The number increased by.
631 * @param int $donor_id Donor id.
632 */
633 do_action( 'give_donor_post_increase_donation_count', $this->purchase_count, $count, $this->id );
634
635 return $this->purchase_count;
636 }
637
638 /**
639 * Decrease the donor donation count.
640 *
641 * @since 1.0
642 * @access public
643 *
644 * @param int $count The amount to decrease by.
645 *
646 * @return mixed If successful, the new count, otherwise false.
647 */
648 public function decrease_donation_count( $count = 1 ) {
649
650 // Make sure it's numeric and not negative
651 if ( ! is_numeric( $count ) || $count != absint( $count ) ) {
652 return false;
653 }
654
655 $new_total = (int) $this->purchase_count - (int) $count;
656
657 if ( $new_total < 0 ) {
658 $new_total = 0;
659 }
660
661 /**
662 * Fires before decreasing the donor's donation count.
663 *
664 * @since 1.0
665 *
666 * @param int $count The number to decrease by.
667 * @param int $donor_id Customer id.
668 */
669 do_action( 'give_donor_pre_decrease_donation_count', $count, $this->id );
670
671 if ( $this->update( array( 'purchase_count' => $new_total ) ) ) {
672 $this->purchase_count = $new_total;
673 }
674
675 /**
676 * Fires after decreasing the donor's donation count.
677 *
678 * @since 1.0
679 *
680 * @param int $purchase_count Donor's donation count.
681 * @param int $count The number decreased by.
682 * @param int $donor_id Donor id.
683 */
684 do_action( 'give_donor_post_decrease_donation_count', $this->purchase_count, $count, $this->id );
685
686 return $this->purchase_count;
687 }
688
689 /**
690 * Increase the donor's lifetime value.
691 *
692 * @since 1.0
693 * @access public
694 *
695 * @param float $value The value to increase by.
696 *
697 * @return mixed If successful, the new value, otherwise false.
698 */
699 public function increase_value( $value = 0.00 ) {
700
701 $new_value = floatval( $this->purchase_value ) + $value;
702
703 /**
704 * Fires before increasing donor lifetime value.
705 *
706 * @since 1.0
707 *
708 * @param float $value The value to increase by.
709 * @param int $donor_id Customer id.
710 */
711 do_action( 'give_donor_pre_increase_value', $value, $this->id );
712
713 if ( $this->update( array( 'purchase_value' => $new_value ) ) ) {
714 $this->purchase_value = $new_value;
715 }
716
717 /**
718 * Fires after increasing donor lifetime value.
719 *
720 * @since 1.0
721 *
722 * @param float $purchase_value Donor's lifetime value.
723 * @param float $value The value increased by.
724 * @param int $donor_id Donor id.
725 */
726 do_action( 'give_donor_post_increase_value', $this->purchase_value, $value, $this->id );
727
728 return $this->purchase_value;
729 }
730
731 /**
732 * Decrease a donor's lifetime value.
733 *
734 * @since 1.0
735 * @access public
736 *
737 * @param float $value The value to decrease by.
738 *
739 * @return mixed If successful, the new value, otherwise false.
740 */
741 public function decrease_value( $value = 0.00 ) {
742
743 $new_value = floatval( $this->purchase_value ) - $value;
744
745 if ( $new_value < 0 ) {
746 $new_value = 0.00;
747 }
748
749 /**
750 * Fires before decreasing donor lifetime value.
751 *
752 * @since 1.0
753 *
754 * @param float $value The value to decrease by.
755 * @param int $donor_id Donor id.
756 */
757 do_action( 'give_donor_pre_decrease_value', $value, $this->id );
758
759 if ( $this->update( array( 'purchase_value' => $new_value ) ) ) {
760 $this->purchase_value = $new_value;
761 }
762
763 /**
764 * Fires after decreasing donor lifetime value.
765 *
766 * @since 1.0
767 *
768 * @param float $purchase_value Donor lifetime value.
769 * @param float $value The value decreased by.
770 * @param int $donor_id Donor id.
771 */
772 do_action( 'give_donor_post_decrease_value', $this->purchase_value, $value, $this->id );
773
774 return $this->purchase_value;
775 }
776
777 /**
778 * Decrease/Increase a donor's lifetime value.
779 *
780 * This function will update donation stat on basis of current amount and new amount donation difference.
781 * Difference value can positive or negative. Negative value will decrease user donation stat while positive value increase donation stat.
782 *
783 * @since 1.0
784 * @access public
785 *
786 * @param float $curr_amount Current Donation amount.
787 * @param float $new_amount New (changed) Donation amount.
788 *
789 * @return mixed If successful, the new donation stat value, otherwise false.
790 */
791 public function update_donation_value( $curr_amount, $new_amount ) {
792 /**
793 * Payment total difference value can be:
794 * zero (in case amount not change)
795 * or -ve (in case amount decrease)
796 * or +ve (in case amount increase)
797 */
798 $payment_total_diff = $new_amount - $curr_amount;
799
800 // We do not need to update donation stat if donation did not change.
801 if ( ! $payment_total_diff ) {
802 return false;
803 }
804
805 if ( $payment_total_diff > 0 ) {
806 $this->increase_value( $payment_total_diff );
807 } else {
808 // Pass payment total difference as +ve value to decrease amount from user lifetime stat.
809 $this->decrease_value( - $payment_total_diff );
810 }
811
812 return $this->purchase_value;
813 }
814
815 /**
816 * Get the parsed notes for a donor as an array.
817 *
818 * @since 1.0
819 * @access public
820 *
821 * @param int $length The number of notes to get.
822 * @param int $paged What note to start at.
823 *
824 * @return array The notes requested.
825 */
826 public function get_notes( $length = 20, $paged = 1 ) {
827
828 $length = is_numeric( $length ) ? $length : 20;
829 $offset = is_numeric( $paged ) && $paged != 1 ? ( ( absint( $paged ) - 1 ) * $length ) : 0;
830
831 $all_notes = $this->get_raw_notes();
832 $notes_array = array_reverse( array_filter( explode( "\n\n", $all_notes ) ) );
833
834 $desired_notes = array_slice( $notes_array, $offset, $length );
835
836 return $desired_notes;
837
838 }
839
840 /**
841 * Get the total number of notes we have after parsing.
842 *
843 * @since 1.0
844 * @access public
845 *
846 * @return int The number of notes for the donor.
847 */
848 public function get_notes_count() {
849
850 $all_notes = $this->get_raw_notes();
851 $notes_array = array_reverse( array_filter( explode( "\n\n", $all_notes ) ) );
852
853 return count( $notes_array );
854
855 }
856
857 /**
858 * Get the total donation amount.
859 *
860 * @since 1.8.17
861 *
862 * @param array $args Pass any additional data.
863 *
864 * @return string|float
865 */
866 public function get_total_donation_amount( $args = array() ) {
867
868 /**
869 * Filter total donation amount.
870 *
871 * @since 1.8.17
872 *
873 * @param string|float $purchase_value Donor Purchase value.
874 * @param integer $donor_id Donor ID.
875 * @param array $args Pass additional data.
876 */
877 return apply_filters( 'give_get_total_donation_amount', $this->purchase_value, $this->id, $args );
878 }
879
880 /**
881 * Add a note for the donor.
882 *
883 * @since 1.0
884 * @access public
885 *
886 * @param string $note The note to add. Default is empty.
887 *
888 * @return string|boolean The new note if added successfully, false otherwise.
889 */
890 public function add_note( $note = '' ) {
891
892 $note = trim( $note );
893 if ( empty( $note ) ) {
894 return false;
895 }
896
897 $notes = $this->get_raw_notes();
898
899 if ( empty( $notes ) ) {
900 $notes = '';
901 }
902
903 $note_string = date_i18n( 'F j, Y H:i:s', current_time( 'timestamp' ) ) . ' - ' . $note;
904 $new_note = apply_filters( 'give_customer_add_note_string', $note_string );
905 $notes .= "\n\n" . $new_note;
906
907 /**
908 * Fires before donor note is added.
909 *
910 * @since 1.0
911 *
912 * @param string $new_note New note to add.
913 * @param int $donor_id Donor id.
914 */
915 do_action( 'give_donor_pre_add_note', $new_note, $this->id );
916
917 $updated = $this->update( array( 'notes' => $notes ) );
918
919 if ( $updated ) {
920 $this->notes = $this->get_notes();
921 }
922
923 /**
924 * Fires after donor note added.
925 *
926 * @since 1.0
927 *
928 * @param array $donor_notes Donor notes.
929 * @param string $new_note New note added.
930 * @param int $donor_id Donor id.
931 */
932 do_action( 'give_donor_post_add_note', $this->notes, $new_note, $this->id );
933
934 // Return the formatted note, so we can test, as well as update any displays
935 return $new_note;
936
937 }
938
939 /**
940 * Get the notes column for the donor
941 *
942 * @since 1.0
943 * @access private
944 *
945 * @return string The Notes for the donor, non-parsed.
946 */
947 private function get_raw_notes() {
948
949 $all_notes = $this->db->get_column( 'notes', $this->id );
950
951 return $all_notes;
952
953 }
954
955 /**
956 * Retrieve a meta field for a donor.
957 *
958 * @since 1.6
959 * @access public
960 *
961 * @param string $meta_key The meta key to retrieve. Default is empty.
962 * @param bool $single Whether to return a single value. Default is true.
963 *
964 * @return mixed Will be an array if $single is false. Will be value of meta data field if $single is true.
965 */
966 public function get_meta( $meta_key = '', $single = true ) {
967 return Give()->donor_meta->get_meta( $this->id, $meta_key, $single );
968 }
969
970 /**
971 * Add a meta data field to a donor.
972 *
973 * @since 1.6
974 * @access public
975 *
976 * @param string $meta_key Metadata name. Default is empty.
977 * @param mixed $meta_value Metadata value.
978 * @param bool $unique Optional. Whether the same key should not be added. Default is false.
979 *
980 * @return bool False for failure. True for success.
981 */
982 public function add_meta( $meta_key = '', $meta_value, $unique = false ) {
983 return Give()->donor_meta->add_meta( $this->id, $meta_key, $meta_value, $unique );
984 }
985
986 /**
987 * Update a meta field based on donor ID.
988 *
989 * @since 1.6
990 * @access public
991 *
992 * @param string $meta_key Metadata key. Default is empty.
993 * @param mixed $meta_value Metadata value.
994 * @param mixed $prev_value Optional. Previous value to check before removing. Default is empty.
995 *
996 * @return bool False on failure, true if success.
997 */
998 public function update_meta( $meta_key = '', $meta_value, $prev_value = '' ) {
999 return Give()->donor_meta->update_meta( $this->id, $meta_key, $meta_value, $prev_value );
1000 }
1001
1002 /**
1003 * Remove metadata matching criteria from a donor.
1004 *
1005 * @since 1.6
1006 * @access public
1007 *
1008 * @param string $meta_key Metadata name. Default is empty.
1009 * @param mixed $meta_value Optional. Metadata value. Default is empty.
1010 *
1011 * @return bool False for failure. True for success.
1012 */
1013 public function delete_meta( $meta_key = '', $meta_value = '' ) {
1014 return Give()->donor_meta->delete_meta( $this->id, $meta_key, $meta_value );
1015 }
1016
1017 /**
1018 * Sanitize the data for update/create
1019 *
1020 * @since 1.0
1021 * @access private
1022 *
1023 * @param array $data The data to sanitize.
1024 *
1025 * @return array The sanitized data, based off column defaults.
1026 */
1027 private function sanitize_columns( $data ) {
1028
1029 $columns = $this->db->get_columns();
1030 $default_values = $this->db->get_column_defaults();
1031
1032 foreach ( $columns as $key => $type ) {
1033
1034 // Only sanitize data that we were provided
1035 if ( ! array_key_exists( $key, $data ) ) {
1036 continue;
1037 }
1038
1039 switch ( $type ) {
1040
1041 case '%s':
1042 if ( 'email' == $key ) {
1043 $data[ $key ] = sanitize_email( $data[ $key ] );
1044 } elseif ( 'notes' == $key ) {
1045 $data[ $key ] = strip_tags( $data[ $key ] );
1046 } else {
1047 $data[ $key ] = sanitize_text_field( $data[ $key ] );
1048 }
1049 break;
1050
1051 case '%d':
1052 if ( ! is_numeric( $data[ $key ] ) || (int) $data[ $key ] !== absint( $data[ $key ] ) ) {
1053 $data[ $key ] = $default_values[ $key ];
1054 } else {
1055 $data[ $key ] = absint( $data[ $key ] );
1056 }
1057 break;
1058
1059 case '%f':
1060 // Convert what was given to a float
1061 $value = floatval( $data[ $key ] );
1062
1063 if ( ! is_float( $value ) ) {
1064 $data[ $key ] = $default_values[ $key ];
1065 } else {
1066 $data[ $key ] = $value;
1067 }
1068 break;
1069
1070 default:
1071 $data[ $key ] = sanitize_text_field( $data[ $key ] );
1072 break;
1073
1074 }
1075 }
1076
1077 return $data;
1078 }
1079
1080 /**
1081 * Attach an email to the donor
1082 *
1083 * @since 1.7
1084 * @access public
1085 *
1086 * @param string $email The email address to attach to the donor
1087 * @param bool $primary Allows setting the email added as the primary
1088 *
1089 * @return bool If the email was added successfully
1090 */
1091 public function add_email( $email = '', $primary = false ) {
1092 if ( ! is_email( $email ) ) {
1093 return false;
1094 }
1095 $existing = new Give_Donor( $email );
1096
1097 if ( $existing->id > 0 ) {
1098 // Email address already belongs to another donor
1099 return false;
1100 }
1101
1102 if ( email_exists( $email ) ) {
1103 $user = get_user_by( 'email', $email );
1104 if ( $user->ID != $this->user_id ) {
1105 return false;
1106 }
1107 }
1108
1109 do_action( 'give_donor_pre_add_email', $email, $this->id, $this );
1110
1111 // Add is used to ensure duplicate emails are not added
1112 $ret = (bool) $this->add_meta( 'additional_email', $email );
1113
1114 do_action( 'give_donor_post_add_email', $email, $this->id, $this );
1115
1116 if ( $ret && true === $primary ) {
1117 $this->set_primary_email( $email );
1118 }
1119
1120 return $ret;
1121 }
1122
1123 /**
1124 * Remove an email from the donor.
1125 *
1126 * @since 1.7
1127 * @access public
1128 *
1129 * @param string $email The email address to remove from the donor.
1130 *
1131 * @return bool If the email was removed successfully.
1132 */
1133 public function remove_email( $email = '' ) {
1134 if ( ! is_email( $email ) ) {
1135 return false;
1136 }
1137
1138 do_action( 'give_donor_pre_remove_email', $email, $this->id, $this );
1139
1140 $ret = (bool) $this->delete_meta( 'additional_email', $email );
1141
1142 do_action( 'give_donor_post_remove_email', $email, $this->id, $this );
1143
1144 return $ret;
1145 }
1146
1147 /**
1148 * Set an email address as the donor's primary email.
1149 *
1150 * This will move the donor's previous primary email to an additional email.
1151 *
1152 * @since 1.7
1153 * @access public
1154 *
1155 * @param string $new_primary_email The email address to remove from the donor.
1156 *
1157 * @return bool If the email was set as primary successfully.
1158 */
1159 public function set_primary_email( $new_primary_email = '' ) {
1160 if ( ! is_email( $new_primary_email ) ) {
1161 return false;
1162 }
1163
1164 do_action( 'give_donor_pre_set_primary_email', $new_primary_email, $this->id, $this );
1165
1166 $existing = new Give_Donor( $new_primary_email );
1167
1168 if ( $existing->id > 0 && (int) $existing->id !== (int) $this->id ) {
1169 // This email belongs to another donor.
1170 return false;
1171 }
1172
1173 $old_email = $this->email;
1174
1175 // Update donor record with new email.
1176 $update = $this->update( array( 'email' => $new_primary_email ) );
1177
1178 // Remove new primary from list of additional emails.
1179 $remove = $this->remove_email( $new_primary_email );
1180
1181 // Add old email to additional emails list.
1182 $add = $this->add_email( $old_email );
1183
1184 $ret = $update && $remove && $add;
1185
1186 if ( $ret ) {
1187 $this->email = $new_primary_email;
1188 }
1189
1190 do_action( 'give_donor_post_set_primary_email', $new_primary_email, $this->id, $this );
1191
1192 return $ret;
1193 }
1194
1195 /**
1196 * Check if address valid or not.
1197 *
1198 * @since 2.0
1199 * @access private
1200 *
1201 * @param $address
1202 *
1203 * @return bool
1204 */
1205 private function is_valid_address( $address ) {
1206 $is_valid_address = true;
1207
1208 // Address ready to process even if only one value set.
1209 foreach ( $address as $address_type => $value ) {
1210 // @todo: Handle state field validation on basis of country.
1211 if( in_array( $address_type, array( 'line2', 'state' )) ) {
1212 continue;
1213 }
1214
1215 if ( empty( $value ) ) {
1216 $is_valid_address = false;
1217 break;
1218 }
1219 }
1220
1221 return $is_valid_address;
1222 }
1223
1224 /**
1225 * Add donor address
1226 *
1227 * @since 2.0
1228 * @access public
1229 *
1230 * @param string $address_type
1231 * @param array $address {
1232 *
1233 * @type string $address2
1234 * @type string city
1235 * @type string zip
1236 * @type string state
1237 * @type string country
1238 * }
1239 *
1240 * @return bool
1241 */
1242 public function add_address( $address_type, $address ) {
1243 // Bailout.
1244 if ( empty( $address_type ) || ! $this->is_valid_address( $address ) || ! $this->id ) {
1245 return false;
1246 }
1247
1248 // Check if multiple address exist or not and set params.
1249 $multi_address_id = null;
1250 if( $is_multi_address = ( false !== strpos( $address_type, '[]' ) ) ) {
1251 $address_type = $is_multi_address ?
1252 str_replace( '[]', '', $address_type ) :
1253 $address_type;
1254 } elseif ( $is_multi_address = ( false !== strpos( $address_type, '_' ) ) ){
1255 $multi_address_id = $is_multi_address ?
1256 array_pop( explode( '_', $address_type ) ) :
1257 $address_type;
1258
1259 $address_type = $is_multi_address ?
1260 array_shift( explode( '_', $address_type ) ) :
1261 $address_type;
1262 }
1263
1264 // Bailout: do not save duplicate orders
1265 if( $this->is_address_exist( $address_type, $address ) ) {
1266 return false;
1267 }
1268
1269 // Set default address.
1270 $address = wp_parse_args(
1271 $address,
1272 array(
1273 'line1' => '',
1274 'line2' => '',
1275 'city' => '',
1276 'state' => '',
1277 'country' => '',
1278 'zip' => '',
1279 )
1280 );
1281
1282 // Set meta key prefix.
1283 global $wpdb;
1284 $meta_key_prefix = "_give_donor_address_{$address_type}_{address_name}";
1285 $meta_type = Give()->donor_meta->meta_type;
1286
1287 if ( $is_multi_address ) {
1288 if ( is_null( $multi_address_id ) ) {
1289 // Get latest address key to set multi address id.
1290 $multi_address_id = $wpdb->get_var(
1291 $wpdb->prepare(
1292 "
1293 SELECT meta_key FROM {$wpdb->donormeta}
1294 WHERE meta_key
1295 LIKE '%%%s%%'
1296 AND {$meta_type}_id=%d
1297 ORDER BY meta_id DESC
1298 LIMIT 1
1299 ",
1300 "_give_donor_address_{$address_type}_line1",
1301 $this->id
1302 )
1303 );
1304
1305 if( ! empty( $multi_address_id ) ) {
1306 $multi_address_id = absint( substr( strrchr( $multi_address_id, '_' ), 1 ) );
1307 $multi_address_id++;
1308 } else{
1309 $multi_address_id = 0;
1310 }
1311 }
1312
1313 $meta_key_prefix = "_give_donor_address_{$address_type}_{address_name}_{$multi_address_id}";
1314 }
1315
1316 // Save donor address.
1317 foreach ( $address as $type => $value ) {
1318 $meta_key = str_replace( '{address_name}', $type, $meta_key_prefix );
1319 Give()->donor_meta->update_meta( $this->id, $meta_key, $value );
1320 }
1321
1322 $this->setup_address();
1323
1324 return true;
1325 }
1326
1327 /**
1328 * Remove donor address
1329 *
1330 * @since 2.0
1331 * @access public
1332 * @global wpdb $wpdb
1333 *
1334 * @param string $address_id
1335 *
1336 * @return bool
1337 */
1338 public function remove_address( $address_id ) {
1339 global $wpdb;
1340
1341 // Get address type.
1342 $is_multi_address = false !== strpos( $address_id, '_' ) ? true : false;
1343
1344 $address_type = false !== strpos( $address_id, '_' ) ?
1345 array_shift( explode( '_', $address_id ) ) :
1346 $address_id;
1347
1348 $address_count = false !== strpos( $address_id, '_' ) ?
1349 array_pop( explode( '_', $address_id ) ) :
1350 null;
1351
1352 // Set meta key prefix.
1353 $meta_key_prefix = "_give_donor_address_{$address_type}_%";
1354 if ( $is_multi_address && is_numeric( $address_count ) ) {
1355 $meta_key_prefix .= "_{$address_count}";
1356 }
1357
1358 $meta_type = Give()->donor_meta->meta_type;
1359
1360 // Process query.
1361 $row_affected = $wpdb->query(
1362 $wpdb->prepare(
1363 "
1364 DELETE FROM {$wpdb->donormeta}
1365 WHERE meta_key
1366 LIKE '%s'
1367 AND {$meta_type}_id=%d
1368 ",
1369 $meta_key_prefix,
1370 $this->id
1371 )
1372 );
1373
1374 $this->setup_address();
1375
1376 return (bool) $row_affected;
1377 }
1378
1379 /**
1380 * Update donor address
1381 *
1382 * @since 2.0
1383 * @access public
1384 * @global wpdb $wpdb
1385 *
1386 * @param string $address_id
1387 * @param array $address
1388 *
1389 * @return bool
1390 */
1391 public function update_address( $address_id, $address ) {
1392 global $wpdb;
1393
1394 // Get address type.
1395 $is_multi_address = false !== strpos( $address_id, '_' ) ? true : false;
1396
1397 $address_type = false !== strpos( $address_id, '_' ) ?
1398 array_shift( explode( '_', $address_id ) ) :
1399 $address_id;
1400
1401 $address_count = false !== strpos( $address_id, '_' ) ?
1402 array_pop( explode( '_', $address_id ) ) :
1403 null;
1404
1405 // Set meta key prefix.
1406 $meta_key_prefix = "_give_donor_address_{$address_type}_%";
1407 if ( $is_multi_address && is_numeric( $address_count ) ) {
1408 $meta_key_prefix .= "_{$address_count}";
1409 }
1410
1411 $meta_type = Give()->donor_meta->meta_type;
1412
1413 // Process query.
1414 $row_affected = $wpdb->get_results(
1415 $wpdb->prepare(
1416 "
1417 SELECT meta_key FROM {$wpdb->donormeta}
1418 WHERE meta_key
1419 LIKE '%s'
1420 AND {$meta_type}_id=%d
1421 ",
1422 $meta_key_prefix,
1423 $this->id
1424 )
1425 );
1426
1427 // Return result.
1428 if( ! count( $row_affected ) ) {
1429 return false;
1430 }
1431
1432 // Update address.
1433 if( ! $this->add_address( $address_id, $address ) ) {
1434 return false;
1435 }
1436
1437 return true;
1438 }
1439
1440
1441 /**
1442 * Check if donor already has current address
1443 *
1444 * @since 2.0
1445 * @access public
1446 *
1447 * @param string $current_address_type
1448 * @param array $current_address
1449 *
1450 * @return bool|null
1451 */
1452 public function is_address_exist( $current_address_type, $current_address ) {
1453 $status = false;
1454
1455 // Bailout.
1456 if( empty( $current_address_type ) || empty( $current_address ) ) {
1457 return null;
1458 }
1459
1460 // Bailout.
1461 if( empty( $this->address ) || empty( $this->address[ $current_address_type ] ) ) {
1462 return $status;
1463 }
1464
1465 // Get address.
1466 $address = $this->address[ $current_address_type ];
1467
1468 switch ( true ){
1469
1470 // Single address.
1471 case is_string( end( $address ) ) :
1472 $status = $this->is_address_match( $current_address, $address );
1473 break;
1474
1475 // Multi address.
1476 case is_array( end( $address ) ):
1477 // Compare address.
1478 foreach ( $address as $saved_address ) {
1479 if( empty( $saved_address ) ) {
1480 continue;
1481 }
1482
1483 // Exit loop immediately if address exist.
1484 if( $status = $this->is_address_match( $current_address, $saved_address ) ) {
1485 break;
1486 }
1487 }
1488 break;
1489 }
1490
1491 return $status;
1492 }
1493
1494 /**
1495 * Compare address.
1496 *
1497 * @since 2.0
1498 * @access private
1499 *
1500 * @param array $address_1
1501 * @param array $address_2
1502 *
1503 * @return bool
1504 */
1505 private function is_address_match( $address_1, $address_2 ) {
1506 $result = array_diff( $address_1, $address_2 );
1507
1508 return empty( $result );
1509 }
1510
1511 /**
1512 * Split donor name into first name and last name
1513 *
1514 * @param int $id Donor ID
1515 * @since 2.0
1516 * @return object
1517 */
1518 public function split_donor_name( $id ) {
1519 $first_name = $last_name = '';
1520 $donor = new Give_Donor( $id );
1521
1522 $split_donor_name = explode( ' ', $donor->name, 2 );
1523
1524 // Check for existence of first name after split of donor name.
1525 if( is_array( $split_donor_name ) && ! empty( $split_donor_name[0] ) ) {
1526 $first_name = $split_donor_name[0];
1527 }
1528
1529 // Check for existence of last name after split of donor name.
1530 if( is_array( $split_donor_name ) && ! empty( $split_donor_name[1] ) ) {
1531 $last_name = $split_donor_name[1];
1532 }
1533 return (object) array( 'first_name' => $first_name, 'last_name' => $last_name );
1534 }
1535
1536 /**
1537 * Retrieves first name of donor with backward compatibility
1538 *
1539 * @since 2.0
1540 * @return string
1541 */
1542 public function get_first_name() {
1543 $first_name = $this->get_meta( '_give_donor_first_name');
1544 if( ! $first_name ) {
1545 $first_name = $this->split_donor_name( $this->id )->first_name;
1546 }
1547
1548 return $first_name;
1549 }
1550
1551 /**
1552 * Retrieves last name of donor with backward compatibility
1553 *
1554 * @since 2.0
1555 * @return string
1556 */
1557 public function get_last_name() {
1558 $first_name = $this->get_meta( '_give_donor_first_name');
1559 $last_name = $this->get_meta( '_give_donor_last_name');
1560
1561 // This condition will prevent unnecessary splitting of donor name to fetch last name.
1562 if( ! $first_name && ! $last_name ) {
1563 $last_name = $this->split_donor_name( $this->id )->last_name;
1564 }
1565
1566 return ( $last_name ) ? $last_name : '';
1567 }
1568
1569 /**
1570 * Retrieves company name of donor
1571 *
1572 * @since 2.1.0
1573 *
1574 * @return string $company_name Donor Company Name
1575 */
1576 public function get_company_name() {
1577 $company_name = $this->get_meta( '_give_donor_company' );
1578
1579 return $company_name;
1580 }
1581 }
1582