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