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