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