PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.5.11
GiveWP – Donation Plugin and Fundraising Platform v2.5.11
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 6 years ago api 6 years ago database 6 years ago deprecated 6 years ago donors 6 years ago emails 6 years ago forms 6 years ago frontend 7 years ago gateways 6 years ago libraries 7 years ago payments 6 years ago actions.php 6 years ago ajax-functions.php 6 years ago class-give-async-process.php 7 years ago class-give-background-updater.php 6 years ago class-give-cache-setting.php 6 years ago class-give-cache.php 6 years ago class-give-cli-commands.php 6 years ago class-give-comment.php 7 years ago class-give-cron.php 6 years ago class-give-donate-form.php 6 years ago class-give-donor-wall-widget.php 6 years ago class-give-donor.php 6 years ago class-give-email-access.php 7 years ago class-give-license-handler.php 6 years ago class-give-logging.php 7 years ago class-give-readme-parser.php 7 years ago class-give-roles.php 6 years ago class-give-scripts.php 6 years ago class-give-session.php 6 years ago class-give-stats.php 7 years ago class-give-template-loader.php 8 years ago class-give-tooltips.php 7 years ago class-give-translation.php 8 years ago class-notices.php 6 years ago country-functions.php 6 years ago currencies-list.php 6 years ago currency-functions.php 7 years ago error-tracking.php 7 years ago filters.php 7 years ago formatting.php 6 years ago install.php 6 years ago login-register.php 7 years ago misc-functions.php 6 years ago plugin-compatibility.php 6 years ago post-types.php 6 years ago price-functions.php 7 years ago process-donation.php 6 years ago setting-functions.php 6 years ago shortcodes.php 6 years ago template-functions.php 6 years ago user-functions.php 6 years ago
class-give-donor.php
1722 lines
1 <?php
2 /**
3 * Donor
4 *
5 * @package Give
6 * @subpackage Classes/Give_Donor
7 * @copyright Copyright (c) 2016, GiveWP
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 protected $notes = null;
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 ( false === $_id_or_email || ( is_numeric( $_id_or_email ) && (int) $_id_or_email !== absint( $_id_or_email ) ) ) {
157 return false;
158 }
159
160 $by_user_id = is_bool( $by_user_id ) ? $by_user_id : false;
161
162 if ( is_numeric( $_id_or_email ) ) {
163 $field = $by_user_id ? 'user_id' : 'id';
164 } else {
165 $field = 'email';
166 }
167
168 $donor = $this->db->get_donor_by( $field, $_id_or_email );
169
170 if ( empty( $donor ) || ! is_object( $donor ) ) {
171 return false;
172 }
173
174 $this->setup_donor( $donor );
175
176 }
177
178 /**
179 * Setup Donor
180 *
181 * Set donor variables.
182 *
183 * @since 1.0
184 * @access private
185 *
186 * @param object $donor The Donor Object.
187 *
188 * @return bool If the setup was successful or not.
189 */
190 private function setup_donor( $donor ) {
191
192 if ( ! is_object( $donor ) ) {
193 return false;
194 }
195
196 // Get cached donors.
197 $donor_vars = Give_Cache::get_group( $donor->id, 'give-donors' );
198
199 if ( is_null( $donor_vars ) ) {
200 foreach ( $donor as $key => $value ) {
201
202 switch ( $key ) {
203
204 // @todo We will remove this statement when we will remove notes column from donor table
205 // https://github.com/impress-org/give/issues/3632
206 case 'notes':
207 break;
208
209 default:
210 $this->$key = $value;
211 break;
212
213 }
214 }
215
216 // Get donor's all email including primary email.
217 $this->emails = (array) $this->get_meta( 'additional_email', false );
218 $this->emails = array( 'primary' => $this->email ) + $this->emails;
219
220 $this->setup_address();
221
222 Give_Cache::set_group( $donor->id, get_object_vars( $this ), 'give-donors' );
223 } else {
224 foreach ( $donor_vars as $donor_var => $value ) {
225 $this->$donor_var = $value;
226 }
227 }
228
229 // Donor ID and email are the only things that are necessary, make sure they exist.
230 if ( ! empty( $this->id ) && ! empty( $this->email ) ) {
231 return true;
232 }
233
234 return false;
235
236 }
237
238
239 /**
240 * Setup donor address.
241 *
242 * @since 2.0
243 * @access public
244 */
245 public function setup_address() {
246 global $wpdb;
247 $meta_type = Give()->donor_meta->meta_type;
248
249 $addresses = $this->get_addresses_from_meta_cache();
250
251 $addresses = ! empty( $addresses )
252 ? $addresses
253 : $wpdb->get_results( $wpdb->prepare( "
254 SELECT meta_key, meta_value FROM {$wpdb->donormeta}
255 WHERE meta_key
256 LIKE '%%%s%%'
257 AND {$meta_type}_id=%d
258 ", 'give_donor_address', $this->id ), ARRAY_N );
259
260 if ( empty( $addresses ) ) {
261 return $this->address;
262 }
263
264 foreach ( $addresses as $address ) {
265 $address[0] = str_replace( '_give_donor_address_', '', $address[0] );
266 $address[0] = explode( '_', $address[0] );
267
268 if ( 3 === count( $address[0] ) ) {
269 $this->address[ $address[0][0] ][ $address[0][2] ][ $address[0][1] ] = $address[1];
270 } else {
271 $this->address[ $address[0][0] ][ $address[0][1] ] = $address[1];
272 }
273 }
274 }
275
276
277 /**
278 * Get addresses from meta cache
279 *
280 * @since 2.5.0
281 * @return array
282 */
283 private function get_addresses_from_meta_cache() {
284 $meta = wp_cache_get( $this->id, 'donor_meta' );
285 $addresses = array();
286
287 if ( ! empty( $meta ) ) {
288 foreach ( $meta as $meta_key => $meta_value ) {
289 if ( false === strpos( $meta_key, 'give_donor_address' ) ) {
290 continue;
291 }
292
293 $addresses[] = array( $meta_key, current( $meta_value ) );
294 }
295 }
296
297 return $addresses;
298 }
299
300 /**
301 * Returns the saved address for a donor
302 *
303 * @access public
304 *
305 * @since 2.1.3
306 *
307 * @param array $args donor address.
308 *
309 * @return array The donor's address, if any
310 */
311 public function get_donor_address( $args = array() ) {
312 $args = wp_parse_args(
313 $args,
314 array(
315 'address_type' => 'billing',
316 )
317 );
318
319 $default_address = array(
320 'line1' => '',
321 'line2' => '',
322 'city' => '',
323 'state' => '',
324 'country' => '',
325 'zip' => '',
326 );
327
328 // Backward compatibility.
329 if ( ! give_has_upgrade_completed( 'v20_upgrades_user_address' ) ) {
330
331 // Backward compatibility for user id param.
332 return wp_parse_args( (array) get_user_meta( $this->user_id, '_give_user_address', true ), $default_address );
333
334 }
335
336 if ( ! $this->id || empty( $this->address ) || ! array_key_exists( $args['address_type'], $this->address ) ) {
337 return $default_address;
338 }
339
340 switch ( true ) {
341 case is_string( end( $this->address[ $args['address_type'] ] ) ):
342 $address = wp_parse_args( $this->address[ $args['address_type'] ], $default_address );
343 break;
344
345 case is_array( end( $this->address[ $args['address_type'] ] ) ):
346 $address = wp_parse_args( array_shift( $this->address[ $args['address_type'] ] ), $default_address );
347 break;
348 }
349
350 return $address;
351 }
352
353 /**
354 * Magic __get function to dispatch a call to retrieve a private property.
355 *
356 * @since 1.0
357 * @access public
358 *
359 * @param $key
360 *
361 * @return mixed|\WP_Error
362 */
363 public function __get( $key ) {
364
365 if ( method_exists( $this, 'get_' . $key ) ) {
366
367 return call_user_func( array( $this, 'get_' . $key ) );
368
369 } else {
370
371 /* translators: %s: property key */
372 return new WP_Error( 'give-donor-invalid-property', sprintf( esc_html__( 'Can\'t get property %s.', 'give' ), $key ) );
373
374 }
375
376 }
377
378 /**
379 * Creates a donor.
380 *
381 * @since 1.0
382 * @access public
383 *
384 * @param array $data Array of attributes for a donor.
385 *
386 * @return bool|int False if not a valid creation, donor ID if user is found or valid creation.
387 */
388 public function create( $data = array() ) {
389
390 if ( $this->id != 0 || empty( $data ) ) {
391 return false;
392 }
393
394 $defaults = array(
395 'payment_ids' => '',
396 );
397
398 $args = wp_parse_args( $data, $defaults );
399 $args = $this->sanitize_columns( $args );
400
401 if ( empty( $args['email'] ) || ! is_email( $args['email'] ) ) {
402 return false;
403 }
404
405 if ( ! empty( $args['payment_ids'] ) && is_array( $args['payment_ids'] ) ) {
406 $args['payment_ids'] = implode( ',', array_unique( array_values( $args['payment_ids'] ) ) );
407 }
408
409 /**
410 * Fires before creating donors.
411 *
412 * @since 1.0
413 *
414 * @param array $args Donor attributes.
415 */
416 do_action( 'give_donor_pre_create', $args );
417
418 $created = false;
419
420 // The DB class 'add' implies an update if the donor being asked to be created already exists
421 if ( $this->db->add( $data ) ) {
422
423 // We've successfully added/updated the donor, reset the class vars with the new data
424 $donor = $this->db->get_donor_by( 'email', $args['email'] );
425
426 // Setup the donor data with the values from DB
427 $this->setup_donor( $donor );
428
429 $created = $this->id;
430 }
431
432 /**
433 * Fires after creating donors.
434 *
435 * @since 1.0
436 *
437 * @param bool|int $created False if not a valid creation, donor ID if user is found or valid creation.
438 * @param array $args Customer attributes.
439 */
440 do_action( 'give_donor_post_create', $created, $args );
441
442 return $created;
443
444 }
445
446 /**
447 * Updates a donor record.
448 *
449 * @since 1.0
450 * @access public
451 *
452 * @param array $data Array of data attributes for a donor (checked via whitelist).
453 *
454 * @return bool If the update was successful or not.
455 */
456 public function update( $data = array() ) {
457
458 if ( empty( $data ) ) {
459 return false;
460 }
461
462 $data = $this->sanitize_columns( $data );
463
464 /**
465 * Fires before updating donors.
466 *
467 * @since 1.0
468 *
469 * @param int $donor_id Donor id.
470 * @param array $data Donor attributes.
471 */
472 do_action( 'give_donor_pre_update', $this->id, $data );
473
474 $updated = false;
475
476 if ( $this->db->update( $this->id, $data ) ) {
477
478 $donor = $this->db->get_donor_by( 'id', $this->id );
479
480 $this->setup_donor( $donor );
481
482 $updated = true;
483 }
484
485 /**
486 * Fires after updating donors.
487 *
488 * @since 1.0
489 *
490 * @param bool $updated If the update was successful or not.
491 * @param int $donor_id Donor id.
492 * @param array $data Donor attributes.
493 */
494 do_action( 'give_donor_post_update', $updated, $this->id, $data );
495
496 return $updated;
497 }
498
499 /**
500 * Attach Payment
501 *
502 * Attach payment to the donor then triggers increasing stats.
503 *
504 * @since 1.0
505 * @access public
506 *
507 * @param int $payment_id The payment ID to attach to the donor.
508 * @param bool $update_stats For backwards compatibility, if we should increase the stats or not.
509 *
510 * @return bool If the attachment was successfully.
511 */
512 public function attach_payment( $payment_id = 0, $update_stats = true ) {
513
514 if ( empty( $payment_id ) ) {
515 return false;
516 }
517
518 if ( empty( $this->payment_ids ) ) {
519
520 $new_payment_ids = $payment_id;
521
522 } else {
523
524 $payment_ids = array_map( 'absint', explode( ',', $this->payment_ids ) );
525
526 if ( in_array( $payment_id, $payment_ids ) ) {
527 $update_stats = false;
528 }
529
530 $payment_ids[] = $payment_id;
531
532 $new_payment_ids = implode( ',', array_unique( array_values( $payment_ids ) ) );
533
534 }
535
536 /**
537 * Fires before attaching payments to donors.
538 *
539 * @since 1.0
540 *
541 * @param int $payment_id Payment id.
542 * @param int $donor_id Donor id.
543 */
544 do_action( 'give_donor_pre_attach_payment', $payment_id, $this->id );
545
546 $payment_added = $this->update( array( 'payment_ids' => $new_payment_ids ) );
547
548 if ( $payment_added ) {
549
550 $this->payment_ids = $new_payment_ids;
551
552 // We added this payment successfully, increment the stats
553 if ( $update_stats ) {
554 $payment_amount = give_donation_amount( $payment_id, array( 'type' => 'stats' ) );
555
556 if ( ! empty( $payment_amount ) ) {
557 $this->increase_value( $payment_amount );
558 }
559
560 $this->increase_purchase_count();
561 }
562 }
563
564 /**
565 * Fires after attaching payments to the donor.
566 *
567 * @since 1.0
568 *
569 * @param bool $payment_added If the attachment was successfully.
570 * @param int $payment_id Payment id.
571 * @param int $donor_id Donor id.
572 */
573 do_action( 'give_donor_post_attach_payment', $payment_added, $payment_id, $this->id );
574
575 return $payment_added;
576 }
577
578 /**
579 * Remove Payment
580 *
581 * Remove a payment from this donor, then triggers reducing stats.
582 *
583 * @since 1.0
584 * @access public
585 *
586 * @param int $payment_id The Payment ID to remove.
587 * @param bool $update_stats For backwards compatibility, if we should increase the stats or not.
588 *
589 * @return boolean If the removal was successful.
590 */
591 public function remove_payment( $payment_id = 0, $update_stats = true ) {
592
593 if ( empty( $payment_id ) ) {
594 return false;
595 }
596
597 $payment = new Give_Payment( $payment_id );
598
599 if ( 'publish' !== $payment->status && 'revoked' !== $payment->status ) {
600 $update_stats = false;
601 }
602
603 $new_payment_ids = '';
604
605 if ( ! empty( $this->payment_ids ) ) {
606
607 $payment_ids = array_map( 'absint', explode( ',', $this->payment_ids ) );
608
609 $pos = array_search( $payment_id, $payment_ids );
610 if ( false === $pos ) {
611 return false;
612 }
613
614 unset( $payment_ids[ $pos ] );
615 $payment_ids = array_filter( $payment_ids );
616
617 $new_payment_ids = implode( ',', array_unique( array_values( $payment_ids ) ) );
618
619 }
620
621 /**
622 * Fires before removing payments from customers.
623 *
624 * @since 1.0
625 *
626 * @param int $payment_id Payment id.
627 * @param int $donor_id Customer id.
628 */
629 do_action( 'give_donor_pre_remove_payment', $payment_id, $this->id );
630
631 $payment_removed = $this->update( array( 'payment_ids' => $new_payment_ids ) );
632
633 if ( $payment_removed ) {
634
635 $this->payment_ids = $new_payment_ids;
636
637 if ( $update_stats ) {
638 // We removed this payment successfully, decrement the stats
639 $payment_amount = give_donation_amount( $payment_id );
640
641 if ( ! empty( $payment_amount ) ) {
642 $this->decrease_value( $payment_amount );
643 }
644
645 $this->decrease_donation_count();
646 }
647 }
648
649 /**
650 * Fires after removing payments from donors.
651 *
652 * @since 1.0
653 *
654 * @param bool $payment_removed If the removal was successfully.
655 * @param int $payment_id Payment id.
656 * @param int $donor_id Donor id.
657 */
658 do_action( 'give_donor_post_remove_payment', $payment_removed, $payment_id, $this->id );
659
660 return $payment_removed;
661
662 }
663
664 /**
665 * Increase the donation count of a donor.
666 *
667 * @since 1.0
668 * @access public
669 *
670 * @param int $count The number to increase by.
671 *
672 * @return int The donation count.
673 */
674 public function increase_purchase_count( $count = 1 ) {
675
676 // Make sure it's numeric and not negative.
677 if ( ! is_numeric( $count ) || $count != absint( $count ) ) {
678 return false;
679 }
680
681 $new_total = (int) $this->purchase_count + (int) $count;
682
683 /**
684 * Fires before increasing the donor's donation count.
685 *
686 * @since 1.0
687 *
688 * @param int $count The number to increase by.
689 * @param int $donor_id Donor id.
690 */
691 do_action( 'give_donor_pre_increase_donation_count', $count, $this->id );
692
693 if ( $this->update( array( 'purchase_count' => $new_total ) ) ) {
694 $this->purchase_count = $new_total;
695 }
696
697 /**
698 * Fires after increasing the donor's donation count.
699 *
700 * @since 1.0
701 *
702 * @param int $purchase_count Donor donation count.
703 * @param int $count The number increased by.
704 * @param int $donor_id Donor id.
705 */
706 do_action( 'give_donor_post_increase_donation_count', $this->purchase_count, $count, $this->id );
707
708 return $this->purchase_count;
709 }
710
711 /**
712 * Decrease the donor donation count.
713 *
714 * @since 1.0
715 * @access public
716 *
717 * @param int $count The amount to decrease by.
718 *
719 * @return mixed If successful, the new count, otherwise false.
720 */
721 public function decrease_donation_count( $count = 1 ) {
722
723 // Make sure it's numeric and not negative
724 if ( ! is_numeric( $count ) || $count != absint( $count ) ) {
725 return false;
726 }
727
728 $new_total = (int) $this->purchase_count - (int) $count;
729
730 if ( $new_total < 0 ) {
731 $new_total = 0;
732 }
733
734 /**
735 * Fires before decreasing the donor's donation count.
736 *
737 * @since 1.0
738 *
739 * @param int $count The number to decrease by.
740 * @param int $donor_id Customer id.
741 */
742 do_action( 'give_donor_pre_decrease_donation_count', $count, $this->id );
743
744 if ( $this->update( array( 'purchase_count' => $new_total ) ) ) {
745 $this->purchase_count = $new_total;
746 }
747
748 /**
749 * Fires after decreasing the donor's donation count.
750 *
751 * @since 1.0
752 *
753 * @param int $purchase_count Donor's donation count.
754 * @param int $count The number decreased by.
755 * @param int $donor_id Donor id.
756 */
757 do_action( 'give_donor_post_decrease_donation_count', $this->purchase_count, $count, $this->id );
758
759 return $this->purchase_count;
760 }
761
762 /**
763 * Increase the donor's lifetime value.
764 *
765 * @since 1.0
766 * @access public
767 *
768 * @param float $value The value to increase by.
769 *
770 * @return mixed If successful, the new value, otherwise false.
771 */
772 public function increase_value( $value = 0.00 ) {
773
774 $new_value = floatval( $this->purchase_value ) + $value;
775
776 /**
777 * Fires before increasing donor lifetime value.
778 *
779 * @since 1.0
780 *
781 * @param float $value The value to increase by.
782 * @param int $donor_id Customer id.
783 */
784 do_action( 'give_donor_pre_increase_value', $value, $this->id );
785
786 if ( $this->update( array( 'purchase_value' => $new_value ) ) ) {
787 $this->purchase_value = $new_value;
788 }
789
790 /**
791 * Fires after increasing donor lifetime value.
792 *
793 * @since 1.0
794 *
795 * @param float $purchase_value Donor's lifetime value.
796 * @param float $value The value increased by.
797 * @param int $donor_id Donor id.
798 */
799 do_action( 'give_donor_post_increase_value', $this->purchase_value, $value, $this->id );
800
801 return $this->purchase_value;
802 }
803
804 /**
805 * Decrease a donor's lifetime value.
806 *
807 * @since 1.0
808 * @access public
809 *
810 * @param float $value The value to decrease by.
811 *
812 * @return mixed If successful, the new value, otherwise false.
813 */
814 public function decrease_value( $value = 0.00 ) {
815
816 $new_value = floatval( $this->purchase_value ) - $value;
817
818 if ( $new_value < 0 ) {
819 $new_value = 0.00;
820 }
821
822 /**
823 * Fires before decreasing donor lifetime value.
824 *
825 * @since 1.0
826 *
827 * @param float $value The value to decrease by.
828 * @param int $donor_id Donor id.
829 */
830 do_action( 'give_donor_pre_decrease_value', $value, $this->id );
831
832 if ( $this->update( array( 'purchase_value' => $new_value ) ) ) {
833 $this->purchase_value = $new_value;
834 }
835
836 /**
837 * Fires after decreasing donor lifetime value.
838 *
839 * @since 1.0
840 *
841 * @param float $purchase_value Donor lifetime value.
842 * @param float $value The value decreased by.
843 * @param int $donor_id Donor id.
844 */
845 do_action( 'give_donor_post_decrease_value', $this->purchase_value, $value, $this->id );
846
847 return $this->purchase_value;
848 }
849
850 /**
851 * Decrease/Increase a donor's lifetime value.
852 *
853 * This function will update donation stat on basis of current amount and new amount donation difference.
854 * Difference value can positive or negative. Negative value will decrease user donation stat while positive value
855 * increase donation stat.
856 *
857 * @since 1.0
858 * @access public
859 *
860 * @param float $curr_amount Current Donation amount.
861 * @param float $new_amount New (changed) Donation amount.
862 *
863 * @return mixed If successful, the new donation stat value, otherwise false.
864 */
865 public function update_donation_value( $curr_amount, $new_amount ) {
866 /**
867 * Payment total difference value can be:
868 * zero (in case amount not change)
869 * or -ve (in case amount decrease)
870 * or +ve (in case amount increase)
871 */
872 $payment_total_diff = $new_amount - $curr_amount;
873
874 // We do not need to update donation stat if donation did not change.
875 if ( ! $payment_total_diff ) {
876 return false;
877 }
878
879 if ( $payment_total_diff > 0 ) {
880 $this->increase_value( $payment_total_diff );
881 } else {
882 // Pass payment total difference as +ve value to decrease amount from user lifetime stat.
883 $this->decrease_value( - $payment_total_diff );
884 }
885
886 return $this->purchase_value;
887 }
888
889 /**
890 * Get the parsed notes for a donor as an array.
891 *
892 * @since 1.0
893 * @access public
894 *
895 * @param int $length The number of notes to get.
896 * @param int $paged What note to start at.
897 *
898 * @return array The notes requested.
899 */
900 public function get_notes( $length = 20, $paged = 1 ) {
901
902 $length = is_numeric( $length ) ? $length : 20;
903 $offset = is_numeric( $paged ) && $paged != 1 ? ( ( absint( $paged ) - 1 ) * $length ) : 0;
904
905 $all_notes = $this->get_raw_notes();
906 $notes_array = array_reverse( array_filter( explode( "\n\n", $all_notes ) ) );
907
908 $desired_notes = array_slice( $notes_array, $offset, $length );
909
910 return $desired_notes;
911
912 }
913
914 /**
915 * Get the total number of notes we have after parsing.
916 *
917 * @since 1.0
918 * @access public
919 *
920 * @return int The number of notes for the donor.
921 */
922 public function get_notes_count() {
923
924 $all_notes = $this->get_raw_notes();
925 $notes_array = array_reverse( array_filter( explode( "\n\n", $all_notes ) ) );
926
927 return count( $notes_array );
928
929 }
930
931 /**
932 * Get the total donation amount.
933 *
934 * @since 1.8.17
935 *
936 * @param array $args Pass any additional data.
937 *
938 * @return string|float
939 */
940 public function get_total_donation_amount( $args = array() ) {
941
942 /**
943 * Filter total donation amount.
944 *
945 * @since 1.8.17
946 *
947 * @param string|float $purchase_value Donor Purchase value.
948 * @param integer $donor_id Donor ID.
949 * @param array $args Pass additional data.
950 */
951 return apply_filters( 'give_get_total_donation_amount', $this->purchase_value, $this->id, $args );
952 }
953
954 /**
955 * Add a note for the donor.
956 *
957 * @since 1.0
958 * @access public
959 *
960 * @param string $note The note to add. Default is empty.
961 *
962 * @return string|boolean The new note if added successfully, false otherwise.
963 */
964 public function add_note( $note = '' ) {
965
966 $note = trim( $note );
967 if ( empty( $note ) ) {
968 return false;
969 }
970
971 $notes = $this->get_raw_notes();
972
973 if ( empty( $notes ) ) {
974 $notes = '';
975 }
976
977 // Backward compatibility.
978 $note_string = date_i18n( 'F j, Y H:i:s', current_time( 'timestamp' ) ) . ' - ' . $note;
979 $formatted_new_note = apply_filters( 'give_customer_add_note_string', $note_string );
980 $notes .= "\n\n" . $formatted_new_note;
981
982 /**
983 * Fires before donor note is added.
984 *
985 * @since 1.0
986 *
987 * @param string $formatted_new_note Formatted new note to add.
988 * @param int $donor_id Donor id.
989 */
990 do_action( 'give_donor_pre_add_note', $formatted_new_note, $this->id );
991
992 if ( ! give_has_upgrade_completed( 'v230_move_donor_note' ) ) {
993 // Backward compatibility.
994 $updated = $this->update( array( 'notes' => $notes ) );
995 } else {
996 $updated = Give()->comment->db->add(
997 array(
998 'comment_content' => $note,
999 'user_id' => get_current_user_id(),
1000 'comment_parent' => $this->id,
1001 'comment_type' => 'donor',
1002 )
1003 );
1004 }
1005
1006 if ( $updated ) {
1007 $this->notes = $this->get_notes();
1008 }
1009
1010 /**
1011 * Fires after donor note added.
1012 *
1013 * @since 1.0
1014 *
1015 * @param array $donor_notes Donor notes.
1016 * @param string $formatted_new_note Formatted new note added.
1017 * @param int $donor_id Donor id.
1018 */
1019 do_action( 'give_donor_post_add_note', $this->notes, $formatted_new_note, $this->id );
1020
1021 // Return the formatted note, so we can test, as well as update any displays
1022 return $formatted_new_note;
1023 }
1024
1025 /**
1026 * Get the notes column for the donor
1027 *
1028 * @since 1.0
1029 * @access private
1030 *
1031 * @return string The Notes for the donor, non-parsed.
1032 */
1033 private function get_raw_notes() {
1034 $all_notes = '';
1035 $comments = Give()->comment->db->get_results_by( array( 'comment_parent' => $this->id ) );
1036
1037 // Generate notes output as we are doing before 2.3.0.
1038 if( ! empty( $comments ) ) {
1039 /* @var stdClass $comment */
1040 foreach ( $comments as $comment ) {
1041 $all_notes .= date_i18n( 'F j, Y H:i:s', strtotime( $comment->comment_date ) ) . " - {$comment->comment_content}\n\n";
1042 }
1043 }
1044
1045 // Backward compatibility.
1046 if( ! give_has_upgrade_completed('v230_move_donor_note') ) {
1047 $all_notes = $this->db->get_column( 'notes', $this->id );
1048 }
1049
1050 return $all_notes;
1051
1052 }
1053
1054 /**
1055 * Retrieve a meta field for a donor.
1056 *
1057 * @since 1.6
1058 * @access public
1059 *
1060 * @param string $meta_key The meta key to retrieve. Default is empty.
1061 * @param bool $single Whether to return a single value. Default is true.
1062 *
1063 * @return mixed Will be an array if $single is false. Will be value of meta data field if $single is
1064 * true.
1065 */
1066 public function get_meta( $meta_key = '', $single = true ) {
1067 return Give()->donor_meta->get_meta( $this->id, $meta_key, $single );
1068 }
1069
1070 /**
1071 * Add a meta data field to a donor.
1072 *
1073 * @since 1.6
1074 * @access public
1075 *
1076 * @param string $meta_key Metadata name. Default is empty.
1077 * @param mixed $meta_value Metadata value.
1078 * @param bool $unique Optional. Whether the same key should not be added. Default is false.
1079 *
1080 * @return bool False for failure. True for success.
1081 */
1082 public function add_meta( $meta_key = '', $meta_value, $unique = false ) {
1083 return Give()->donor_meta->add_meta( $this->id, $meta_key, $meta_value, $unique );
1084 }
1085
1086 /**
1087 * Update a meta field based on donor ID.
1088 *
1089 * @since 1.6
1090 * @access public
1091 *
1092 * @param string $meta_key Metadata key. Default is empty.
1093 * @param mixed $meta_value Metadata value.
1094 * @param mixed $prev_value Optional. Previous value to check before removing. Default is empty.
1095 *
1096 * @return bool False on failure, true if success.
1097 */
1098 public function update_meta( $meta_key = '', $meta_value, $prev_value = '' ) {
1099 return Give()->donor_meta->update_meta( $this->id, $meta_key, $meta_value, $prev_value );
1100 }
1101
1102 /**
1103 * Remove metadata matching criteria from a donor.
1104 *
1105 * @since 1.6
1106 * @access public
1107 *
1108 * @param string $meta_key Metadata name. Default is empty.
1109 * @param mixed $meta_value Optional. Metadata value. Default is empty.
1110 *
1111 * @return bool False for failure. True for success.
1112 */
1113 public function delete_meta( $meta_key = '', $meta_value = '' ) {
1114 return Give()->donor_meta->delete_meta( $this->id, $meta_key, $meta_value );
1115 }
1116
1117 /**
1118 * Sanitize the data for update/create
1119 *
1120 * @since 1.0
1121 * @access private
1122 *
1123 * @param array $data The data to sanitize.
1124 *
1125 * @return array The sanitized data, based off column defaults.
1126 */
1127 private function sanitize_columns( $data ) {
1128
1129 $columns = $this->db->get_columns();
1130 $default_values = $this->db->get_column_defaults();
1131
1132 foreach ( $columns as $key => $type ) {
1133
1134 // Only sanitize data that we were provided
1135 if ( ! array_key_exists( $key, $data ) ) {
1136 continue;
1137 }
1138
1139 switch ( $type ) {
1140
1141 case '%s':
1142 if ( 'email' == $key ) {
1143 $data[ $key ] = sanitize_email( $data[ $key ] );
1144 } elseif ( 'notes' == $key ) {
1145 $data[ $key ] = strip_tags( $data[ $key ] );
1146 } else {
1147 $data[ $key ] = sanitize_text_field( $data[ $key ] );
1148 }
1149 break;
1150
1151 case '%d':
1152 if ( ! is_numeric( $data[ $key ] ) || (int) $data[ $key ] !== absint( $data[ $key ] ) ) {
1153 $data[ $key ] = $default_values[ $key ];
1154 } else {
1155 $data[ $key ] = absint( $data[ $key ] );
1156 }
1157 break;
1158
1159 case '%f':
1160 // Convert what was given to a float
1161 $value = floatval( $data[ $key ] );
1162
1163 if ( ! is_float( $value ) ) {
1164 $data[ $key ] = $default_values[ $key ];
1165 } else {
1166 $data[ $key ] = $value;
1167 }
1168 break;
1169
1170 default:
1171 $data[ $key ] = sanitize_text_field( $data[ $key ] );
1172 break;
1173
1174 }
1175 }
1176
1177 return $data;
1178 }
1179
1180 /**
1181 * Attach an email to the donor
1182 *
1183 * @since 1.7
1184 * @access public
1185 *
1186 * @param string $email The email address to attach to the donor
1187 * @param bool $primary Allows setting the email added as the primary
1188 *
1189 * @return bool If the email was added successfully
1190 */
1191 public function add_email( $email = '', $primary = false ) {
1192 if ( ! is_email( $email ) ) {
1193 return false;
1194 }
1195 $existing = new Give_Donor( $email );
1196
1197 if ( $existing->id > 0 ) {
1198 // Email address already belongs to another donor
1199 return false;
1200 }
1201
1202 if ( email_exists( $email ) ) {
1203 $user = get_user_by( 'email', $email );
1204 if ( $user->ID != $this->user_id ) {
1205 return false;
1206 }
1207 }
1208
1209 do_action( 'give_donor_pre_add_email', $email, $this->id, $this );
1210
1211 // Add is used to ensure duplicate emails are not added
1212 $ret = (bool) $this->add_meta( 'additional_email', $email );
1213
1214 do_action( 'give_donor_post_add_email', $email, $this->id, $this );
1215
1216 if ( $ret && true === $primary ) {
1217 $this->set_primary_email( $email );
1218 }
1219
1220 return $ret;
1221 }
1222
1223 /**
1224 * Remove an email from the donor.
1225 *
1226 * @since 1.7
1227 * @access public
1228 *
1229 * @param string $email The email address to remove from the donor.
1230 *
1231 * @return bool If the email was removed successfully.
1232 */
1233 public function remove_email( $email = '' ) {
1234 if ( ! is_email( $email ) ) {
1235 return false;
1236 }
1237
1238 do_action( 'give_donor_pre_remove_email', $email, $this->id, $this );
1239
1240 $ret = (bool) $this->delete_meta( 'additional_email', $email );
1241
1242 do_action( 'give_donor_post_remove_email', $email, $this->id, $this );
1243
1244 return $ret;
1245 }
1246
1247 /**
1248 * Set an email address as the donor's primary email.
1249 *
1250 * This will move the donor's previous primary email to an additional email.
1251 *
1252 * @since 1.7
1253 * @access public
1254 *
1255 * @param string $new_primary_email The email address to remove from the donor.
1256 *
1257 * @return bool If the email was set as primary successfully.
1258 */
1259 public function set_primary_email( $new_primary_email = '' ) {
1260 if ( ! is_email( $new_primary_email ) ) {
1261 return false;
1262 }
1263
1264 do_action( 'give_donor_pre_set_primary_email', $new_primary_email, $this->id, $this );
1265
1266 $existing = new Give_Donor( $new_primary_email );
1267
1268 if ( $existing->id > 0 && (int) $existing->id !== (int) $this->id ) {
1269 // This email belongs to another donor.
1270 return false;
1271 }
1272
1273 $old_email = $this->email;
1274
1275 // Update donor record with new email.
1276 $update = $this->update( array( 'email' => $new_primary_email ) );
1277
1278 // Remove new primary from list of additional emails.
1279 $remove = $this->remove_email( $new_primary_email );
1280
1281 // Add old email to additional emails list.
1282 $add = $this->add_email( $old_email );
1283
1284 $ret = $update && $remove && $add;
1285
1286 if ( $ret ) {
1287 $this->email = $new_primary_email;
1288 }
1289
1290 do_action( 'give_donor_post_set_primary_email', $new_primary_email, $this->id, $this );
1291
1292 return $ret;
1293 }
1294
1295 /**
1296 * Check if address valid or not.
1297 *
1298 * @since 2.0
1299 * @access private
1300 *
1301 * @param $address
1302 *
1303 * @return bool
1304 */
1305 private function is_valid_address( $address ) {
1306 $is_valid_address = true;
1307
1308 // Address ready to process even if only one value set.
1309 foreach ( $address as $address_type => $value ) {
1310 // @todo: Handle state field validation on basis of country.
1311 if ( in_array( $address_type, array( 'line2', 'state' ) ) ) {
1312 continue;
1313 }
1314
1315 if ( empty( $value ) ) {
1316 $is_valid_address = false;
1317 break;
1318 }
1319 }
1320
1321 return $is_valid_address;
1322 }
1323
1324 /**
1325 * Add donor address
1326 *
1327 * @since 2.0
1328 * @access public
1329 *
1330 * @param string $address_type
1331 * @param array $address {
1332 *
1333 * @type string $address2
1334 * @type string city
1335 * @type string zip
1336 * @type string state
1337 * @type string country
1338 * }
1339 *
1340 * @return bool
1341 */
1342 public function add_address( $address_type, $address ) {
1343 // Bailout.
1344 if ( empty( $address_type ) || ! $this->is_valid_address( $address ) || ! $this->id ) {
1345 return false;
1346 }
1347
1348 // Check if multiple address exist or not and set params.
1349 $multi_address_id = null;
1350 if ( $is_multi_address = ( false !== strpos( $address_type, '[]' ) ) ) {
1351 $address_type = $is_multi_address ? str_replace( '[]', '', $address_type ) : $address_type;
1352 } elseif ( $is_multi_address = ( false !== strpos( $address_type, '_' ) ) ) {
1353 $exploded_address_type = explode( '_', $address_type );
1354 $multi_address_id = $is_multi_address ? array_pop( $exploded_address_type ) : $address_type;
1355
1356 $address_type = $is_multi_address ? array_shift( $exploded_address_type ) : $address_type;
1357 }
1358
1359 // Bailout: do not save duplicate orders
1360 if ( $this->does_address_exist( $address_type, $address ) ) {
1361 return false;
1362 }
1363
1364 // Set default address.
1365 $address = wp_parse_args( $address, array(
1366 'line1' => '',
1367 'line2' => '',
1368 'city' => '',
1369 'state' => '',
1370 'country' => '',
1371 'zip' => '',
1372 ) );
1373
1374 // Set meta key prefix.
1375 global $wpdb;
1376 $meta_key_prefix = "_give_donor_address_{$address_type}_{address_name}";
1377 $meta_type = Give()->donor_meta->meta_type;
1378
1379 if ( $is_multi_address ) {
1380 if ( is_null( $multi_address_id ) ) {
1381 // Get latest address key to set multi address id.
1382 $multi_address_id = $wpdb->get_var( $wpdb->prepare( "
1383 SELECT meta_key FROM {$wpdb->donormeta}
1384 WHERE meta_key
1385 LIKE '%%%s%%'
1386 AND {$meta_type}_id=%d
1387 ORDER BY meta_id DESC
1388 LIMIT 1
1389 ", "_give_donor_address_{$address_type}_line1", $this->id ) );
1390
1391 if ( ! empty( $multi_address_id ) ) {
1392 $multi_address_id = absint( substr( strrchr( $multi_address_id, '_' ), 1 ) );
1393 $multi_address_id ++;
1394 } else {
1395 $multi_address_id = 0;
1396 }
1397 }
1398
1399 $meta_key_prefix = "_give_donor_address_{$address_type}_{address_name}_{$multi_address_id}";
1400 }
1401
1402 // Save donor address.
1403 foreach ( $address as $type => $value ) {
1404 $meta_key = str_replace( '{address_name}', $type, $meta_key_prefix );
1405 Give()->donor_meta->update_meta( $this->id, $meta_key, $value );
1406 }
1407
1408 $this->setup_address();
1409
1410 return true;
1411 }
1412
1413 /**
1414 * Remove donor address
1415 *
1416 * @since 2.0
1417 * @access public
1418 * @global wpdb $wpdb
1419 *
1420 * @param string $address_id
1421 *
1422 * @return bool
1423 */
1424 public function remove_address( $address_id ) {
1425 global $wpdb;
1426
1427 // Get address type.
1428 $is_multi_address = false !== strpos( $address_id, '_' ) ? true : false;
1429
1430 $address_key_arr = explode( '_', $address_id );
1431
1432 $address_type = false !== strpos( $address_id, '_' ) ? array_shift( $address_key_arr ) : $address_id;
1433 $address_count = false !== strpos( $address_id, '_' ) ? array_pop( $address_key_arr ) : null;
1434
1435 // Set meta key prefix.
1436 $meta_key_prefix = "_give_donor_address_{$address_type}_%";
1437 if ( $is_multi_address && is_numeric( $address_count ) ) {
1438 $meta_key_prefix .= "_{$address_count}";
1439 }
1440
1441 $meta_type = Give()->donor_meta->meta_type;
1442
1443 // Process query.
1444 $row_affected = $wpdb->query( $wpdb->prepare( "
1445 DELETE FROM {$wpdb->donormeta}
1446 WHERE meta_key
1447 LIKE '%s'
1448 AND {$meta_type}_id=%d
1449 ", $meta_key_prefix, $this->id ) );
1450
1451 // Delete cache.
1452 Give_Cache::delete_group( $this->id, 'give-donors' );
1453 wp_cache_delete( $this->id, "{$meta_type}_meta" );
1454
1455 $this->setup_address();
1456
1457 return (bool) $row_affected;
1458 }
1459
1460 /**
1461 * Update donor address
1462 *
1463 * @since 2.0
1464 * @access public
1465 * @global wpdb $wpdb
1466 *
1467 * @param string $address_id
1468 * @param array $address
1469 *
1470 * @return bool
1471 */
1472 public function update_address( $address_id, $address ) {
1473 global $wpdb;
1474
1475 // Get address type.
1476 $is_multi_address = false !== strpos( $address_id, '_' ) ? true : false;
1477 $exploded_address_id = explode( '_', $address_id );
1478
1479 $address_type = false !== strpos( $address_id, '_' ) ? array_shift( $exploded_address_id ) : $address_id;
1480
1481 $address_count = false !== strpos( $address_id, '_' ) ? array_pop( $exploded_address_id ) : null;
1482
1483 // Set meta key prefix.
1484 $meta_key_prefix = "_give_donor_address_{$address_type}_%";
1485 if ( $is_multi_address && is_numeric( $address_count ) ) {
1486 $meta_key_prefix .= "_{$address_count}";
1487 }
1488
1489 $meta_type = Give()->donor_meta->meta_type;
1490
1491 // Process query.
1492 $row_affected = $wpdb->get_results( $wpdb->prepare( "
1493 SELECT meta_key FROM {$wpdb->donormeta}
1494 WHERE meta_key
1495 LIKE '%s'
1496 AND {$meta_type}_id=%d
1497 ", $meta_key_prefix, $this->id ) );
1498
1499 // Return result.
1500 if ( ! count( $row_affected ) ) {
1501 return false;
1502 }
1503
1504 // Update address.
1505 if ( ! $this->add_address( $address_id, $address ) ) {
1506 return false;
1507 }
1508
1509 return true;
1510 }
1511
1512
1513 /**
1514 * Check if donor already has current address
1515 *
1516 * @since 2.0
1517 * @access public
1518 *
1519 * @param string $current_address_type
1520 * @param array $current_address
1521 *
1522 * @return bool|null
1523 */
1524 public function does_address_exist( $current_address_type, $current_address ) {
1525 $status = false;
1526
1527 // Bailout.
1528 if ( empty( $current_address_type ) || empty( $current_address ) ) {
1529 return null;
1530 }
1531
1532 // Bailout.
1533 if ( empty( $this->address ) || empty( $this->address[ $current_address_type ] ) ) {
1534 return $status;
1535 }
1536
1537 // Get address.
1538 $address = $this->address[ $current_address_type ];
1539
1540 switch ( true ) {
1541
1542 // Single address.
1543 case is_string( end( $address ) ) :
1544 $status = $this->is_address_match( $current_address, $address );
1545 break;
1546
1547 // Multi address.
1548 case is_array( end( $address ) ):
1549 // Compare address.
1550 foreach ( $address as $saved_address ) {
1551 if ( empty( $saved_address ) ) {
1552 continue;
1553 }
1554
1555 // Exit loop immediately if address exist.
1556 if ( $status = $this->is_address_match( $current_address, $saved_address ) ) {
1557 break;
1558 }
1559 }
1560 break;
1561 }
1562
1563 return $status;
1564 }
1565
1566 /**
1567 * Compare address.
1568 *
1569 * @since 2.0
1570 * @access private
1571 *
1572 * @param array $address_1
1573 * @param array $address_2
1574 *
1575 * @return bool
1576 */
1577 private function is_address_match( $address_1, $address_2 ) {
1578 $result = array_diff_assoc( $address_1, $address_2 );
1579
1580 return empty( $result );
1581 }
1582
1583 /**
1584 * Split donor name into first name and last name
1585 *
1586 * @param int $id Donor ID
1587 *
1588 * @since 2.0
1589 * @return object
1590 */
1591 public function split_donor_name( $id ) {
1592 $first_name = $last_name = '';
1593 $donor = new Give_Donor( $id );
1594
1595 $split_donor_name = explode( ' ', $donor->name, 2 );
1596
1597 // Check for existence of first name after split of donor name.
1598 if ( is_array( $split_donor_name ) && ! empty( $split_donor_name[0] ) ) {
1599 $first_name = $split_donor_name[0];
1600 }
1601
1602 // Check for existence of last name after split of donor name.
1603 if ( is_array( $split_donor_name ) && ! empty( $split_donor_name[1] ) ) {
1604 $last_name = $split_donor_name[1];
1605 }
1606
1607 return (object) array( 'first_name' => $first_name, 'last_name' => $last_name );
1608 }
1609
1610 /**
1611 * Retrieves first name of donor with backward compatibility
1612 *
1613 * @since 2.0
1614 * @return string
1615 */
1616 public function get_first_name() {
1617 $first_name = $this->get_meta( '_give_donor_first_name' );
1618 if ( ! $first_name ) {
1619 $first_name = $this->split_donor_name( $this->id )->first_name;
1620 }
1621
1622 return $first_name;
1623 }
1624
1625 /**
1626 * Retrieves last name of donor with backward compatibility
1627 *
1628 * @since 2.0
1629 * @return string
1630 */
1631 public function get_last_name() {
1632 $first_name = $this->get_meta( '_give_donor_first_name' );
1633 $last_name = $this->get_meta( '_give_donor_last_name' );
1634
1635 // This condition will prevent unnecessary splitting of donor name to fetch last name.
1636 if ( ! $first_name && ! $last_name ) {
1637 $last_name = $this->split_donor_name( $this->id )->last_name;
1638 }
1639
1640 return ( $last_name ) ? $last_name : '';
1641 }
1642
1643 /**
1644 * Retrieves company name of donor
1645 *
1646 * @since 2.1
1647 *
1648 * @return string $company_name Donor Company Name
1649 */
1650 public function get_company_name() {
1651 $company_name = $this->get_meta( '_give_donor_company' );
1652
1653 return $company_name;
1654 }
1655
1656 /**
1657 * Retrieves last donation for the donor.
1658 *
1659 * @since 2.1
1660 *
1661 * @return string $company_name Donor Company Name
1662 */
1663 public function get_last_donation() {
1664
1665 $payments = array_unique( array_values( explode( ',', $this->payment_ids ) ) );
1666
1667 return end( $payments );
1668
1669 }
1670
1671 /**
1672 * Retrieves last donation for the donor.
1673 *
1674 * @since 2.1
1675 *
1676 * @param bool $formatted Whether to return with the date format or not.
1677 *
1678 * @return string The date of the last donation.
1679 */
1680 public function get_last_donation_date( $formatted = false ) {
1681 $completed_data = '';
1682
1683 // Return if donation id is invalid.
1684 if( ! ( $last_donation = absint( $this->get_last_donation() ) ) ) {
1685 return $completed_data;
1686 }
1687
1688 $completed_data = give_get_payment_completed_date( $last_donation );
1689
1690 if ( $formatted ) {
1691 return date_i18n( give_date_format(), strtotime( $completed_data ) );
1692 }
1693
1694 return $completed_data;
1695
1696 }
1697
1698 /**
1699 * Retrieves a donor's initials (first name and last name).
1700 *
1701 * @since 2.1
1702 *
1703 * @return string The donor's two initials (no middle).
1704 */
1705 public function get_donor_initals() {
1706 /**
1707 * Filter the donor name initials
1708 *
1709 * @since 2.1.0
1710 */
1711 return apply_filters(
1712 'get_donor_initals',
1713 give_get_name_initial( array(
1714 'firstname' => $this->get_first_name(),
1715 'lastname' => $this->get_last_name()
1716 ) )
1717 );
1718
1719 }
1720
1721 }
1722