Completed
Push — issues/1132 ( b0ddd9...34d612 )
by Ravinder
22:33 queued 02:37
created

functions.php ➔ give_delete_donation()   B

Complexity

Conditions 7
Paths 12

Size

Total Lines 66
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 23
nc 12
nop 2
dl 0
loc 66
rs 7.0832
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 46 and the first side effect is on line 14.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Payment Functions
4
 *
5
 * @package     Give
6
 * @subpackage  Payments
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
 * Get Payments
19
 *
20
 * Retrieve payments from the database.
21
 *
22
 * Since 1.0, this function takes an array of arguments, instead of individual
23
 * parameters. All of the original parameters remain, but can be passed in any
24
 * order via the array.
25
 *
26
 * @since 1.0
27
 *
28
 * @param array $args     {
29
 *                        Optional. Array of arguments passed to payments query.
30
 *
31
 * @type int    $offset   The number of payments to offset before retrieval.
32
 *                            Default is 0.
33
 * @type int    $number   The number of payments to query for. Use -1 to request all
34
 *                            payments. Default is 20.
35
 * @type string $mode     Default is 'live'.
36
 * @type string $order    Designates ascending or descending order of payments.
37
 *                            Accepts 'ASC', 'DESC'. Default is 'DESC'.
38
 * @type string $orderby  Sort retrieved payments by parameter. Default is 'ID'.
39
 * @type string $status   The status of the payments. Default is 'any'.
40
 * @type string $user     User. Default is null.
41
 * @type string $meta_key Custom field key. Default is null.
42
 * }
43
 *
44
 * @return array $payments Payments retrieved from the database
45
 */
46
function give_get_payments( $args = array() ) {
47
48
	// Fallback to post objects to ensure backwards compatibility.
49
	if ( ! isset( $args['output'] ) ) {
50
		$args['output'] = 'posts';
51
	}
52
53
	$args     = apply_filters( 'give_get_payments_args', $args );
54
	$payments = new Give_Payments_Query( $args );
55
56
	return $payments->get_payments();
57
}
58
59
/**
60
 * Retrieve payment by a given field
61
 *
62
 * @since  1.0
63
 *
64
 * @param  string $field The field to retrieve the payment with.
65
 * @param  mixed  $value The value for $field.
66
 *
67
 * @return mixed
68
 */
69
function give_get_payment_by( $field = '', $value = '' ) {
70
71
	if ( empty( $field ) || empty( $value ) ) {
72
		return false;
73
	}
74
75
	switch ( strtolower( $field ) ) {
76
77
		case 'id':
78
			$payment = new Give_Payment( $value );
79
			$id      = $payment->ID;
80
81
			if ( empty( $id ) ) {
82
				return false;
83
			}
84
85
			break;
86
87
		case 'key':
88
			$payment = give_get_payments( array(
89
				'meta_key'       => '_give_payment_purchase_key',
90
				'meta_value'     => $value,
91
				'posts_per_page' => 1,
92
				'fields'         => 'ids',
93
			) );
94
95
			if ( $payment ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $payment of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
96
				$payment = new Give_Payment( $payment[0] );
97
			}
98
99
			break;
100
101
		case 'payment_number':
102
			$payment = give_get_payments( array(
103
				'meta_key'       => '_give_payment_number',
104
				'meta_value'     => $value,
105
				'posts_per_page' => 1,
106
				'fields'         => 'ids',
107
			) );
108
109
			if ( $payment ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $payment of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
110
				$payment = new Give_Payment( $payment[0] );
111
			}
112
113
			break;
114
115
		default:
116
			return false;
117
	}
118
119
	if ( $payment ) {
120
		return $payment;
121
	}
122
123
	return false;
124
}
125
126
/**
127
 * Insert Payment
128
 *
129
 * @since  1.0
130
 *
131
 * @param  array $payment_data Arguments passed.
132
 *
133
 * @return int|bool Payment ID if payment is inserted, false otherwise.
134
 */
135
function give_insert_payment( $payment_data = array() ) {
136
137
	if ( empty( $payment_data ) ) {
138
		return false;
139
	}
140
141
	$payment    = new Give_Payment();
142
	$gateway    = ! empty( $payment_data['gateway'] ) ? $payment_data['gateway'] : '';
143
	$gateway    = empty( $gateway ) && isset( $_POST['give-gateway'] ) ? $_POST['give-gateway'] : $gateway;
144
	$form_id    = isset( $payment_data['give_form_id'] ) ? $payment_data['give_form_id'] : 0;
145
	$price_id   = give_get_payment_meta_price_id( $payment_data );
146
	$form_title = isset( $payment_data['give_form_title'] ) ? $payment_data['give_form_title'] : get_the_title( $form_id );
147
148
	// Set properties.
149
	$payment->total          = $payment_data['price'];
150
	$payment->status         = ! empty( $payment_data['status'] ) ? $payment_data['status'] : 'pending';
151
	$payment->currency       = ! empty( $payment_data['currency'] ) ? $payment_data['currency'] : give_get_currency();
152
	$payment->user_info      = $payment_data['user_info'];
153
	$payment->gateway        = $gateway;
154
	$payment->form_title     = $form_title;
155
	$payment->form_id        = $form_id;
156
	$payment->price_id       = $price_id;
157
	$payment->user_id        = $payment_data['user_info']['id'];
158
	$payment->email          = $payment_data['user_email'];
159
	$payment->first_name     = $payment_data['user_info']['first_name'];
160
	$payment->last_name      = $payment_data['user_info']['last_name'];
161
	$payment->email          = $payment_data['user_info']['email'];
162
	$payment->ip             = give_get_ip();
163
	$payment->key            = $payment_data['purchase_key'];
164
	$payment->mode           = give_is_test_mode() ? 'test' : 'live';
165
	$payment->parent_payment = ! empty( $payment_data['parent'] ) ? absint( $payment_data['parent'] ) : '';
166
167
	// Add the donation.
168
	$args = array(
169
		'price'    => $payment->total,
170
		'price_id' => $payment->price_id,
171
	);
172
173
	$payment->add_donation( $payment->form_id, $args );
174
175
	// Set date if present.
176
	if ( isset( $payment_data['post_date'] ) ) {
177
		$payment->date = $payment_data['post_date'];
178
	}
179
180
	// Handle sequential payments.
181
	if ( give_get_option( 'enable_sequential' ) ) {
182
		$number          = give_get_next_payment_number();
183
		$payment->number = give_format_payment_number( $number );
184
		update_option( 'give_last_payment_number', $number );
185
	}
186
187
	// Clear the user's donation cache.
188
	delete_transient( 'give_user_' . $payment_data['user_info']['id'] . '_purchases' );
189
190
	// Save payment.
191
	$payment->save();
192
193
	/**
194
	 * Fires while inserting payments.
195
	 *
196
	 * @since 1.0
197
	 *
198
	 * @param int   $payment_id   The payment ID.
199
	 * @param array $payment_data Arguments passed.
200
	 */
201
	do_action( 'give_insert_payment', $payment->ID, $payment_data );
202
203
	// Return payment ID upon success.
204
	if ( ! empty( $payment->ID ) ) {
205
		return $payment->ID;
206
	}
207
208
	// Return false if no payment was inserted.
209
	return false;
210
211
}
212
213
/**
214
 * Create payment.
215
 *
216
 * @param $payment_data
217
 *
218
 * @return bool|int
219
 */
220
function give_create_payment( $payment_data ) {
221
222
	$form_id  = intval( $payment_data['post_data']['give-form-id'] );
223
	$price_id = isset( $payment_data['post_data']['give-price-id'] ) ? $payment_data['post_data']['give-price-id'] : '';
224
225
	// Collect payment data.
226
	$insert_payment_data = array(
227
		'price'           => $payment_data['price'],
228
		'give_form_title' => $payment_data['post_data']['give-form-title'],
229
		'give_form_id'    => $form_id,
230
		'give_price_id'   => $price_id,
231
		'date'            => $payment_data['date'],
232
		'user_email'      => $payment_data['user_email'],
233
		'purchase_key'    => $payment_data['purchase_key'],
234
		'currency'        => give_get_currency(),
235
		'user_info'       => $payment_data['user_info'],
236
		'status'          => 'pending',
237
		'gateway'         => 'paypal',
238
	);
239
240
	/**
241
	 * Filter the payment params.
242
	 *
243
	 * @since 1.8
244
	 *
245
	 * @param array $insert_payment_data
246
	 */
247
	$insert_payment_data = apply_filters( 'give_create_payment', $insert_payment_data );
248
249
	// Record the pending payment.
250
	return give_insert_payment( $insert_payment_data );
251
}
252
253
/**
254
 * Updates a payment status.
255
 *
256
 * @since  1.0
257
 *
258
 * @param  int    $payment_id Payment ID.
259
 * @param  string $new_status New Payment Status. Default is 'publish'.
260
 *
261
 * @return bool
262
 */
263
function give_update_payment_status( $payment_id, $new_status = 'publish' ) {
264
265
	$payment         = new Give_Payment( $payment_id );
266
	$payment->status = $new_status;
267
	$updated         = $payment->save();
268
269
	return $updated;
270
}
271
272
273
/**
274
 * Deletes a Donation
275
 *
276
 * @since  1.0
277
 *
278
 * @param  int  $payment_id   Payment ID (default: 0).
279
 * @param  bool $update_donor If we should update the donor stats (default:true).
280
 *
281
 * @return void
282
 */
283
function give_delete_donation( $payment_id = 0, $update_donor = true ) {
284
	$payment     = new Give_Payment( $payment_id );
285
	$amount      = give_get_payment_amount( $payment_id );
286
	$status      = $payment->post_status;
287
288
	$donor_id = give_get_payment_donor_id( $payment_id );
289
	$donor    = new Give_Donor( $donor_id );
290
291
	// Only undo donations that aren't these statuses.
292
	$dont_undo_statuses = apply_filters( 'give_undo_donation_statuses', array(
293
		'pending',
294
		'cancelled',
295
	) );
296
297
	if ( ! in_array( $status, $dont_undo_statuses ) ) {
298
		give_undo_donation( $payment_id );
299
	}
300
301
	if ( $status == 'publish' ) {
302
303
		// Only decrease earnings if they haven't already been decreased (or were never increased for this payment).
304
		give_decrease_total_earnings( $amount );
305
306
		// @todo: Refresh only range related stat cache
307
		give_delete_donation_stats();
308
309
		if ( $donor->id && $update_donor ) {
310
311
			// Decrement the stats for the donor.
312
			$donor->decrease_donation_count();
313
			$donor->decrease_value( $amount );
314
315
		}
316
	}
317
318
	/**
319
	 * Fires before deleting payment.
320
	 *
321
	 * @since 1.0
322
	 *
323
	 * @param int $payment_id Payment ID.
324
	 */
325
	do_action( 'give_payment_delete', $payment_id );
326
327
	if ( $donor->id && $update_donor ) {
328
329
		// Remove the payment ID from the donor.
330
		$donor->remove_payment( $payment_id );
331
332
	}
333
334
	// Remove the payment.
335
	wp_delete_post( $payment_id, true );
336
337
	// Remove related sale log entries.
338
	Give()->logs->delete_logs( $payment_id );
339
340
	/**
341
	 * Fires after payment deleted.
342
	 *
343
	 * @since 1.0
344
	 *
345
	 * @param int $payment_id Payment ID.
346
	 */
347
	do_action( 'give_payment_deleted', $payment_id );
348
}
349
350
/**
351
 * Undo Donation
352
 *
353
 * Undoes a donation, including the decrease of donations and earning stats.
354
 * Used for when refunding or deleting a donation.
355
 *
356
 * @since  1.0
357
 *
358
 * @param  int $payment_id Payment ID.
359
 *
360
 * @return void
361
 */
362
function give_undo_donation( $payment_id ) {
363
364
	$payment = new Give_Payment( $payment_id );
365
366
	$maybe_decrease_earnings = apply_filters( 'give_decrease_earnings_on_undo', true, $payment, $payment->form_id );
367
	if ( true === $maybe_decrease_earnings ) {
368
		// Decrease earnings.
369
		give_decrease_earnings( $payment->form_id, $payment->total );
370
	}
371
372
	$maybe_decrease_donations = apply_filters( 'give_decrease_donations_on_undo', true, $payment, $payment->form_id );
373
	if ( true === $maybe_decrease_donations ) {
374
		// Decrease donation count.
375
		give_decrease_donation_count( $payment->form_id );
376
	}
377
378
}
379
380
381
/**
382
 * Count Payments
383
 *
384
 * Returns the total number of payments recorded.
385
 *
386
 * @since  1.0
387
 *
388
 * @param  array $args Arguments passed.
389
 *
390
 * @return object $stats Contains the number of payments per payment status.
391
 */
392
function give_count_payments( $args = array() ) {
393
394
	global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
395
396
	$defaults = array(
397
		'user'       => null,
398
		's'          => null,
399
		'start-date' => null,
400
		'end-date'   => null,
401
		'form_id'    => null,
402
	);
403
404
	$args = wp_parse_args( $args, $defaults );
405
406
	$select = 'SELECT p.post_status,count( * ) AS num_posts';
407
	$join   = '';
408
	$where  = "WHERE p.post_type = 'give_payment'";
409
410
	// Count payments for a specific user.
411
	if ( ! empty( $args['user'] ) ) {
412
413
		if ( is_email( $args['user'] ) ) {
414
			$field = 'email';
415
		} elseif ( is_numeric( $args['user'] ) ) {
416
			$field = 'id';
417
		} else {
418
			$field = '';
419
		}
420
421
		$join = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
422
423
		if ( ! empty( $field ) ) {
424
			$where .= "
425
				AND m.meta_key = '_give_payment_user_{$field}'
426
				AND m.meta_value = '{$args['user']}'";
427
		}
428
429
430
	} elseif ( ! empty( $args['donor'] ) ) {
431
432
		$join  = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
433
		$where .= "
434
			AND m.meta_key = '_give_payment_customer_id'
435
			AND m.meta_value = '{$args['donor']}'";
436
437
		// Count payments for a search.
438
	} elseif ( ! empty( $args['s'] ) ) {
439
440
		if ( is_email( $args['s'] ) || strlen( $args['s'] ) == 32 ) {
441
442
			if ( is_email( $args['s'] ) ) {
443
				$field = '_give_payment_user_email';
444
			} else {
445
				$field = '_give_payment_purchase_key';
446
			}
447
448
			$join  = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
449
			$where .= $wpdb->prepare( '
450
                AND m.meta_key = %s
451
                AND m.meta_value = %s', $field, $args['s'] );
452
453
		} elseif ( '#' == substr( $args['s'], 0, 1 ) ) {
454
455
			$search = str_replace( '#:', '', $args['s'] );
456
			$search = str_replace( '#', '', $search );
457
458
			$select = 'SELECT p.post_status,count( * ) AS num_posts ';
459
			$join   = '';
460
			$where  = $wpdb->prepare( 'WHERE p.post_type=%s  AND p.ID = %d ', 'give_payment', $search );
461
462
463
		} elseif ( is_numeric( $args['s'] ) ) {
464
465
			$join  = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
466
			$where .= $wpdb->prepare( "
467
				AND m.meta_key = '_give_payment_user_id'
468
				AND m.meta_value = %d", $args['s'] );
469
470
		} else {
471
			$search = $wpdb->esc_like( $args['s'] );
472
			$search = '%' . $search . '%';
473
474
			$where .= $wpdb->prepare( 'AND ((p.post_title LIKE %s) OR (p.post_content LIKE %s))', $search, $search );
475
		}
476
	}
477
478
	if ( ! empty( $args['form_id'] ) && is_numeric( $args['form_id'] ) ) {
479
		$where .= $wpdb->prepare( ' AND p.post_parent = %d', $args['form_id'] );
480
	}
481
482
	// Limit payments count by date.
483
	if ( ! empty( $args['start-date'] ) && false !== strpos( $args['start-date'], '/' ) ) {
484
485
		$date_parts = explode( '/', $args['start-date'] );
486
		$month      = ! empty( $date_parts[0] ) && is_numeric( $date_parts[0] ) ? $date_parts[0] : 0;
487
		$day        = ! empty( $date_parts[1] ) && is_numeric( $date_parts[1] ) ? $date_parts[1] : 0;
488
		$year       = ! empty( $date_parts[2] ) && is_numeric( $date_parts[2] ) ? $date_parts[2] : 0;
489
490
		$is_date = checkdate( $month, $day, $year );
491
		if ( false !== $is_date ) {
492
493
			$date  = new DateTime( $args['start-date'] );
494
			$where .= $wpdb->prepare( " AND p.post_date >= '%s'", $date->format( 'Y-m-d' ) );
495
496
		}
497
498
		// Fixes an issue with the payments list table counts when no end date is specified (with stats class).
499
		if ( empty( $args['end-date'] ) ) {
500
			$args['end-date'] = $args['start-date'];
501
		}
502
	}
503
504
	if ( ! empty( $args['end-date'] ) && false !== strpos( $args['end-date'], '/' ) ) {
505
506
		$date_parts = explode( '/', $args['end-date'] );
507
508
		$month = ! empty( $date_parts[0] ) ? $date_parts[0] : 0;
509
		$day   = ! empty( $date_parts[1] ) ? $date_parts[1] : 0;
510
		$year  = ! empty( $date_parts[2] ) ? $date_parts[2] : 0;
511
512
		$is_date = checkdate( $month, $day, $year );
513
		if ( false !== $is_date ) {
514
515
			$date  = new DateTime( $args['end-date'] );
516
			$where .= $wpdb->prepare( " AND p.post_date <= '%s'", $date->format( 'Y-m-d' ) );
517
518
		}
519
	}
520
521
	$where = apply_filters( 'give_count_payments_where', $where );
522
	$join  = apply_filters( 'give_count_payments_join', $join );
523
524
	$query = "$select
525
		FROM $wpdb->posts p
526
		$join
527
		$where
528
		GROUP BY p.post_status
529
	";
530
531
	$cache_key = md5( $query );
532
533
	$count = wp_cache_get( $cache_key, 'counts' );
534
	if ( false !== $count ) {
535
		return $count;
536
	}
537
538
	$count = $wpdb->get_results( $query, ARRAY_A );
539
540
	$stats    = array();
541
	$statuses = get_post_stati();
542
	if ( isset( $statuses['private'] ) && empty( $args['s'] ) ) {
543
		unset( $statuses['private'] );
544
	}
545
546
	foreach ( $statuses as $state ) {
547
		$stats[ $state ] = 0;
548
	}
549
550
	foreach ( (array) $count as $row ) {
551
552
		if ( 'private' == $row['post_status'] && empty( $args['s'] ) ) {
553
			continue;
554
		}
555
556
		$stats[ $row['post_status'] ] = $row['num_posts'];
557
	}
558
559
	$stats = (object) $stats;
560
	wp_cache_set( $cache_key, $stats, 'counts' );
561
562
	return $stats;
563
}
564
565
566
/**
567
 * Check For Existing Payment
568
 *
569
 * @since  1.0
570
 *
571
 * @param  int $payment_id Payment ID
572
 *
573
 * @return bool $exists True if payment exists, false otherwise.
574
 */
575
function give_check_for_existing_payment( $payment_id ) {
576
	$exists  = false;
577
	$payment = new Give_Payment( $payment_id );
578
579
	if ( $payment_id === $payment->ID && 'publish' === $payment->status ) {
580
		$exists = true;
581
	}
582
583
	return $exists;
584
}
585
586
/**
587
 * Get Payment Status
588
 *
589
 * @since 1.0
590
 *
591
 * @param WP_Post|Give_Payment $payment      Payment object.
592
 * @param bool                 $return_label Whether to return the translated status label
593
 *                                           instead of status value. Default false.
594
 *
595
 * @return bool|mixed True if payment status exists, false otherwise.
596
 */
597
function give_get_payment_status( $payment, $return_label = false ) {
598
599
	if ( ! is_object( $payment ) || ! isset( $payment->post_status ) ) {
600
		return false;
601
	}
602
603
	$statuses = give_get_payment_statuses();
604
605
	if ( ! is_array( $statuses ) || empty( $statuses ) ) {
606
		return false;
607
	}
608
609
	// Get payment object if no already given.
610
	$payment = $payment instanceof Give_Payment ? $payment : new Give_Payment( $payment->ID );
611
612
	if ( array_key_exists( $payment->status, $statuses ) ) {
613
		if ( true === $return_label ) {
614
			// Return translated status label.
615
			return $statuses[ $payment->status ];
616
		} else {
617
			// Account that our 'publish' status is labeled 'Complete'
618
			$post_status = 'publish' == $payment->status ? 'Complete' : $payment->post_status;
619
620
			// Make sure we're matching cases, since they matter
621
			return array_search( strtolower( $post_status ), array_map( 'strtolower', $statuses ) );
622
		}
623
	}
624
625
	return false;
626
}
627
628
/**
629
 * Retrieves all available statuses for payments.
630
 *
631
 * @since  1.0
632
 *
633
 * @return array $payment_status All the available payment statuses.
634
 */
635
function give_get_payment_statuses() {
636
	$payment_statuses = array(
637
		'pending'     => __( 'Pending', 'give' ),
638
		'publish'     => __( 'Complete', 'give' ),
639
		'refunded'    => __( 'Refunded', 'give' ),
640
		'failed'      => __( 'Failed', 'give' ),
641
		'cancelled'   => __( 'Cancelled', 'give' ),
642
		'abandoned'   => __( 'Abandoned', 'give' ),
643
		'preapproval' => __( 'Pre-Approved', 'give' ),
644
		'processing'  => __( 'Processing', 'give' ),
645
		'revoked'     => __( 'Revoked', 'give' ),
646
	);
647
648
	return apply_filters( 'give_payment_statuses', $payment_statuses );
649
}
650
651
/**
652
 * Get Payment Status Keys
653
 *
654
 * Retrieves keys for all available statuses for payments
655
 *
656
 * @since  1.0
657
 *
658
 * @return array $payment_status All the available payment statuses.
659
 */
660
function give_get_payment_status_keys() {
661
	$statuses = array_keys( give_get_payment_statuses() );
662
	asort( $statuses );
663
664
	return array_values( $statuses );
665
}
666
667
/**
668
 * Get Earnings By Date
669
 *
670
 * @since  1.0
671
 *
672
 * @param  int $day       Day number. Default is null.
673
 * @param  int $month_num Month number. Default is null.
674
 * @param  int $year      Year number. Default is null.
675
 * @param  int $hour      Hour number. Default is null.
676
 *
677
 * @return int $earnings  Earnings
0 ignored issues
show
Documentation introduced by
Should the return type not be double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
678
 */
679
function give_get_earnings_by_date( $day = null, $month_num, $year = null, $hour = null ) {
680
681
	// This is getting deprecated soon. Use Give_Payment_Stats with the get_earnings() method instead.
682
	global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
683
684
	$args = array(
685
		'post_type'              => 'give_payment',
686
		'nopaging'               => true,
687
		'year'                   => $year,
688
		'monthnum'               => $month_num,
689
		'post_status'            => array( 'publish' ),
690
		'fields'                 => 'ids',
691
		'update_post_term_cache' => false,
692
	);
693
	if ( ! empty( $day ) ) {
694
		$args['day'] = $day;
695
	}
696
697
	if ( ! empty( $hour ) ) {
698
		$args['hour'] = $hour;
699
	}
700
701
	$args = apply_filters( 'give_get_earnings_by_date_args', $args );
702
	$key  = Give_Cache::get_key( 'give_stats', $args );
703
704
	if ( ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'give-refresh-reports' ) ) {
705
		$earnings = false;
706
	} else {
707
		$earnings = Give_Cache::get( $key );
708
	}
709
710
	if ( false === $earnings ) {
711
		$donations = get_posts( $args );
712
		$earnings  = 0;
713
		if ( $donations ) {
714
			$donations = implode( ',', $donations );
715
716
			$earnings = $wpdb->get_var( "SELECT SUM(meta_value) FROM $wpdb->postmeta WHERE meta_key = '_give_payment_total' AND post_id IN ({$donations})" );
717
718
		}
719
		// Cache the results for one hour.
720
		Give_Cache::set( $key, $earnings, HOUR_IN_SECONDS );
721
	}
722
723
	return round( $earnings, 2 );
724
}
725
726
/**
727
 * Get Donations (sales) By Date
728
 *
729
 * @since  1.0
730
 *
731
 * @param  int $day       Day number. Default is null.
732
 * @param  int $month_num Month number. Default is null.
733
 * @param  int $year      Year number. Default is null.
734
 * @param  int $hour      Hour number. Default is null.
735
 *
736
 * @return int $count     Sales
737
 */
738
function give_get_sales_by_date( $day = null, $month_num = null, $year = null, $hour = null ) {
739
740
	// This is getting deprecated soon. Use Give_Payment_Stats with the get_sales() method instead.
741
	$args = array(
742
		'post_type'              => 'give_payment',
743
		'nopaging'               => true,
744
		'year'                   => $year,
745
		'fields'                 => 'ids',
746
		'post_status'            => array( 'publish' ),
747
		'update_post_meta_cache' => false,
748
		'update_post_term_cache' => false,
749
	);
750
751
	$show_free = apply_filters( 'give_sales_by_date_show_free', true, $args );
752
753
	if ( false === $show_free ) {
754
		$args['meta_query'] = array(
755
			array(
756
				'key'     => '_give_payment_total',
757
				'value'   => 0,
758
				'compare' => '>',
759
				'type'    => 'NUMERIC',
760
			),
761
		);
762
	}
763
764
	if ( ! empty( $month_num ) ) {
765
		$args['monthnum'] = $month_num;
766
	}
767
768
	if ( ! empty( $day ) ) {
769
		$args['day'] = $day;
770
	}
771
772
	if ( ! empty( $hour ) ) {
773
		$args['hour'] = $hour;
774
	}
775
776
	$args = apply_filters( 'give_get_sales_by_date_args', $args );
777
778
	$key = Give_Cache::get_key( 'give_stats', $args );
779
780
	if ( ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'give-refresh-reports' ) ) {
781
		$count = false;
782
	} else {
783
		$count = Give_Cache::get( $key );
784
	}
785
786
	if ( false === $count ) {
787
		$donations = new WP_Query( $args );
788
		$count     = (int) $donations->post_count;
789
		// Cache the results for one hour.
790
		Give_Cache::set( $key, $count, HOUR_IN_SECONDS );
791
	}
792
793
	return $count;
794
}
795
796
/**
797
 * Checks whether a payment has been marked as complete.
798
 *
799
 * @since  1.0
800
 *
801
 * @param  int $payment_id Payment ID to check against.
802
 *
803
 * @return bool $ret True if complete, false otherwise.
804
 */
805
function give_is_payment_complete( $payment_id ) {
806
	$payment = new Give_Payment( $payment_id );
807
808
	$ret = false;
809
810
	if ( $payment->ID > 0 ) {
811
812
		if ( (int) $payment_id === (int) $payment->ID && 'publish' == $payment->status ) {
813
			$ret = true;
814
		}
815
	}
816
817
	return apply_filters( 'give_is_payment_complete', $ret, $payment_id, $payment->post_status );
818
}
819
820
/**
821
 * Get Total Donations.
822
 *
823
 * @since  1.0
824
 *
825
 * @return int $count Total number of donations.
826
 */
827
function give_get_total_donations() {
828
829
	$payments = give_count_payments();
830
831
	return $payments->publish;
832
}
833
834
/**
835
 * Get Total Earnings
836
 *
837
 * @since  1.0
838
 *
839
 * @param bool $recalculate Recalculate earnings forcefully.
840
 *
841
 * @return float $total Total earnings.
842
 */
843
function give_get_total_earnings( $recalculate = false ) {
844
845
	$total = get_option( 'give_earnings_total', 0 );
846
847
	// Calculate total earnings.
848
	if ( ! $total || $recalculate ) {
849
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
850
851
		$total = (float) 0;
852
853
		$args = apply_filters( 'give_get_total_earnings_args', array(
854
			'offset' => 0,
855
			'number' => - 1,
856
			'status' => array( 'publish' ),
857
			'fields' => 'ids',
858
		) );
859
860
		$payments = give_get_payments( $args );
861
		if ( $payments ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $payments of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
862
863
			/**
864
			 * If performing a donation, we need to skip the very last payment in the database,
865
			 * since it calls give_increase_total_earnings() on completion,
866
			 * which results in duplicated earnings for the very first donation.
867
			 */
868
			if ( did_action( 'give_update_payment_status' ) ) {
869
				array_pop( $payments );
870
			}
871
872
			if ( ! empty( $payments ) ) {
873
				$payments = implode( ',', $payments );
874
				$total    += $wpdb->get_var( "SELECT SUM(meta_value) FROM $wpdb->postmeta WHERE meta_key = '_give_payment_total' AND post_id IN({$payments})" );
875
			}
876
		}
877
878
		update_option( 'give_earnings_total', $total, 'no' );
879
	}
880
881
	if ( $total < 0 ) {
882
		$total = 0; // Don't ever show negative earnings.
883
	}
884
885
	return apply_filters( 'give_total_earnings', round( $total, give_currency_decimal_filter() ) );
886
}
887
888
/**
889
 * Increase the Total Earnings
890
 *
891
 * @since  1.0
892
 *
893
 * @param  int $amount   The amount you would like to increase the total earnings by.
894
 *                       Default is 0.
895
 *
896
 * @return float $total  Total earnings.
897
 */
898
function give_increase_total_earnings( $amount = 0 ) {
899
	$total = give_get_total_earnings();
900
	$total += $amount;
901
	update_option( 'give_earnings_total', $total );
902
903
	return $total;
904
}
905
906
/**
907
 * Decrease the Total Earnings
908
 *
909
 * @since 1.0
910
 *
911
 * @param int $amount The amount you would like to decrease the total earnings by.
912
 *
913
 * @return float $total Total earnings.
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
914
 */
915
function give_decrease_total_earnings( $amount = 0 ) {
916
	$total = give_get_total_earnings();
917
	$total -= $amount;
918
	if ( $total < 0 ) {
919
		$total = 0;
920
	}
921
	update_option( 'give_earnings_total', $total );
922
923
	return $total;
924
}
925
926
/**
927
 * Get Payment Meta for a specific Payment
928
 *
929
 * @since 1.0
930
 *
931
 * @param int    $payment_id Payment ID.
932
 * @param string $meta_key   The meta key to pull.
933
 * @param bool   $single     Pull single meta entry or as an object.
934
 *
935
 * @return mixed $meta Payment Meta.
936
 */
937
function give_get_payment_meta( $payment_id = 0, $meta_key = '_give_payment_meta', $single = true ) {
938
	$payment = new Give_Payment( $payment_id );
939
940
	return $payment->get_meta( $meta_key, $single );
941
}
942
943
/**
944
 * Update the meta for a payment
945
 *
946
 * @param  int    $payment_id Payment ID.
947
 * @param  string $meta_key   Meta key to update.
948
 * @param  string $meta_value Value to update to.
949
 * @param  string $prev_value Previous value.
950
 *
951
 * @return mixed Meta ID if successful, false if unsuccessful.
952
 */
953
function give_update_payment_meta( $payment_id = 0, $meta_key = '', $meta_value = '', $prev_value = '' ) {
954
	$payment = new Give_Payment( $payment_id );
955
956
	return $payment->update_meta( $meta_key, $meta_value, $prev_value );
957
}
958
959
/**
960
 * Get the user_info Key from Payment Meta
961
 *
962
 * @since 1.0
963
 *
964
 * @param int $payment_id Payment ID.
965
 *
966
 * @return array $user_info User Info Meta Values.
967
 */
968
function give_get_payment_meta_user_info( $payment_id ) {
969
	$payment = new Give_Payment( $payment_id );
970
971
	return $payment->user_info;
972
}
973
974
/**
975
 * Get the donations Key from Payment Meta
976
 *
977
 * Retrieves the form_id from a (Previously titled give_get_payment_meta_donations)
978
 *
979
 * @since 1.0
980
 *
981
 * @param int $payment_id Payment ID.
982
 *
983
 * @return int $form_id Form ID.
0 ignored issues
show
Documentation introduced by
Should the return type not be string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
984
 */
985
function give_get_payment_form_id( $payment_id ) {
986
	$payment = new Give_Payment( $payment_id );
987
988
	return $payment->form_id;
989
}
990
991
/**
992
 * Get the user email associated with a payment
993
 *
994
 * @since 1.0
995
 *
996
 * @param int $payment_id Payment ID.
997
 *
998
 * @return string $email User email.
999
 */
1000
function give_get_payment_user_email( $payment_id ) {
1001
	$payment = new Give_Payment( $payment_id );
1002
1003
	return $payment->email;
1004
}
1005
1006
/**
1007
 * Is the payment provided associated with a user account
1008
 *
1009
 * @since  1.3
1010
 *
1011
 * @param  int $payment_id The payment ID.
1012
 *
1013
 * @return bool $is_guest_payment If the payment is associated with a user (false) or not (true)
1014
 */
1015
function give_is_guest_payment( $payment_id ) {
1016
	$payment_user_id  = give_get_payment_user_id( $payment_id );
1017
	$is_guest_payment = ! empty( $payment_user_id ) && $payment_user_id > 0 ? false : true;
1018
1019
	return (bool) apply_filters( 'give_is_guest_payment', $is_guest_payment, $payment_id );
1020
}
1021
1022
/**
1023
 * Get the user ID associated with a payment
1024
 *
1025
 * @since 1.3
1026
 *
1027
 * @param int $payment_id Payment ID.
1028
 *
1029
 * @return int $user_id User ID.
1030
 */
1031
function give_get_payment_user_id( $payment_id ) {
1032
	$payment = new Give_Payment( $payment_id );
1033
1034
	return $payment->user_id;
1035
}
1036
1037
/**
1038
 * Get the donor ID associated with a payment.
1039
 *
1040
 * @since 1.0
1041
 *
1042
 * @param int $payment_id Payment ID.
1043
 *
1044
 * @return int $payment->customer_id Donor ID.
1045
 */
1046
function give_get_payment_donor_id( $payment_id ) {
1047
	$payment = new Give_Payment( $payment_id );
1048
1049
	return $payment->customer_id;
1050
}
1051
1052
/**
1053
 * Get the IP address used to make a donation
1054
 *
1055
 * @since 1.0
1056
 *
1057
 * @param int $payment_id Payment ID.
1058
 *
1059
 * @return string $ip User IP.
1060
 */
1061
function give_get_payment_user_ip( $payment_id ) {
1062
	$payment = new Give_Payment( $payment_id );
1063
1064
	return $payment->ip;
1065
}
1066
1067
/**
1068
 * Get the date a payment was completed
1069
 *
1070
 * @since 1.0
1071
 *
1072
 * @param int $payment_id Payment ID.
1073
 *
1074
 * @return string $date The date the payment was completed.
1075
 */
1076
function give_get_payment_completed_date( $payment_id = 0 ) {
1077
	$payment = new Give_Payment( $payment_id );
1078
1079
	return $payment->completed_date;
1080
}
1081
1082
/**
1083
 * Get the gateway associated with a payment
1084
 *
1085
 * @since 1.0
1086
 *
1087
 * @param int $payment_id Payment ID.
1088
 *
1089
 * @return string $gateway Gateway.
1090
 */
1091
function give_get_payment_gateway( $payment_id ) {
1092
	$payment = new Give_Payment( $payment_id );
1093
1094
	return $payment->gateway;
1095
}
1096
1097
/**
1098
 * Get the currency code a payment was made in
1099
 *
1100
 * @since 1.0
1101
 *
1102
 * @param int $payment_id Payment ID.
1103
 *
1104
 * @return string $currency The currency code.
1105
 */
1106
function give_get_payment_currency_code( $payment_id = 0 ) {
1107
	$payment = new Give_Payment( $payment_id );
1108
1109
	return $payment->currency;
1110
}
1111
1112
/**
1113
 * Get the currency name a payment was made in
1114
 *
1115
 * @since 1.0
1116
 *
1117
 * @param int $payment_id Payment ID.
1118
 *
1119
 * @return string $currency The currency name.
1120
 */
1121
function give_get_payment_currency( $payment_id = 0 ) {
1122
	$currency = give_get_payment_currency_code( $payment_id );
1123
1124
	return apply_filters( 'give_payment_currency', give_get_currency_name( $currency ), $payment_id );
1125
}
1126
1127
/**
1128
 * Get the key for a donation
1129
 *
1130
 * @since 1.0
1131
 *
1132
 * @param int $payment_id Payment ID.
1133
 *
1134
 * @return string $key Donation key.
1135
 */
1136
function give_get_payment_key( $payment_id = 0 ) {
1137
	$payment = new Give_Payment( $payment_id );
1138
1139
	return $payment->key;
1140
}
1141
1142
/**
1143
 * Get the payment order number
1144
 *
1145
 * This will return the payment ID if sequential order numbers are not enabled or the order number does not exist
1146
 *
1147
 * @since 1.0
1148
 *
1149
 * @param int $payment_id Payment ID.
1150
 *
1151
 * @return string $number Payment order number.
1152
 */
1153
function give_get_payment_number( $payment_id = 0 ) {
1154
	$payment = new Give_Payment( $payment_id );
1155
1156
	return $payment->number;
1157
}
1158
1159
/**
1160
 * Formats the payment number with the prefix and postfix
1161
 *
1162
 * @since  1.3
1163
 *
1164
 * @param  int $number The payment number to format.
1165
 *
1166
 * @return string      The formatted payment number.
1167
 */
1168
function give_format_payment_number( $number ) {
1169
1170
	if ( ! give_get_option( 'enable_sequential' ) ) {
1171
		return $number;
1172
	}
1173
1174
	if ( ! is_numeric( $number ) ) {
1175
		return $number;
1176
	}
1177
1178
	$prefix  = give_get_option( 'sequential_prefix' );
1179
	$number  = absint( $number );
1180
	$postfix = give_get_option( 'sequential_postfix' );
1181
1182
	$formatted_number = $prefix . $number . $postfix;
1183
1184
	return apply_filters( 'give_format_payment_number', $formatted_number, $prefix, $number, $postfix );
1185
}
1186
1187
/**
1188
 * Gets the next available order number
1189
 *
1190
 * This is used when inserting a new payment
1191
 *
1192
 * @since 1.0
1193
 * @return string $number The next available payment number.
1194
 */
1195
function give_get_next_payment_number() {
1196
1197
	if ( ! give_get_option( 'enable_sequential' ) ) {
1198
		return false;
1199
	}
1200
1201
	$number           = get_option( 'give_last_payment_number' );
1202
	$start            = give_get_option( 'sequential_start', 1 );
1203
	$increment_number = true;
1204
1205
	if ( false !== $number ) {
1206
1207
		if ( empty( $number ) ) {
1208
1209
			$number           = $start;
1210
			$increment_number = false;
1211
1212
		}
1213
	} else {
1214
1215
		// This case handles the first addition of the new option, as well as if it get's deleted for any reason.
1216
		$payments     = new Give_Payments_Query( array(
1217
			'number'  => 1,
1218
			'order'   => 'DESC',
1219
			'orderby' => 'ID',
1220
			'output'  => 'posts',
1221
			'fields'  => 'ids',
1222
		) );
1223
		$last_payment = $payments->get_payments();
1224
1225
		if ( ! empty( $last_payment ) ) {
1226
1227
			$number = give_get_payment_number( $last_payment[0] );
1228
1229
		}
1230
1231
		if ( ! empty( $number ) && $number !== (int) $last_payment[0] ) {
1232
1233
			$number = give_remove_payment_prefix_postfix( $number );
1234
1235
		} else {
1236
1237
			$number           = $start;
1238
			$increment_number = false;
1239
		}
1240
	}
1241
1242
	$increment_number = apply_filters( 'give_increment_payment_number', $increment_number, $number );
1243
1244
	if ( $increment_number ) {
1245
		$number ++;
1246
	}
1247
1248
	return apply_filters( 'give_get_next_payment_number', $number );
1249
}
1250
1251
/**
1252
 * Given a given a number, remove the pre/postfix
1253
 *
1254
 * @since  1.3
1255
 *
1256
 * @param  string $number The formatted Current Number to increment.
1257
 *
1258
 * @return string The new Payment number without prefix and postfix.
1259
 */
1260
function give_remove_payment_prefix_postfix( $number ) {
1261
1262
	$prefix  = give_get_option( 'sequential_prefix' );
1263
	$postfix = give_get_option( 'sequential_postfix' );
1264
1265
	// Remove prefix.
1266
	$number = preg_replace( '/' . $prefix . '/', '', $number, 1 );
1267
1268
	// Remove the postfix.
1269
	$length      = strlen( $number );
1270
	$postfix_pos = strrpos( $number, $postfix );
1271
	if ( false !== $postfix_pos ) {
1272
		$number = substr_replace( $number, '', $postfix_pos, $length );
1273
	}
1274
1275
	// Ensure it's a whole number.
1276
	$number = intval( $number );
1277
1278
	return apply_filters( 'give_remove_payment_prefix_postfix', $number, $prefix, $postfix );
1279
1280
}
1281
1282
1283
/**
1284
 * Get Payment Amount
1285
 *
1286
 * Get the fully formatted payment amount. The payment amount is retrieved using give_get_payment_amount() and is then
1287
 * sent through give_currency_filter() and  give_format_amount() to format the amount correctly.
1288
 *
1289
 * @since       1.0
1290
 *
1291
 * @param int $payment_id Payment ID.
1292
 *
1293
 * @return string $amount Fully formatted payment amount.
1294
 */
1295
function give_payment_amount( $payment_id = 0 ) {
1296
	$amount = give_get_payment_amount( $payment_id );
1297
1298
	return give_currency_filter( give_format_amount( $amount ), give_get_payment_currency_code( $payment_id ) );
1299
}
1300
1301
/**
1302
 * Get the amount associated with a payment
1303
 *
1304
 * @access public
1305
 * @since  1.0
1306
 *
1307
 * @param int $payment_id Payment ID.
1308
 *
1309
 * @return mixed
1310
 */
1311
function give_get_payment_amount( $payment_id ) {
1312
1313
	$payment = new Give_Payment( $payment_id );
1314
1315
	return apply_filters( 'give_payment_amount', floatval( $payment->total ), $payment_id );
1316
}
1317
1318
/**
1319
 * Payment Subtotal
1320
 *
1321
 * Retrieves subtotal for payment and then returns a full formatted amount. This
1322
 * function essentially calls give_get_payment_subtotal()
1323
 *
1324
 * @since 1.5
1325
 *
1326
 * @param int $payment_id Payment ID.
1327
 *
1328
 * @see   give_get_payment_subtotal()
1329
 *
1330
 * @return array Fully formatted payment subtotal.
1331
 */
1332
function give_payment_subtotal( $payment_id = 0 ) {
1333
	$subtotal = give_get_payment_subtotal( $payment_id );
1334
1335
	return give_currency_filter( give_format_amount( $subtotal ), give_get_payment_currency_code( $payment_id ) );
1336
}
1337
1338
/**
1339
 * Get Payment Subtotal
1340
 *
1341
 * Retrieves subtotal for payment and then returns a non formatted amount.
1342
 *
1343
 * @since 1.5
1344
 *
1345
 * @param int $payment_id Payment ID.
1346
 *
1347
 * @return float $subtotal Subtotal for payment (non formatted).
1348
 */
1349
function give_get_payment_subtotal( $payment_id = 0 ) {
1350
	$payment = new Give_Payment( $payment_id );
1351
1352
	return $payment->subtotal;
1353
}
1354
1355
/**
1356
 * Retrieves the donation ID
1357
 *
1358
 * @since  1.0
1359
 *
1360
 * @param int $payment_id Payment ID.
1361
 *
1362
 * @return string The donation ID.
1363
 */
1364
function give_get_payment_transaction_id( $payment_id = 0 ) {
1365
	$payment = new Give_Payment( $payment_id );
1366
1367
	return $payment->transaction_id;
1368
}
1369
1370
/**
1371
 * Sets a Transaction ID in post meta for the given Payment ID.
1372
 *
1373
 * @since  1.0
1374
 *
1375
 * @param int    $payment_id     Payment ID.
1376
 * @param string $transaction_id The transaction ID from the gateway.
1377
 *
1378
 * @return bool|mixed
1379
 */
1380
function give_set_payment_transaction_id( $payment_id = 0, $transaction_id = '' ) {
1381
1382
	if ( empty( $payment_id ) || empty( $transaction_id ) ) {
1383
		return false;
1384
	}
1385
1386
	$transaction_id = apply_filters( 'give_set_payment_transaction_id', $transaction_id, $payment_id );
1387
1388
	return give_update_payment_meta( $payment_id, '_give_payment_transaction_id', $transaction_id );
1389
}
1390
1391
/**
1392
 * Retrieve the donation ID based on the key
1393
 *
1394
 * @since 1.0
1395
 * @global object $wpdb Used to query the database using the WordPress Database API.
1396
 *
1397
 * @param string  $key  the key to search for.
1398
 *
1399
 * @return int $purchase Donation ID.
1400
 */
1401
function give_get_purchase_id_by_key( $key ) {
1402
	global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1403
1404
	$purchase = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_give_payment_purchase_key' AND meta_value = %s LIMIT 1", $key ) );
1405
1406
	if ( $purchase != null ) {
1407
		return $purchase;
1408
	}
1409
1410
	return 0;
1411
}
1412
1413
1414
/**
1415
 * Retrieve the donation ID based on the transaction ID
1416
 *
1417
 * @since 1.3
1418
 * @global object $wpdb Used to query the database using the WordPress Database API.
1419
 *
1420
 * @param string  $key  The transaction ID to search for.
1421
 *
1422
 * @return int $purchase Donation ID.
1423
 */
1424
function give_get_purchase_id_by_transaction_id( $key ) {
1425
	global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1426
1427
	$purchase = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_give_payment_transaction_id' AND meta_value = %s LIMIT 1", $key ) );
1428
1429
	if ( $purchase != null ) {
1430
		return $purchase;
1431
	}
1432
1433
	return 0;
1434
}
1435
1436
/**
1437
 * Retrieve all notes attached to a donation
1438
 *
1439
 * @since 1.0
1440
 *
1441
 * @param int    $payment_id The donation ID to retrieve notes for.
1442
 * @param string $search     Search for notes that contain a search term.
1443
 *
1444
 * @return array $notes Donation Notes
1445
 */
1446
function give_get_payment_notes( $payment_id = 0, $search = '' ) {
1447
1448
	if ( empty( $payment_id ) && empty( $search ) ) {
1449
		return false;
1450
	}
1451
1452
	remove_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1453
	remove_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10 );
1454
1455
	$notes = get_comments( array( 'post_id' => $payment_id, 'order' => 'ASC', 'search' => $search ) );
1456
1457
	add_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1458
	add_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10, 2 );
1459
1460
	return $notes;
1461
}
1462
1463
1464
/**
1465
 * Add a note to a payment
1466
 *
1467
 * @since 1.0
1468
 *
1469
 * @param int    $payment_id The payment ID to store a note for.
1470
 * @param string $note       The note to store.
1471
 *
1472
 * @return int The new note ID
1473
 */
1474
function give_insert_payment_note( $payment_id = 0, $note = '' ) {
1475
	if ( empty( $payment_id ) ) {
1476
		return false;
1477
	}
1478
1479
	/**
1480
	 * Fires before inserting payment note.
1481
	 *
1482
	 * @since 1.0
1483
	 *
1484
	 * @param int    $payment_id Payment ID.
1485
	 * @param string $note       The note.
1486
	 */
1487
	do_action( 'give_pre_insert_payment_note', $payment_id, $note );
1488
1489
	$note_id = wp_insert_comment( wp_filter_comment( array(
1490
		'comment_post_ID'      => $payment_id,
1491
		'comment_content'      => $note,
1492
		'user_id'              => is_admin() ? get_current_user_id() : 0,
1493
		'comment_date'         => current_time( 'mysql' ),
1494
		'comment_date_gmt'     => current_time( 'mysql', 1 ),
1495
		'comment_approved'     => 1,
1496
		'comment_parent'       => 0,
1497
		'comment_author'       => '',
1498
		'comment_author_IP'    => '',
1499
		'comment_author_url'   => '',
1500
		'comment_author_email' => '',
1501
		'comment_type'         => 'give_payment_note',
1502
1503
	) ) );
1504
1505
	/**
1506
	 * Fires after payment note inserted.
1507
	 *
1508
	 * @since 1.0
1509
	 *
1510
	 * @param int    $note_id    Note ID.
1511
	 * @param int    $payment_id Payment ID.
1512
	 * @param string $note       The note.
1513
	 */
1514
	do_action( 'give_insert_payment_note', $note_id, $payment_id, $note );
1515
1516
	return $note_id;
1517
}
1518
1519
/**
1520
 * Deletes a payment note
1521
 *
1522
 * @since 1.0
1523
 *
1524
 * @param int $comment_id The comment ID to delete.
1525
 * @param int $payment_id The payment ID the note is connected to.
1526
 *
1527
 * @return bool True on success, false otherwise.
1528
 */
1529
function give_delete_payment_note( $comment_id = 0, $payment_id = 0 ) {
1530
	if ( empty( $comment_id ) ) {
1531
		return false;
1532
	}
1533
1534
	/**
1535
	 * Fires before deleting donation note.
1536
	 *
1537
	 * @since 1.0
1538
	 *
1539
	 * @param int $comment_id Note ID.
1540
	 * @param int $payment_id Payment ID.
1541
	 */
1542
	do_action( 'give_pre_delete_payment_note', $comment_id, $payment_id );
1543
1544
	$ret = wp_delete_comment( $comment_id, true );
1545
1546
	/**
1547
	 * Fires after donation note deleted.
1548
	 *
1549
	 * @since 1.0
1550
	 *
1551
	 * @param int $comment_id Note ID.
1552
	 * @param int $payment_id Payment ID.
1553
	 */
1554
	do_action( 'give_post_delete_payment_note', $comment_id, $payment_id );
1555
1556
	return $ret;
1557
}
1558
1559
/**
1560
 * Gets the payment note HTML
1561
 *
1562
 * @since 1.0
1563
 *
1564
 * @param object|int $note       The comment object or ID.
1565
 * @param int        $payment_id The payment ID the note is connected to.
1566
 *
1567
 * @return string
1568
 */
1569
function give_get_payment_note_html( $note, $payment_id = 0 ) {
1570
1571
	if ( is_numeric( $note ) ) {
1572
		$note = get_comment( $note );
1573
	}
1574
1575
	if ( ! empty( $note->user_id ) ) {
1576
		$user = get_userdata( $note->user_id );
1577
		$user = $user->display_name;
1578
	} else {
1579
		$user = esc_html__( 'System', 'give' );
1580
	}
1581
1582
	$date_format = give_date_format() . ', ' . get_option( 'time_format' );
1583
1584
	$delete_note_url = wp_nonce_url( add_query_arg( array(
1585
		'give-action' => 'delete_payment_note',
1586
		'note_id'     => $note->comment_ID,
1587
		'payment_id'  => $payment_id,
1588
	) ), 'give_delete_payment_note_' . $note->comment_ID );
1589
1590
	$note_html = '<div class="give-payment-note" id="give-payment-note-' . $note->comment_ID . '">';
1591
	$note_html .= '<p>';
1592
	$note_html .= '<strong>' . $user . '</strong>&nbsp;&ndash;&nbsp;<span style="color:#aaa;font-style:italic;">' . date_i18n( $date_format, strtotime( $note->comment_date ) ) . '</span><br/>';
1593
	$note_html .= $note->comment_content;
1594
	$note_html .= '&nbsp;&ndash;&nbsp;<a href="' . esc_url( $delete_note_url ) . '" class="give-delete-payment-note" data-note-id="' . absint( $note->comment_ID ) . '" data-payment-id="' . absint( $payment_id ) . '" aria-label="' . esc_attr__( 'Delete this donation note.', 'give' ) . '">' . esc_html__( 'Delete', 'give' ) . '</a>';
1595
	$note_html .= '</p>';
1596
	$note_html .= '</div>';
1597
1598
	return $note_html;
1599
1600
}
1601
1602
/**
1603
 * Exclude notes (comments) on give_payment post type from showing in Recent
1604
 * Comments widgets
1605
 *
1606
 * @since 1.0
1607
 *
1608
 * @param object $query WordPress Comment Query Object.
1609
 *
1610
 * @return void
1611
 */
1612
function give_hide_payment_notes( $query ) {
1613
	if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '>=' ) ) {
1614
		$types = isset( $query->query_vars['type__not_in'] ) ? $query->query_vars['type__not_in'] : array();
1615
		if ( ! is_array( $types ) ) {
1616
			$types = array( $types );
1617
		}
1618
		$types[]                           = 'give_payment_note';
1619
		$query->query_vars['type__not_in'] = $types;
1620
	}
1621
}
1622
1623
add_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1624
1625
/**
1626
 * Exclude notes (comments) on give_payment post type from showing in Recent Comments widgets
1627
 *
1628
 * @since 1.0
1629
 *
1630
 * @param array  $clauses          Comment clauses for comment query.
1631
 * @param object $wp_comment_query WordPress Comment Query Object.
1632
 *
1633
 * @return array $clauses Updated comment clauses.
1634
 */
1635
function give_hide_payment_notes_pre_41( $clauses, $wp_comment_query ) {
0 ignored issues
show
Unused Code introduced by
The parameter $wp_comment_query is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1636
	if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '<' ) ) {
1637
		$clauses['where'] .= ' AND comment_type != "give_payment_note"';
1638
	}
1639
1640
	return $clauses;
1641
}
1642
1643
add_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10, 2 );
1644
1645
1646
/**
1647
 * Exclude notes (comments) on give_payment post type from showing in comment feeds
1648
 *
1649
 * @since 1.0
1650
 *
1651
 * @param string $where
1652
 * @param object $wp_comment_query WordPress Comment Query Object.
1653
 *
1654
 * @return string $where
1655
 */
1656
function give_hide_payment_notes_from_feeds( $where, $wp_comment_query ) {
0 ignored issues
show
Unused Code introduced by
The parameter $wp_comment_query is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1657
	global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1658
1659
	$where .= $wpdb->prepare( ' AND comment_type != %s', 'give_payment_note' );
1660
1661
	return $where;
1662
}
1663
1664
add_filter( 'comment_feed_where', 'give_hide_payment_notes_from_feeds', 10, 2 );
1665
1666
1667
/**
1668
 * Remove Give Comments from the wp_count_comments function
1669
 *
1670
 * @access public
1671
 * @since  1.0
1672
 *
1673
 * @param array $stats   (empty from core filter).
1674
 * @param int   $post_id Post ID.
1675
 *
1676
 * @return array Array of comment counts.
1677
 */
1678
function give_remove_payment_notes_in_comment_counts( $stats, $post_id ) {
1679
	global $wpdb, $pagenow;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1680
1681
	if ( 'index.php' != $pagenow ) {
1682
		return $stats;
1683
	}
1684
1685
	$post_id = (int) $post_id;
1686
1687
	if ( apply_filters( 'give_count_payment_notes_in_comments', false ) ) {
1688
		return $stats;
1689
	}
1690
1691
	$stats = wp_cache_get( "comments-{$post_id}", 'counts' );
1692
1693
	if ( false !== $stats ) {
1694
		return $stats;
1695
	}
1696
1697
	$where = 'WHERE comment_type != "give_payment_note"';
1698
1699
	if ( $post_id > 0 ) {
1700
		$where .= $wpdb->prepare( ' AND comment_post_ID = %d', $post_id );
1701
	}
1702
1703
	$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A );
1704
1705
	$total    = 0;
1706
	$approved = array(
1707
		'0'            => 'moderated',
1708
		'1'            => 'approved',
1709
		'spam'         => 'spam',
1710
		'trash'        => 'trash',
1711
		'post-trashed' => 'post-trashed',
1712
	);
1713
	foreach ( (array) $count as $row ) {
1714
		// Don't count post-trashed toward totals.
1715
		if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
1716
			$total += $row['num_comments'];
1717
		}
1718
		if ( isset( $approved[ $row['comment_approved'] ] ) ) {
1719
			$stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
1720
		}
1721
	}
1722
1723
	$stats['total_comments'] = $total;
1724
	foreach ( $approved as $key ) {
1725
		if ( empty( $stats[ $key ] ) ) {
1726
			$stats[ $key ] = 0;
1727
		}
1728
	}
1729
1730
	$stats = (object) $stats;
1731
	wp_cache_set( "comments-{$post_id}", $stats, 'counts' );
1732
1733
	return $stats;
1734
}
1735
1736
add_filter( 'wp_count_comments', 'give_remove_payment_notes_in_comment_counts', 10, 2 );
1737
1738
1739
/**
1740
 * Filter where older than one week
1741
 *
1742
 * @access public
1743
 * @since  1.0
1744
 *
1745
 * @param string $where Where clause.
1746
 *
1747
 * @return string $where Modified where clause.
1748
 */
1749
function give_filter_where_older_than_week( $where = '' ) {
1750
	// Payments older than one week.
1751
	$start = date( 'Y-m-d', strtotime( '-7 days' ) );
1752
	$where .= " AND post_date <= '{$start}'";
1753
1754
	return $where;
1755
}
1756
1757
1758
/**
1759
 * Get Payment Form ID.
1760
 *
1761
 * Retrieves the form title and appends the level name if present.
1762
 *
1763
 * @since 1.5
1764
 *
1765
 * @param array  $payment_meta Payment meta data.
1766
 * @param bool   $only_level   If set to true will only return the level name if multi-level enabled.
1767
 * @param string $separator    The separator between the .
1768
 *
1769
 * @return string $form_title Returns the full title if $only_level is false, otherwise returns the levels title.
1770
 */
1771
function give_get_payment_form_title( $payment_meta, $only_level = false, $separator = '' ) {
1772
1773
	$form_id    = isset( $payment_meta['form_id'] ) ? $payment_meta['form_id'] : 0;
1774
	$price_id   = isset( $payment_meta['price_id'] ) ? $payment_meta['price_id'] : null;
1775
	$form_title = isset( $payment_meta['form_title'] ) ? $payment_meta['form_title'] : '';
1776
1777
	if ( $only_level == true ) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
1778
		$form_title = '';
1779
	}
1780
1781
	//If multi-level, append to the form title.
1782
	if ( give_has_variable_prices( $form_id ) ) {
1783
1784
		//Only add separator if there is a form title.
1785
		if ( ! empty( $form_title ) ) {
1786
			$form_title .= ' ' . $separator . ' ';
1787
		}
1788
1789
		$form_title .= '<span class="donation-level-text-wrap">';
1790
1791
		if ( $price_id == 'custom' ) {
1792
			$custom_amount_text = give_get_meta( $form_id, '_give_custom_amount_text', true );
1793
			$form_title         .= ! empty( $custom_amount_text ) ? $custom_amount_text : __( 'Custom Amount', 'give' );
1794
		} else {
1795
			$form_title .= give_get_price_option_name( $form_id, $price_id );
1796
		}
1797
1798
		$form_title .= '</span>';
1799
1800
	}
1801
1802
	return apply_filters( 'give_get_payment_form_title', $form_title, $payment_meta );
1803
1804
}
1805
1806
/**
1807
 * Get Price ID
1808
 *
1809
 * Retrieves the Price ID when provided a proper form ID and price (donation) total
1810
 *
1811
 * @param int    $form_id Form ID.
1812
 * @param string $price   Price ID.
1813
 *
1814
 * @return string $price_id
1815
 */
1816
function give_get_price_id( $form_id, $price ) {
1817
1818
	$price_id = 0;
1819
1820
	if ( give_has_variable_prices( $form_id ) ) {
1821
1822
		$levels = maybe_unserialize( give_get_meta( $form_id, '_give_donation_levels', true ) );
1823
1824
		foreach ( $levels as $level ) {
1825
1826
			$level_amount = (float) give_sanitize_amount( $level['_give_amount'] );
1827
1828
			// Check that this indeed the recurring price.
1829
			if ( $level_amount == $price ) {
1830
1831
				$price_id = $level['_give_id']['level_id'];
1832
1833
			}
1834
		}
1835
	}
1836
1837
	return $price_id;
1838
1839
}
1840
1841
/**
1842
 * Get/Print give form dropdown html
1843
 *
1844
 * This function is wrapper to public method forms_dropdown of Give_HTML_Elements class to get/print form dropdown html.
1845
 * Give_HTML_Elements is defined in includes/class-give-html-elements.php.
1846
 *
1847
 * @since 1.6
1848
 *
1849
 * @param array $args Arguments for form dropdown.
1850
 * @param bool  $echo This parameter decides if print form dropdown html output or not.
1851
 *
1852
 * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
1853
 */
1854
function give_get_form_dropdown( $args = array(), $echo = false ) {
1855
	$form_dropdown_html = Give()->html->forms_dropdown( $args );
1856
1857
	if ( ! $echo ) {
1858
		return $form_dropdown_html;
1859
	}
1860
1861
	echo $form_dropdown_html;
1862
}
1863
1864
/**
1865
 * Get/Print give form variable price dropdown html
1866
 *
1867
 * @since 1.6
1868
 *
1869
 * @param array $args Arguments for form dropdown.
1870
 * @param bool  $echo This parameter decide if print form dropdown html output or not.
1871
 *
1872
 * @return string|bool
0 ignored issues
show
Documentation introduced by
Should the return type not be false|string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
1873
 */
1874
function give_get_form_variable_price_dropdown( $args = array(), $echo = false ) {
1875
1876
	// Check for give form id.
1877
	if ( empty( $args['id'] ) ) {
1878
		return false;
1879
	}
1880
1881
	$form = new Give_Donate_Form( $args['id'] );
1882
1883
	// Check if form has variable prices or not.
1884
	if ( ! $form->ID || ! $form->has_variable_prices() ) {
1885
		return false;
1886
	}
1887
1888
	$variable_prices        = $form->get_prices();
1889
	$variable_price_options = array();
1890
1891
	// Check if multi donation form support custom donation or not.
1892
	if ( $form->is_custom_price_mode() ) {
1893
		$variable_price_options['custom'] = _x( 'Custom', 'custom donation dropdown item', 'give' );
1894
	}
1895
1896
	// Get variable price and ID from variable price array.
1897
	foreach ( $variable_prices as $variable_price ) {
1898
		$variable_price_options[ $variable_price['_give_id']['level_id'] ] = ! empty( $variable_price['_give_text'] ) ? $variable_price['_give_text'] : give_currency_filter( give_format_amount( $variable_price['_give_amount'] ) );
1899
	}
1900
1901
	// Update options.
1902
	$args = array_merge( $args, array( 'options' => $variable_price_options ) );
1903
1904
	// Generate select html.
1905
	$form_dropdown_html = Give()->html->select( $args );
1906
1907
	if ( ! $echo ) {
1908
		return $form_dropdown_html;
1909
	}
1910
1911
	echo $form_dropdown_html;
1912
}
1913
1914
/**
1915
 * Get the price_id from the payment meta.
1916
 *
1917
 * Some gateways use `give_price_id` and others were using just `price_id`;
1918
 * This checks for the difference and falls back to retrieving it from the form as a last resort.
1919
 *
1920
 * @since 1.8.6
1921
 *
1922
 * @param $payment_meta
1923
 *
1924
 * @return string
1925
 */
1926
function give_get_payment_meta_price_id( $payment_meta ) {
1927
1928
	if ( isset( $payment_meta['give_price_id'] ) ) {
1929
		$price_id = $payment_meta['give_price_id'];
1930
	} elseif ( isset( $payment_meta['price_id'] ) ) {
1931
		$price_id = $payment_meta['price_id'];
1932
	} else {
1933
		$price_id = give_get_price_id( $payment_meta['give_form_id'], $payment_meta['price'] );
1934
	}
1935
1936
	return apply_filters( 'give_get_payment_meta_price_id', $price_id );
1937
1938
}