PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.16.9
GiveWP – Donation Plugin and Fundraising Platform v4.16.9
4.16.9 4.16.8.1 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 All 255 releases
give / includes / database / class-give-db-donors.php

class-give-db-donors.php in GiveWP – Donation Plugin and Fundraising Platform 4.16.9, at includes/database/class-give-db-donors.php

668 lines 14.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Donors DB
4 *
5 * @package Give
6 * @subpackage Classes/Give_DB_Donors
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_DB_Donors Class
19 *
20 * This class is for interacting with the donor database table.
21 *
22 * @since 1.0
23 */
24 class Give_DB_Donors extends Give_DB {
25
26 /**
27 * Give_DB_Donors constructor.
28 *
29 * Set up the Give DB Donor class.
30 *
31 * @since 1.0
32 * @access public
33 */
34 public function __construct() {
35 /* @var WPDB $wpdb */
36 global $wpdb;
37
38 $wpdb->donors = $this->table_name = "{$wpdb->prefix}give_donors";
39 $this->primary_key = 'id';
40 $this->version = '1.0';
41
42 $this->bc_200_params();
43
44 parent::__construct();
45 }
46
47 /**
48 * Get columns and formats
49 *
50 * @since 1.0
51 * @access public
52 *
53 * @return array Columns and formats.
54 */
55 public function get_columns() {
56 return array(
57 'id' => '%d',
58 'user_id' => '%d',
59 'name' => '%s',
60 'email' => '%s',
61 'payment_ids' => '%s',
62 'purchase_value' => '%f',
63 'purchase_count' => '%d',
64 'date_created' => '%s',
65 'token' => '%s',
66 'verify_key' => '%s',
67 'verify_throttle' => '%s',
68 );
69 }
70
71 /**
72 * Get default column values
73 *
74 * @since 1.0
75 * @access public
76 *
77 * @return array Default column values.
78 */
79 public function get_column_defaults() {
80 return array(
81 'user_id' => 0,
82 'email' => '',
83 'name' => '',
84 'payment_ids' => '',
85 'purchase_value' => 0.00,
86 'purchase_count' => 0,
87 'date_created' => date( 'Y-m-d H:i:s' ),
88 'token' => '',
89 'verify_key' => '',
90 'verify_throttle' => '',
91 );
92 }
93
94 /**
95 * Add a donor
96 *
97 * @param array $data List of donor data to add.
98 *
99 * @since 1.0
100 * @access public
101 *
102 * @return int|bool
103 */
104 public function add( $data = array() ) {
105
106 $defaults = array(
107 'payment_ids' => '',
108 );
109
110 $args = wp_parse_args( $data, $defaults );
111
112 if ( empty( $args['email'] ) ) {
113 return false;
114 }
115
116 if ( ! empty( $args['payment_ids'] ) && is_array( $args['payment_ids'] ) ) {
117 $args['payment_ids'] = implode( ',', array_unique( array_values( $args['payment_ids'] ) ) );
118 }
119
120 $donor = $this->get_donor_by( 'email', $args['email'] );
121
122 // update an existing donor.
123 if ( $donor ) {
124
125 // Update the payment IDs attached to the donor
126 if ( ! empty( $args['payment_ids'] ) ) {
127
128 if ( empty( $donor->payment_ids ) ) {
129
130 $donor->payment_ids = $args['payment_ids'];
131
132 } else {
133
134 $existing_ids = array_map( 'absint', explode( ',', $donor->payment_ids ) );
135 $payment_ids = array_map( 'absint', explode( ',', $args['payment_ids'] ) );
136 $payment_ids = array_merge( $payment_ids, $existing_ids );
137 $donor->payment_ids = implode( ',', array_unique( array_values( $payment_ids ) ) );
138
139 }
140
141 $args['payment_ids'] = $donor->payment_ids;
142
143 }
144
145 $this->update( $donor->id, $args );
146
147 return $donor->id;
148
149 } else {
150
151 return $this->insert( $args, 'donor' );
152
153 }
154
155 }
156
157
158 /**
159 * Update a donor.
160 *
161 * @param int $row_id
162 * @param array $data
163 * @param string $where
164 *
165 * @return bool
166 */
167 public function update( $row_id, $data = array(), $where = '' ) {
168
169 $status = parent::update( $row_id, $data, $where );
170
171 if ( $status ) {
172 Give_Cache::delete_group( $row_id, 'give-donors' );
173 }
174
175 return $status;
176 }
177
178 /**
179 * Insert a donor.
180 *
181 * @param array $data
182 * @param string $type
183 *
184 * @return int
185 */
186 public function insert( $data, $type = '' ) {
187 $donor_id = parent::insert( $data, $type );
188
189 if ( $donor_id ) {
190 Give_Cache::delete_group( $donor_id, 'give-donors' );
191 }
192
193 return $donor_id;
194 }
195
196 /**
197 * Delete a donor.
198 *
199 * NOTE: This should not be called directly as it does not make necessary changes to
200 * the payment meta and logs. Use give_donor_delete() instead.
201 *
202 * @param bool|string|int $_id_or_email ID or Email of Donor.
203 *
204 * @since 1.0
205 * @access public
206 *
207 * @return bool|int
208 */
209 public function delete( $_id_or_email = false ) {
210
211 if ( empty( $_id_or_email ) ) {
212 return false;
213 }
214
215 $column = is_email( $_id_or_email ) ? 'email' : 'id';
216 $donor = $this->get_donor_by( $column, $_id_or_email );
217
218 if ( $donor->id > 0 ) {
219
220 global $wpdb;
221
222 /**
223 * Deleting the donor meta.
224 *
225 * @since 1.8.14
226 */
227 Give()->donor_meta->delete_all_meta( $donor->id );
228
229 // Cache already deleted in delete_all_meta fn.
230
231 return $wpdb->delete( $this->table_name, array( 'id' => $donor->id ), array( '%d' ) );
232
233 } else {
234 return false;
235 }
236
237 }
238
239 /**
240 * Delete a donor by user ID.
241 *
242 * NOTE: This should not be called directly as it does not make necessary changes to
243 * the payment meta and logs. Use give_donor_delete() instead.
244 *
245 * @since 1.0
246 * @access public
247 *
248 * @param int|bool $user_id
249 *
250 * @return bool|int
251 */
252 public function delete_by_user_id( $user_id = false ) {
253 global $wpdb;
254
255 if ( empty( $user_id ) ) {
256 return false;
257 }
258
259 /**
260 * Deleting the donor meta.
261 *
262 * @since 1.8.14
263 */
264 $donor = new Give_Donor( $user_id, true );
265 if ( ! empty( $donor->id ) ) {
266 Give()->donor_meta->delete_all_meta( $donor->id );
267 }
268
269 // Cache is already deleted in delete_all_meta fn.
270
271 return $wpdb->delete( $this->table_name, array( 'user_id' => $user_id ), array( '%d' ) );
272 }
273
274 /**
275 * Checks if a donor exists
276 *
277 * @param string $value The value to search for. Default is empty.
278 * @param string $field The Donor ID or email to search in. Default is 'email'.
279 *
280 * @since 1.0
281 * @access public
282 *
283 * @return bool True is exists, false otherwise.
284 */
285 public function exists( $value = '', $field = 'email' ) {
286
287 $columns = $this->get_columns();
288 if ( ! array_key_exists( $field, $columns ) ) {
289 return false;
290 }
291
292 return (bool) $this->get_column_by( 'id', $field, $value );
293
294 }
295
296 /**
297 * Attaches a payment ID to a donor
298 *
299 * @since 1.0
300 * @access public
301 *
302 * @param int $donor_id Donor ID.
303 * @param int $payment_id Payment ID.
304 *
305 * @return bool
306 */
307 public function attach_payment( $donor_id = 0, $payment_id = 0 ) {
308
309 $donor = new Give_Donor( $donor_id );
310
311 if ( empty( $donor->id ) ) {
312 return false;
313 }
314
315 // Attach the payment, but don't increment stats, as this function previously did not
316 return $donor->attach_payment( $payment_id, false );
317
318 }
319
320 /**
321 * Removes a payment ID from a donor.
322 *
323 * @since 1.0
324 * @access public
325 *
326 * @param int $donor_id Donor ID.
327 * @param int $payment_id Payment ID.
328 *
329 * @return bool
330 */
331 public function remove_payment( $donor_id = 0, $payment_id = 0 ) {
332
333 $donor = new Give_Donor( $donor_id );
334
335 if ( ! $donor ) {
336 return false;
337 }
338
339 // Remove the payment, but don't decrease stats, as this function previously did not
340 return $donor->remove_payment( $payment_id, false );
341
342 }
343
344 /**
345 * Increments donor's donation stats.
346 *
347 * @access public
348 *
349 * @param int $donor_id Donor ID.
350 * @param float $amount THe amount to increase.
351 *
352 * @return bool
353 */
354 public function increment_stats( $donor_id = 0, $amount = 0.00 ) {
355
356 $donor = new Give_Donor( $donor_id );
357
358 if ( empty( $donor->id ) ) {
359 return false;
360 }
361
362 $increased_count = $donor->increase_purchase_count();
363 $increased_value = $donor->increase_value( $amount );
364
365 return ( $increased_count && $increased_value ) ? true : false;
366
367 }
368
369 /**
370 * Decrements donor's donation stats.
371 *
372 * @since 1.0
373 * @access public
374 *
375 * @param int $donor_id Donor ID.
376 * @param float $amount Amount.
377 *
378 * @return bool
379 */
380 public function decrement_stats( $donor_id = 0, $amount = 0.00 ) {
381
382 $donor = new Give_Donor( $donor_id );
383
384 if ( ! $donor ) {
385 return false;
386 }
387
388 $decreased_count = $donor->decrease_donation_count();
389 $decreased_value = $donor->decrease_value( $amount );
390
391 return ( $decreased_count && $decreased_value ) ? true : false;
392
393 }
394
395 /**
396 * Retrieves a single donor from the database
397 *
398 * @since 4.16.8.1 Reject an email lookup value that sanitize_text_field() would rewrite, instead of matching against the rewritten form.
399 * @since 1.0
400 * @access public
401 *
402 * @param string $field ID or email. Default is 'id'.
403 * @param mixed $value The Customer ID or email to search. Default is 0.
404 *
405 * @return mixed Upon success, an object of the donor. Upon failure, NULL
406 */
407 public function get_donor_by( $field = 'id', $value = 0 ) {
408 $submitted_value = is_string( $value ) ? trim( $value ) : $value;
409 $value = sanitize_text_field( $value );
410
411 // Bailout.
412 if ( empty( $field ) || empty( $value ) ) {
413 return null;
414 }
415
416 // Verify values.
417 if ( 'id' === $field || 'user_id' === $field ) {
418 // Make sure the value is numeric to avoid casting objects, for example,
419 // to int 1.
420 if ( ! is_numeric( $value ) ) {
421 return false;
422 }
423
424 $value = absint( $value );
425
426 if ( $value < 1 ) {
427 return false;
428 }
429 } elseif ( 'email' === $field ) {
430
431 if ( ! is_email( $value ) ) {
432 return false;
433 }
434
435 // The column this looks up is unique on its raw, stored bytes. Matching
436 // against a form that sanitize_text_field() rewrote (e.g. by removing
437 // percent-hex sequences) would compare a different string than what is
438 // actually stored, letting one row's raw value resolve to another row's
439 // plain value. Require the two to already agree.
440 if ( $value !== $submitted_value ) {
441 return false;
442 }
443
444 $value = trim( $value );
445 }
446
447 // Bailout
448 if ( ! $value ) {
449 return false;
450 }
451
452 // Set query params.
453 switch ( $field ) {
454 case 'id':
455 $args['donor'] = $value;
456 break;
457 case 'email':
458 $args['email'] = $value;
459 break;
460 case 'user_id':
461 $args['user'] = $value;
462 break;
463 default:
464 return false;
465 }
466
467 // Get donors.
468 $donor = new Give_Donors_Query( $args );
469
470 if ( ! $donor = $donor->get_donors() ) {
471 // Look for donor from an additional email.
472 $args = array(
473 'meta_query' => array(
474 array(
475 'key' => 'additional_email',
476 'value' => $value,
477 ),
478 ),
479 );
480
481 $donor = new Give_Donors_Query( $args );
482 $donor = $donor->get_donors();
483
484 if ( empty( $donor ) ) {
485 return false;
486 }
487 }
488
489 $donor = current( $donor );
490
491 isset( $donor->id ) && Give_Donors_Query::update_meta_cache( array( $donor->id ) );
492
493 return $donor;
494 }
495
496 /**
497 * This function will return donor details by token id.
498 *
499 * Note: This function is for internal purposes only. Don't use this function as it will be deprecated soon.
500 *
501 * @param int $id Email Access Token ID.
502 * @since 4.16.6 Require a non-empty, scalar string token before querying.
503 * @since 2.3.1
504 *
505 * @return object
506 */
507 public function get_donor_by_token( $id ) {
508 // Require a non-empty, scalar string token: every donor row defaults to
509 // verify_key = '' until they request their own access link.
510 if ( ! is_string( $id ) || '' === $id ) {
511 return null;
512 }
513
514 global $wpdb;
515 $row = $wpdb->get_row(
516 $wpdb->prepare( "SELECT * FROM {$wpdb->donors} WHERE verify_key = %s LIMIT 1", $id )
517 );
518 return $row;
519 }
520
521 /**
522 * Retrieve donors from the database.
523 *
524 * @since 1.0
525 * @access public
526 *
527 * @param array $args
528 *
529 * @return array|object|null Donors array or object. Null if not found.
530 */
531 public function get_donors( $args = array() ) {
532 $this->bc_1814_params( $args );
533
534 $donors = new Give_Donors_Query( $args );
535
536 return $donors->get_donors();
537
538 }
539
540
541 /**
542 * Count the total number of donors in the database
543 *
544 * @since 1.0
545 * @access public
546 *
547 * @param array $args
548 *
549 * @return int Total number of donors.
550 */
551 public function count( $args = array() ) {
552 $this->bc_1814_params( $args );
553 $args['count'] = true;
554
555 $cache_key = md5( 'give_donors_count' . serialize( $args ) );
556 $count = Give_Cache::get_group( $cache_key, 'donors' );
557
558 if ( is_null( $count ) ) {
559 $donors = new Give_Donors_Query( $args );
560 $count = $donors->get_donors();
561
562 Give_Cache::set_group( $cache_key, $count, 'donors', 3600 );
563 }
564
565 return absint( $count );
566
567 }
568
569 /**
570 * Create the table
571 *
572 * @since 1.0
573 * @access public
574 *
575 * @return void
576 */
577 public function create_table() {
578
579 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
580
581 $sql = "CREATE TABLE {$this->table_name} (
582 id bigint(20) NOT NULL AUTO_INCREMENT,
583 user_id bigint(20) NOT NULL,
584 email varchar(255) NOT NULL,
585 name mediumtext NOT NULL,
586 purchase_value mediumtext NOT NULL,
587 purchase_count bigint(20) NOT NULL,
588 payment_ids longtext NOT NULL,
589 date_created datetime NOT NULL,
590 token VARCHAR(255) CHARACTER SET utf8 NOT NULL,
591 verify_key VARCHAR(255) CHARACTER SET utf8 NOT NULL,
592 verify_throttle DATETIME NOT NULL,
593 PRIMARY KEY (id),
594 UNIQUE KEY email (email),
595 KEY user (user_id)
596 ) CHARACTER SET utf8 COLLATE utf8_general_ci;";
597
598 dbDelta( $sql );
599
600 update_option( $this->table_name . '_db_version', $this->version, false );
601 }
602
603 /**
604 * Add backward compatibility for old table name
605 *
606 * @since 2.0
607 * @access private
608 * @global wpdb $wpdb
609 */
610 private function bc_200_params() {
611 /* @var wpdb $wpdb */
612 global $wpdb;
613
614 if (
615 ! give_has_upgrade_completed( 'v20_rename_donor_tables' ) &&
616 $wpdb->query( $wpdb->prepare( 'SHOW TABLES LIKE %s', "{$wpdb->prefix}give_customers" ) )
617 ) {
618 $wpdb->donors = $this->table_name = "{$wpdb->prefix}give_customers";
619 }
620 }
621
622 /**
623 * Add backward compatibility for deprecated param
624 *
625 * @since 1.8.14
626 * @access private
627 *
628 * @param $args
629 */
630 private function bc_1814_params( &$args ) {
631 // Backward compatibility: user_id
632 if ( ! empty( $args['user_id'] ) ) {
633 $args['user'] = $args['user_id'];
634 }
635
636 // Backward compatibility: id
637 if ( ! empty( $args['id'] ) ) {
638 $args['donor'] = $args['id'];
639 }
640
641 // Backward compatibility: name
642 if ( ! empty( $args['name'] ) ) {
643 $args['s'] = "name:{$args['name']}";
644 }
645
646 // Backward compatibility: date
647 // Donors created for a specific date or in a date range.
648 if ( ! empty( $args['date'] ) ) {
649
650 if ( is_array( $args['date'] ) ) {
651
652 if ( ! empty( $args['date']['start'] ) ) {
653 $args['date_query']['after'] = date( 'Y-m-d H:i:s', strtotime( $args['date']['start'] ) );
654 }
655
656 if ( ! empty( $args['date']['end'] ) ) {
657 $args['date_query']['before'] = date( 'Y-m-d H:i:s', strtotime( $args['date']['end'] ) );
658 }
659 } else {
660
661 $args['date_query']['year'] = date( 'Y', strtotime( $args['date'] ) );
662 $args['date_query']['month'] = date( 'm', strtotime( $args['date'] ) );
663 $args['date_query']['day'] = date( 'd', strtotime( $args['date'] ) );
664 }
665 }
666 }
667 }
668