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