Test Failed
Push — feature/meta-tables ( 00f89f )
by Ravinder
05:15
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
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 View Code Duplication
		case 'key':
0 ignored issues
show
Duplication introduced by
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.

Loading history...
88
			$payment = give_get_payments( array(
89
				'meta_key'       => '_give_payment_purchase_key',
0 ignored issues
show
introduced by
Detected usage of meta_key, possible slow query.
Loading history...
90
				'meta_value'     => $value,
0 ignored issues
show
introduced by
Detected usage of meta_value, possible slow query.
Loading history...
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 View Code Duplication
		case 'payment_number':
0 ignored issues
show
Duplication introduced by
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.

Loading history...
102
			$payment = give_get_payments( array(
103
				'meta_key'       => '_give_payment_number',
0 ignored issues
show
introduced by
Detected usage of meta_key, possible slow query.
Loading history...
104
				'meta_value'     => $value,
0 ignored issues
show
introduced by
Detected usage of meta_value, possible slow query.
Loading history...
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
	}// End switch().
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;
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
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 );
0 ignored issues
show
Documentation introduced by
$donor_id is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
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' ) {
0 ignored issues
show
introduced by
Found "== '". Use Yoda Condition checks, you must
Loading history...
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;
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
	} elseif ( ! empty( $args['donor'] ) ) {
429
430
		$join  = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
431
		$where .= "
432
			AND m.meta_key = '_give_payment_customer_id'
433
			AND m.meta_value = '{$args['donor']}'";
434
435
		// Count payments for a search.
436
	} elseif ( ! empty( $args['s'] ) ) {
437
438
		if ( is_email( $args['s'] ) || strlen( $args['s'] ) == 32 ) {
439
440
			if ( is_email( $args['s'] ) ) {
441
				$field = '_give_payment_user_email';
442
			} else {
443
				$field = '_give_payment_purchase_key';
444
			}
445
446
			$join  = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
447
			$where .= $wpdb->prepare( '
448
                AND m.meta_key = %s
449
                AND m.meta_value = %s', $field, $args['s'] );
450
451
		} elseif ( '#' == substr( $args['s'], 0, 1 ) ) {
452
453
			$search = str_replace( '#:', '', $args['s'] );
454
			$search = str_replace( '#', '', $search );
455
456
			$select = 'SELECT p.post_status,count( * ) AS num_posts ';
457
			$join   = '';
458
			$where  = $wpdb->prepare( 'WHERE p.post_type=%s  AND p.ID = %d ', 'give_payment', $search );
459
460
		} elseif ( is_numeric( $args['s'] ) ) {
461
462
			$join  = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
463
			$where .= $wpdb->prepare( "
464
				AND m.meta_key = '_give_payment_user_id'
465
				AND m.meta_value = %d", $args['s'] );
466
467
		} else {
468
			$search = $wpdb->esc_like( $args['s'] );
469
			$search = '%' . $search . '%';
470
471
			$where .= $wpdb->prepare( 'AND ((p.post_title LIKE %s) OR (p.post_content LIKE %s))', $search, $search );
472
		}// End if().
473
	}// End if().
474
475
	if ( ! empty( $args['form_id'] ) && is_numeric( $args['form_id'] ) ) {
476
477
		$join  = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
478
		$where .= $wpdb->prepare( '
479
                AND m.meta_key = %s
480
                AND m.meta_value = %s', '_give_payment_form_id', $args['form_id'] );
481
	}
482
483
	// Limit payments count by date.
484
	if ( ! empty( $args['start-date'] ) && false !== strpos( $args['start-date'], '/' ) ) {
485
486
		$date_parts = explode( '/', $args['start-date'] );
487
		$month      = ! empty( $date_parts[0] ) && is_numeric( $date_parts[0] ) ? $date_parts[0] : 0;
488
		$day        = ! empty( $date_parts[1] ) && is_numeric( $date_parts[1] ) ? $date_parts[1] : 0;
489
		$year       = ! empty( $date_parts[2] ) && is_numeric( $date_parts[2] ) ? $date_parts[2] : 0;
490
491
		$is_date = checkdate( $month, $day, $year );
492 View Code Duplication
		if ( false !== $is_date ) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
493
494
			$date  = new DateTime( $args['start-date'] );
495
			$where .= $wpdb->prepare( " AND p.post_date >= '%s'", $date->format( 'Y-m-d' ) );
496
497
		}
498
499
		// Fixes an issue with the payments list table counts when no end date is specified (with stats class).
500
		if ( empty( $args['end-date'] ) ) {
501
			$args['end-date'] = $args['start-date'];
502
		}
503
	}
504
505
	if ( ! empty( $args['end-date'] ) && false !== strpos( $args['end-date'], '/' ) ) {
506
507
		$date_parts = explode( '/', $args['end-date'] );
508
509
		$month = ! empty( $date_parts[0] ) ? $date_parts[0] : 0;
510
		$day   = ! empty( $date_parts[1] ) ? $date_parts[1] : 0;
511
		$year  = ! empty( $date_parts[2] ) ? $date_parts[2] : 0;
512
513
		$is_date = checkdate( $month, $day, $year );
514 View Code Duplication
		if ( false !== $is_date ) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
515
516
			$date  = new DateTime( $args['end-date'] );
517
			$where .= $wpdb->prepare( " AND p.post_date <= '%s'", $date->format( 'Y-m-d' ) );
518
519
		}
520
	}
521
522
	$where = apply_filters( 'give_count_payments_where', $where );
523
	$join  = apply_filters( 'give_count_payments_join', $join );
524
525
	$query = "$select
526
		FROM $wpdb->posts p
527
		$join
528
		$where
529
		GROUP BY p.post_status
530
	";
531
532
	$cache_key = md5( $query );
533
534
	$count = wp_cache_get( $cache_key, 'counts' );
535
	if ( false !== $count ) {
536
		return $count;
537
	}
538
539
	$count = $wpdb->get_results( $query, ARRAY_A );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
540
541
	$stats    = array();
542
	$statuses = get_post_stati();
543
	if ( isset( $statuses['private'] ) && empty( $args['s'] ) ) {
544
		unset( $statuses['private'] );
545
	}
546
547
	foreach ( $statuses as $state ) {
548
		$stats[ $state ] = 0;
549
	}
550
551
	foreach ( (array) $count as $row ) {
552
553
		if ( 'private' == $row['post_status'] && empty( $args['s'] ) ) {
554
			continue;
555
		}
556
557
		$stats[ $row['post_status'] ] = $row['num_posts'];
558
	}
559
560
	$stats = (object) $stats;
561
	wp_cache_set( $cache_key, $stats, 'counts' );
562
563
	return $stats;
564
}
565
566
567
/**
568
 * Check For Existing Payment
569
 *
570
 * @since  1.0
571
 *
572
 * @param  int $payment_id Payment ID
573
 *
574
 * @return bool $exists True if payment exists, false otherwise.
575
 */
576
function give_check_for_existing_payment( $payment_id ) {
577
	$exists  = false;
578
	$payment = new Give_Payment( $payment_id );
579
580
	if ( $payment_id === $payment->ID && 'publish' === $payment->status ) {
581
		$exists = true;
582
	}
583
584
	return $exists;
585
}
586
587
/**
588
 * Get Payment Status
589
 *
590
 * @since 1.0
591
 *
592
 * @param WP_Post|Give_Payment $payment      Payment object.
593
 * @param bool                 $return_label Whether to return the translated status label
594
 *                                           instead of status value. Default false.
595
 *
596
 * @return bool|mixed True if payment status exists, false otherwise.
597
 */
598
function give_get_payment_status( $payment, $return_label = false ) {
599
600
	if ( ! is_object( $payment ) || ! isset( $payment->post_status ) ) {
601
		return false;
602
	}
603
604
	$statuses = give_get_payment_statuses();
605
606
	if ( ! is_array( $statuses ) || empty( $statuses ) ) {
607
		return false;
608
	}
609
610
	// Get payment object if no already given.
611
	$payment = $payment instanceof Give_Payment ? $payment : new Give_Payment( $payment->ID );
612
613
	if ( array_key_exists( $payment->status, $statuses ) ) {
614
		if ( true === $return_label ) {
615
			// Return translated status label.
616
			return $statuses[ $payment->status ];
617
		} else {
618
			// Account that our 'publish' status is labeled 'Complete'
619
			$post_status = 'publish' == $payment->status ? 'Complete' : $payment->post_status;
620
621
			// Make sure we're matching cases, since they matter
622
			return array_search( strtolower( $post_status ), array_map( 'strtolower', $statuses ) );
623
		}
624
	}
625
626
	return false;
627
}
628
629
/**
630
 * Retrieves all available statuses for payments.
631
 *
632
 * @since  1.0
633
 *
634
 * @return array $payment_status All the available payment statuses.
635
 */
636
function give_get_payment_statuses() {
637
	$payment_statuses = array(
638
		'pending'     => __( 'Pending', 'give' ),
639
		'publish'     => __( 'Complete', 'give' ),
640
		'refunded'    => __( 'Refunded', 'give' ),
641
		'failed'      => __( 'Failed', 'give' ),
642
		'cancelled'   => __( 'Cancelled', 'give' ),
643
		'abandoned'   => __( 'Abandoned', 'give' ),
644
		'preapproval' => __( 'Pre-Approved', 'give' ),
645
		'processing'  => __( 'Processing', 'give' ),
646
		'revoked'     => __( 'Revoked', 'give' ),
647
	);
648
649
	return apply_filters( 'give_payment_statuses', $payment_statuses );
650
}
651
652
/**
653
 * Get Payment Status Keys
654
 *
655
 * Retrieves keys for all available statuses for payments
656
 *
657
 * @since  1.0
658
 *
659
 * @return array $payment_status All the available payment statuses.
660
 */
661
function give_get_payment_status_keys() {
662
	$statuses = array_keys( give_get_payment_statuses() );
663
	asort( $statuses );
664
665
	return array_values( $statuses );
666
}
667
668
/**
669
 * Get Earnings By Date
670
 *
671
 * @since  1.0
672
 *
673
 * @param  int $day       Day number. Default is null.
674
 * @param  int $month_num Month number. Default is null.
675
 * @param  int $year      Year number. Default is null.
676
 * @param  int $hour      Hour number. Default is null.
677
 *
678
 * @return int $earnings  Earnings
679
 */
680
function give_get_earnings_by_date( $day = null, $month_num, $year = null, $hour = null ) {
681
682
	// This is getting deprecated soon. Use Give_Payment_Stats with the get_earnings() method instead.
683
	global $wpdb;
684
685
	$args = array(
686
		'post_type'              => 'give_payment',
687
		'nopaging'               => true,
0 ignored issues
show
introduced by
Disabling pagination is prohibited in VIP context, do not set nopaging to true ever.
Loading history...
688
		'year'                   => $year,
689
		'monthnum'               => $month_num,
690
		'post_status'            => array( 'publish' ),
691
		'fields'                 => 'ids',
692
		'update_post_term_cache' => false,
693
	);
694
	if ( ! empty( $day ) ) {
695
		$args['day'] = $day;
696
	}
697
698
	if ( ! empty( $hour ) ) {
699
		$args['hour'] = $hour;
700
	}
701
702
	$args = apply_filters( 'give_get_earnings_by_date_args', $args );
703
	$key  = Give_Cache::get_key( 'give_stats', $args );
704
705 View Code Duplication
	if ( ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'give-refresh-reports' ) ) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
706
		$earnings = false;
707
	} else {
708
		$earnings = Give_Cache::get( $key );
709
	}
710
711
	if ( false === $earnings ) {
712
		$donations = get_posts( $args );
713
		$earnings  = 0;
714
		if ( $donations ) {
715
			$donations = implode( ',', $donations );
716
717
			$earnings = $wpdb->get_var( "SELECT SUM(meta_value) FROM $wpdb->postmeta WHERE meta_key = '_give_payment_total' AND post_id IN ({$donations})" );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
introduced by
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
718
719
		}
720
		// Cache the results for one hour.
721
		Give_Cache::set( $key, $earnings, HOUR_IN_SECONDS );
722
	}
723
724
	return round( $earnings, 2 );
725
}
726
727
/**
728
 * Get Donations (sales) By Date
729
 *
730
 * @since  1.0
731
 *
732
 * @param  int $day       Day number. Default is null.
733
 * @param  int $month_num Month number. Default is null.
734
 * @param  int $year      Year number. Default is null.
735
 * @param  int $hour      Hour number. Default is null.
736
 *
737
 * @return int $count     Sales
738
 */
739
function give_get_sales_by_date( $day = null, $month_num = null, $year = null, $hour = null ) {
740
741
	// This is getting deprecated soon. Use Give_Payment_Stats with the get_sales() method instead.
742
	$args = array(
743
		'post_type'              => 'give_payment',
744
		'nopaging'               => true,
0 ignored issues
show
introduced by
Disabling pagination is prohibited in VIP context, do not set nopaging to true ever.
Loading history...
745
		'year'                   => $year,
746
		'fields'                 => 'ids',
747
		'post_status'            => array( 'publish' ),
748
		'update_post_meta_cache' => false,
749
		'update_post_term_cache' => false,
750
	);
751
752
	$show_free = apply_filters( 'give_sales_by_date_show_free', true, $args );
753
754
	if ( false === $show_free ) {
755
		$args['meta_query'] = array(
0 ignored issues
show
introduced by
Detected usage of meta_query, possible slow query.
Loading history...
756
			array(
757
				'key'     => '_give_payment_total',
758
				'value'   => 0,
759
				'compare' => '>',
760
				'type'    => 'NUMERIC',
761
			),
762
		);
763
	}
764
765
	if ( ! empty( $month_num ) ) {
766
		$args['monthnum'] = $month_num;
767
	}
768
769
	if ( ! empty( $day ) ) {
770
		$args['day'] = $day;
771
	}
772
773
	if ( ! empty( $hour ) ) {
774
		$args['hour'] = $hour;
775
	}
776
777
	$args = apply_filters( 'give_get_sales_by_date_args', $args );
778
779
	$key = Give_Cache::get_key( 'give_stats', $args );
780
781 View Code Duplication
	if ( ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'give-refresh-reports' ) ) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
782
		$count = false;
783
	} else {
784
		$count = Give_Cache::get( $key );
785
	}
786
787
	if ( false === $count ) {
788
		$donations = new WP_Query( $args );
789
		$count     = (int) $donations->post_count;
790
		// Cache the results for one hour.
791
		Give_Cache::set( $key, $count, HOUR_IN_SECONDS );
792
	}
793
794
	return $count;
795
}
796
797
/**
798
 * Checks whether a payment has been marked as complete.
799
 *
800
 * @since  1.0
801
 *
802
 * @param  int $payment_id Payment ID to check against.
803
 *
804
 * @return bool $ret True if complete, false otherwise.
805
 */
806
function give_is_payment_complete( $payment_id ) {
807
	$payment = new Give_Payment( $payment_id );
808
809
	$ret = false;
810
811
	if ( $payment->ID > 0 ) {
812
813
		if ( (int) $payment_id === (int) $payment->ID && 'publish' == $payment->status ) {
814
			$ret = true;
815
		}
816
	}
817
818
	return apply_filters( 'give_is_payment_complete', $ret, $payment_id, $payment->post_status );
819
}
820
821
/**
822
 * Get Total Donations.
823
 *
824
 * @since  1.0
825
 *
826
 * @return int $count Total number of donations.
827
 */
828
function give_get_total_donations() {
829
830
	$payments = give_count_payments();
831
832
	return $payments->publish;
833
}
834
835
/**
836
 * Get Total Earnings
837
 *
838
 * @since  1.0
839
 *
840
 * @param bool $recalculate Recalculate earnings forcefully.
841
 *
842
 * @return float $total Total earnings.
843
 */
844
function give_get_total_earnings( $recalculate = false ) {
845
846
	$total = get_option( 'give_earnings_total', 0 );
847
848
	// Calculate total earnings.
849
	if ( ! $total || $recalculate ) {
850
		global $wpdb;
851
852
		$total = (float) 0;
853
854
		$args = apply_filters( 'give_get_total_earnings_args', array(
855
			'offset' => 0,
856
			'number' => - 1,
857
			'status' => array( 'publish' ),
858
			'fields' => 'ids',
859
		) );
860
861
		$payments = give_get_payments( $args );
862
		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...
863
864
			/**
865
			 * If performing a donation, we need to skip the very last payment in the database,
866
			 * since it calls give_increase_total_earnings() on completion,
867
			 * which results in duplicated earnings for the very first donation.
868
			 */
869
			if ( did_action( 'give_update_payment_status' ) ) {
870
				array_pop( $payments );
871
			}
872
873
			if ( ! empty( $payments ) ) {
874
				$payments = implode( ',', $payments );
875
				$total    += $wpdb->get_var( "SELECT SUM(meta_value) FROM $wpdb->postmeta WHERE meta_key = '_give_payment_total' AND post_id IN({$payments})" );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
introduced by
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
876
			}
877
		}
878
879
		update_option( 'give_earnings_total', $total, 'no' );
880
	}
881
882
	if ( $total < 0 ) {
883
		$total = 0; // Don't ever show negative earnings.
884
	}
885
886
	return apply_filters( 'give_total_earnings', round( $total, give_currency_decimal_filter() ) );
887
}
888
889
/**
890
 * Increase the Total Earnings
891
 *
892
 * @since  1.0
893
 *
894
 * @param  int $amount   The amount you would like to increase the total earnings by.
895
 *                       Default is 0.
896
 *
897
 * @return float $total  Total earnings.
898
 */
899
function give_increase_total_earnings( $amount = 0 ) {
900
	$total = give_get_total_earnings();
901
	$total += $amount;
902
	update_option( 'give_earnings_total', $total );
903
904
	return $total;
905
}
906
907
/**
908
 * Decrease the Total Earnings
909
 *
910
 * @since 1.0
911
 *
912
 * @param int $amount The amount you would like to decrease the total earnings by.
913
 *
914
 * @return float $total Total earnings.
915
 */
916
function give_decrease_total_earnings( $amount = 0 ) {
917
	$total = give_get_total_earnings();
918
	$total -= $amount;
919
	if ( $total < 0 ) {
920
		$total = 0;
921
	}
922
	update_option( 'give_earnings_total', $total );
923
924
	return $total;
925
}
926
927
/**
928
 * Get Payment Meta for a specific Payment
929
 *
930
 * @since 1.0
931
 *
932
 * @param int    $payment_id Payment ID.
933
 * @param string $meta_key   The meta key to pull.
934
 * @param bool   $single     Pull single meta entry or as an object.
935
 *
936
 * @return mixed $meta Payment Meta.
937
 */
938
function give_get_payment_meta( $payment_id = 0, $meta_key = '_give_payment_meta', $single = true ) {
939
	$payment = new Give_Payment( $payment_id );
940
941
	return $payment->get_meta( $meta_key, $single );
942
}
943
944
/**
945
 * Update the meta for a payment
946
 *
947
 * @param  int    $payment_id Payment ID.
948
 * @param  string $meta_key   Meta key to update.
949
 * @param  string $meta_value Value to update to.
950
 * @param  string $prev_value Previous value.
951
 *
952
 * @return mixed Meta ID if successful, false if unsuccessful.
953
 */
954
function give_update_payment_meta( $payment_id = 0, $meta_key = '', $meta_value = '', $prev_value = '' ) {
955
	$payment = new Give_Payment( $payment_id );
956
957
	return $payment->update_meta( $meta_key, $meta_value, $prev_value );
958
}
959
960
/**
961
 * Get the user_info Key from Payment Meta
962
 *
963
 * @since 1.0
964
 *
965
 * @param int $payment_id Payment ID.
966
 *
967
 * @return array $user_info User Info Meta Values.
968
 */
969
function give_get_payment_meta_user_info( $payment_id ) {
970
	$payment = new Give_Payment( $payment_id );
971
972
	return $payment->user_info;
973
}
974
975
/**
976
 * Get the donations Key from Payment Meta
977
 *
978
 * Retrieves the form_id from a (Previously titled give_get_payment_meta_donations)
979
 *
980
 * @since 1.0
981
 *
982
 * @param int $payment_id Payment ID.
983
 *
984
 * @return int $form_id Form ID.
985
 */
986
function give_get_payment_form_id( $payment_id ) {
987
	$payment = new Give_Payment( $payment_id );
988
989
	return $payment->form_id;
990
}
991
992
/**
993
 * Get the user email associated with a payment
994
 *
995
 * @since 1.0
996
 *
997
 * @param int $payment_id Payment ID.
998
 *
999
 * @return string $email User email.
1000
 */
1001
function give_get_payment_user_email( $payment_id ) {
1002
	$payment = new Give_Payment( $payment_id );
1003
1004
	return $payment->email;
1005
}
1006
1007
/**
1008
 * Is the payment provided associated with a user account
1009
 *
1010
 * @since  1.3
1011
 *
1012
 * @param  int $payment_id The payment ID.
1013
 *
1014
 * @return bool $is_guest_payment If the payment is associated with a user (false) or not (true)
1015
 */
1016
function give_is_guest_payment( $payment_id ) {
1017
	$payment_user_id  = give_get_payment_user_id( $payment_id );
1018
	$is_guest_payment = ! empty( $payment_user_id ) && $payment_user_id > 0 ? false : true;
1019
1020
	return (bool) apply_filters( 'give_is_guest_payment', $is_guest_payment, $payment_id );
1021
}
1022
1023
/**
1024
 * Get the user ID associated with a payment
1025
 *
1026
 * @since 1.3
1027
 *
1028
 * @param int $payment_id Payment ID.
1029
 *
1030
 * @return int $user_id User ID.
1031
 */
1032
function give_get_payment_user_id( $payment_id ) {
1033
	$payment = new Give_Payment( $payment_id );
1034
1035
	return $payment->user_id;
1036
}
1037
1038
/**
1039
 * Get the donor ID associated with a payment.
1040
 *
1041
 * @since 1.0
1042
 *
1043
 * @param int $payment_id Payment ID.
1044
 *
1045
 * @return int $payment->customer_id Donor ID.
1046
 */
1047
function give_get_payment_donor_id( $payment_id ) {
1048
	$payment = new Give_Payment( $payment_id );
1049
1050
	return $payment->customer_id;
1051
}
1052
1053
/**
1054
 * Get the IP address used to make a donation
1055
 *
1056
 * @since 1.0
1057
 *
1058
 * @param int $payment_id Payment ID.
1059
 *
1060
 * @return string $ip User IP.
1061
 */
1062
function give_get_payment_user_ip( $payment_id ) {
1063
	$payment = new Give_Payment( $payment_id );
1064
1065
	return $payment->ip;
1066
}
1067
1068
/**
1069
 * Get the date a payment was completed
1070
 *
1071
 * @since 1.0
1072
 *
1073
 * @param int $payment_id Payment ID.
1074
 *
1075
 * @return string $date The date the payment was completed.
1076
 */
1077
function give_get_payment_completed_date( $payment_id = 0 ) {
1078
	$payment = new Give_Payment( $payment_id );
1079
1080
	return $payment->completed_date;
1081
}
1082
1083
/**
1084
 * Get the gateway associated with a payment
1085
 *
1086
 * @since 1.0
1087
 *
1088
 * @param int $payment_id Payment ID.
1089
 *
1090
 * @return string $gateway Gateway.
1091
 */
1092
function give_get_payment_gateway( $payment_id ) {
1093
	$payment = new Give_Payment( $payment_id );
1094
1095
	return $payment->gateway;
1096
}
1097
1098
/**
1099
 * Get the currency code a payment was made in
1100
 *
1101
 * @since 1.0
1102
 *
1103
 * @param int $payment_id Payment ID.
1104
 *
1105
 * @return string $currency The currency code.
1106
 */
1107
function give_get_payment_currency_code( $payment_id = 0 ) {
1108
	$payment = new Give_Payment( $payment_id );
1109
1110
	return $payment->currency;
1111
}
1112
1113
/**
1114
 * Get the currency name a payment was made in
1115
 *
1116
 * @since 1.0
1117
 *
1118
 * @param int $payment_id Payment ID.
1119
 *
1120
 * @return string $currency The currency name.
1121
 */
1122
function give_get_payment_currency( $payment_id = 0 ) {
1123
	$currency = give_get_payment_currency_code( $payment_id );
1124
1125
	return apply_filters( 'give_payment_currency', give_get_currency_name( $currency ), $payment_id );
1126
}
1127
1128
/**
1129
 * Get the key for a donation
1130
 *
1131
 * @since 1.0
1132
 *
1133
 * @param int $payment_id Payment ID.
1134
 *
1135
 * @return string $key Donation key.
1136
 */
1137
function give_get_payment_key( $payment_id = 0 ) {
1138
	$payment = new Give_Payment( $payment_id );
1139
1140
	return $payment->key;
1141
}
1142
1143
/**
1144
 * Get the payment order number
1145
 *
1146
 * This will return the payment ID if sequential order numbers are not enabled or the order number does not exist
1147
 *
1148
 * @since 1.0
1149
 *
1150
 * @param int $payment_id Payment ID.
1151
 *
1152
 * @return string $number Payment order number.
1153
 */
1154
function give_get_payment_number( $payment_id = 0 ) {
1155
	$payment = new Give_Payment( $payment_id );
1156
1157
	return $payment->number;
1158
}
1159
1160
/**
1161
 * Formats the payment number with the prefix and postfix
1162
 *
1163
 * @since  1.3
1164
 *
1165
 * @param  int $number The payment number to format.
1166
 *
1167
 * @return string      The formatted payment number.
1168
 */
1169
function give_format_payment_number( $number ) {
1170
1171
	if ( ! give_get_option( 'enable_sequential' ) ) {
1172
		return $number;
1173
	}
1174
1175
	if ( ! is_numeric( $number ) ) {
1176
		return $number;
1177
	}
1178
1179
	$prefix  = give_get_option( 'sequential_prefix' );
1180
	$number  = absint( $number );
1181
	$postfix = give_get_option( 'sequential_postfix' );
1182
1183
	$formatted_number = $prefix . $number . $postfix;
1184
1185
	return apply_filters( 'give_format_payment_number', $formatted_number, $prefix, $number, $postfix );
1186
}
1187
1188
/**
1189
 * Gets the next available order number
1190
 *
1191
 * This is used when inserting a new payment
1192
 *
1193
 * @since 1.0
1194
 * @return string $number The next available payment number.
1195
 */
1196
function give_get_next_payment_number() {
1197
1198
	if ( ! give_get_option( 'enable_sequential' ) ) {
1199
		return false;
1200
	}
1201
1202
	$number           = get_option( 'give_last_payment_number' );
1203
	$start            = give_get_option( 'sequential_start', 1 );
1204
	$increment_number = true;
1205
1206
	if ( false !== $number ) {
1207
1208
		if ( empty( $number ) ) {
1209
1210
			$number           = $start;
1211
			$increment_number = false;
1212
1213
		}
1214
	} else {
1215
1216
		// This case handles the first addition of the new option, as well as if it get's deleted for any reason.
1217
		$payments     = new Give_Payments_Query( array(
1218
			'number'  => 1,
1219
			'order'   => 'DESC',
1220
			'orderby' => 'ID',
1221
			'output'  => 'posts',
1222
			'fields'  => 'ids',
1223
		) );
1224
		$last_payment = $payments->get_payments();
1225
1226
		if ( ! empty( $last_payment ) ) {
1227
1228
			$number = give_get_payment_number( $last_payment[0] );
1229
1230
		}
1231
1232
		if ( ! empty( $number ) && $number !== (int) $last_payment[0] ) {
1233
1234
			$number = give_remove_payment_prefix_postfix( $number );
1235
1236
		} else {
1237
1238
			$number           = $start;
1239
			$increment_number = false;
1240
		}
1241
	}// End if().
1242
1243
	$increment_number = apply_filters( 'give_increment_payment_number', $increment_number, $number );
1244
1245
	if ( $increment_number ) {
1246
		$number ++;
1247
	}
1248
1249
	return apply_filters( 'give_get_next_payment_number', $number );
1250
}
1251
1252
/**
1253
 * Given a given a number, remove the pre/postfix
1254
 *
1255
 * @since  1.3
1256
 *
1257
 * @param  string $number The formatted Current Number to increment.
1258
 *
1259
 * @return string The new Payment number without prefix and postfix.
1260
 */
1261
function give_remove_payment_prefix_postfix( $number ) {
1262
1263
	$prefix  = give_get_option( 'sequential_prefix' );
1264
	$postfix = give_get_option( 'sequential_postfix' );
1265
1266
	// Remove prefix.
1267
	$number = preg_replace( '/' . $prefix . '/', '', $number, 1 );
1268
1269
	// Remove the postfix.
1270
	$length      = strlen( $number );
1271
	$postfix_pos = strrpos( $number, $postfix );
1272
	if ( false !== $postfix_pos ) {
1273
		$number = substr_replace( $number, '', $postfix_pos, $length );
1274
	}
1275
1276
	// Ensure it's a whole number.
1277
	$number = intval( $number );
1278
1279
	return apply_filters( 'give_remove_payment_prefix_postfix', $number, $prefix, $postfix );
1280
1281
}
1282
1283
1284
/**
1285
 * Get Payment Amount
1286
 *
1287
 * Get the fully formatted payment amount. The payment amount is retrieved using give_get_payment_amount() and is then
1288
 * sent through give_currency_filter() and  give_format_amount() to format the amount correctly.
1289
 *
1290
 * @since       1.0
1291
 *
1292
 * @param int $payment_id Payment ID.
1293
 *
1294
 * @return string $amount Fully formatted payment amount.
1295
 */
1296
function give_payment_amount( $payment_id = 0 ) {
1297
	$amount = give_get_payment_amount( $payment_id );
1298
1299
	return give_currency_filter( give_format_amount( $amount, array( 'sanitize' => false ) ), give_get_payment_currency_code( $payment_id ) );
1300
}
1301
1302
/**
1303
 * Get the amount associated with a payment
1304
 *
1305
 * @access public
1306
 * @since  1.0
1307
 *
1308
 * @param int $payment_id Payment ID.
1309
 *
1310
 * @return mixed
1311
 */
1312
function give_get_payment_amount( $payment_id ) {
1313
1314
	$payment = new Give_Payment( $payment_id );
1315
1316
	return apply_filters( 'give_payment_amount', floatval( $payment->total ), $payment_id );
1317
}
1318
1319
/**
1320
 * Payment Subtotal
1321
 *
1322
 * Retrieves subtotal for payment and then returns a full formatted amount. This
1323
 * function essentially calls give_get_payment_subtotal()
1324
 *
1325
 * @since 1.5
1326
 *
1327
 * @param int $payment_id Payment ID.
1328
 *
1329
 * @see   give_get_payment_subtotal()
1330
 *
1331
 * @return array Fully formatted payment subtotal.
1332
 */
1333
function give_payment_subtotal( $payment_id = 0 ) {
1334
	$subtotal = give_get_payment_subtotal( $payment_id );
1335
1336
	return give_currency_filter( give_format_amount( $subtotal , array( 'sanitize' => false ) ), give_get_payment_currency_code( $payment_id ) );
1337
}
1338
1339
/**
1340
 * Get Payment Subtotal
1341
 *
1342
 * Retrieves subtotal for payment and then returns a non formatted amount.
1343
 *
1344
 * @since 1.5
1345
 *
1346
 * @param int $payment_id Payment ID.
1347
 *
1348
 * @return float $subtotal Subtotal for payment (non formatted).
1349
 */
1350
function give_get_payment_subtotal( $payment_id = 0 ) {
1351
	$payment = new Give_Payment( $payment_id );
1352
1353
	return $payment->subtotal;
1354
}
1355
1356
/**
1357
 * Retrieves the donation ID
1358
 *
1359
 * @since  1.0
1360
 *
1361
 * @param int $payment_id Payment ID.
1362
 *
1363
 * @return string The donation ID.
1364
 */
1365
function give_get_payment_transaction_id( $payment_id = 0 ) {
1366
	$payment = new Give_Payment( $payment_id );
1367
1368
	return $payment->transaction_id;
1369
}
1370
1371
/**
1372
 * Sets a Transaction ID in post meta for the given Payment ID.
1373
 *
1374
 * @since  1.0
1375
 *
1376
 * @param int    $payment_id     Payment ID.
1377
 * @param string $transaction_id The transaction ID from the gateway.
1378
 *
1379
 * @return bool|mixed
1380
 */
1381
function give_set_payment_transaction_id( $payment_id = 0, $transaction_id = '' ) {
1382
1383
	if ( empty( $payment_id ) || empty( $transaction_id ) ) {
1384
		return false;
1385
	}
1386
1387
	$transaction_id = apply_filters( 'give_set_payment_transaction_id', $transaction_id, $payment_id );
1388
1389
	return give_update_payment_meta( $payment_id, '_give_payment_transaction_id', $transaction_id );
1390
}
1391
1392
/**
1393
 * Retrieve the donation ID based on the key
1394
 *
1395
 * @since 1.0
1396
 * @global object $wpdb Used to query the database using the WordPress Database API.
1397
 *
1398
 * @param string $key  the key to search for.
1399
 *
1400
 * @return int $purchase Donation ID.
1401
 */
1402 View Code Duplication
function give_get_purchase_id_by_key( $key ) {
0 ignored issues
show
Duplication introduced by
This function 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.

Loading history...
1403
	global $wpdb;
1404
1405
	$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 ) );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
introduced by
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
1406
1407
	if ( $purchase != null ) {
1408
		return $purchase;
1409
	}
1410
1411
	return 0;
1412
}
1413
1414
1415
/**
1416
 * Retrieve the donation ID based on the transaction ID
1417
 *
1418
 * @since 1.3
1419
 * @global object $wpdb Used to query the database using the WordPress Database API.
1420
 *
1421
 * @param string $key  The transaction ID to search for.
1422
 *
1423
 * @return int $purchase Donation ID.
1424
 */
1425 View Code Duplication
function give_get_purchase_id_by_transaction_id( $key ) {
0 ignored issues
show
Duplication introduced by
This function 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.

Loading history...
1426
	global $wpdb;
1427
1428
	$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 ) );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
introduced by
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
1429
1430
	if ( $purchase != null ) {
1431
		return $purchase;
1432
	}
1433
1434
	return 0;
1435
}
1436
1437
/**
1438
 * Retrieve all notes attached to a donation
1439
 *
1440
 * @since 1.0
1441
 *
1442
 * @param int    $payment_id The donation ID to retrieve notes for.
1443
 * @param string $search     Search for notes that contain a search term.
1444
 *
1445
 * @return array $notes Donation Notes
1446
 */
1447
function give_get_payment_notes( $payment_id = 0, $search = '' ) {
1448
1449
	if ( empty( $payment_id ) && empty( $search ) ) {
1450
		return false;
1451
	}
1452
1453
	remove_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1454
	remove_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10 );
1455
1456
	$notes = get_comments( array(
1457
		'post_id' => $payment_id,
1458
		'order' => 'ASC',
1459
		'search' => $search,
1460
	) );
1461
1462
	add_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1463
	add_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10, 2 );
1464
1465
	return $notes;
1466
}
1467
1468
1469
/**
1470
 * Add a note to a payment
1471
 *
1472
 * @since 1.0
1473
 *
1474
 * @param int    $payment_id The payment ID to store a note for.
1475
 * @param string $note       The note to store.
1476
 *
1477
 * @return int The new note ID
1478
 */
1479
function give_insert_payment_note( $payment_id = 0, $note = '' ) {
1480
	if ( empty( $payment_id ) ) {
1481
		return false;
1482
	}
1483
1484
	/**
1485
	 * Fires before inserting payment note.
1486
	 *
1487
	 * @since 1.0
1488
	 *
1489
	 * @param int    $payment_id Payment ID.
1490
	 * @param string $note       The note.
1491
	 */
1492
	do_action( 'give_pre_insert_payment_note', $payment_id, $note );
1493
1494
	$note_id = wp_insert_comment( wp_filter_comment( array(
1495
		'comment_post_ID'      => $payment_id,
1496
		'comment_content'      => $note,
1497
		'user_id'              => is_admin() ? get_current_user_id() : 0,
1498
		'comment_date'         => current_time( 'mysql' ),
1499
		'comment_date_gmt'     => current_time( 'mysql', 1 ),
1500
		'comment_approved'     => 1,
1501
		'comment_parent'       => 0,
1502
		'comment_author'       => '',
1503
		'comment_author_IP'    => '',
1504
		'comment_author_url'   => '',
1505
		'comment_author_email' => '',
1506
		'comment_type'         => 'give_payment_note',
1507
1508
	) ) );
1509
1510
	/**
1511
	 * Fires after payment note inserted.
1512
	 *
1513
	 * @since 1.0
1514
	 *
1515
	 * @param int    $note_id    Note ID.
1516
	 * @param int    $payment_id Payment ID.
1517
	 * @param string $note       The note.
1518
	 */
1519
	do_action( 'give_insert_payment_note', $note_id, $payment_id, $note );
1520
1521
	return $note_id;
1522
}
1523
1524
/**
1525
 * Deletes a payment note
1526
 *
1527
 * @since 1.0
1528
 *
1529
 * @param int $comment_id The comment ID to delete.
1530
 * @param int $payment_id The payment ID the note is connected to.
1531
 *
1532
 * @return bool True on success, false otherwise.
1533
 */
1534
function give_delete_payment_note( $comment_id = 0, $payment_id = 0 ) {
1535
	if ( empty( $comment_id ) ) {
1536
		return false;
1537
	}
1538
1539
	/**
1540
	 * Fires before deleting donation note.
1541
	 *
1542
	 * @since 1.0
1543
	 *
1544
	 * @param int $comment_id Note ID.
1545
	 * @param int $payment_id Payment ID.
1546
	 */
1547
	do_action( 'give_pre_delete_payment_note', $comment_id, $payment_id );
1548
1549
	$ret = wp_delete_comment( $comment_id, true );
1550
1551
	/**
1552
	 * Fires after donation note deleted.
1553
	 *
1554
	 * @since 1.0
1555
	 *
1556
	 * @param int $comment_id Note ID.
1557
	 * @param int $payment_id Payment ID.
1558
	 */
1559
	do_action( 'give_post_delete_payment_note', $comment_id, $payment_id );
1560
1561
	return $ret;
1562
}
1563
1564
/**
1565
 * Gets the payment note HTML
1566
 *
1567
 * @since 1.0
1568
 *
1569
 * @param object|int $note       The comment object or ID.
1570
 * @param int        $payment_id The payment ID the note is connected to.
1571
 *
1572
 * @return string
1573
 */
1574
function give_get_payment_note_html( $note, $payment_id = 0 ) {
1575
1576
	if ( is_numeric( $note ) ) {
1577
		$note = get_comment( $note );
1578
	}
1579
1580
	if ( ! empty( $note->user_id ) ) {
1581
		$user = get_userdata( $note->user_id );
1582
		$user = $user->display_name;
1583
	} else {
1584
		$user = esc_html__( 'System', 'give' );
1585
	}
1586
1587
	$date_format = give_date_format() . ', ' . get_option( 'time_format' );
1588
1589
	$delete_note_url = wp_nonce_url( add_query_arg( array(
1590
		'give-action' => 'delete_payment_note',
1591
		'note_id'     => $note->comment_ID,
1592
		'payment_id'  => $payment_id,
1593
	) ), 'give_delete_payment_note_' . $note->comment_ID );
1594
1595
	$note_html = '<div class="give-payment-note" id="give-payment-note-' . $note->comment_ID . '">';
1596
	$note_html .= '<p>';
1597
	$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/>';
1598
	$note_html .= $note->comment_content;
1599
	$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>';
1600
	$note_html .= '</p>';
1601
	$note_html .= '</div>';
1602
1603
	return $note_html;
1604
1605
}
1606
1607
/**
1608
 * Exclude notes (comments) on give_payment post type from showing in Recent
1609
 * Comments widgets
1610
 *
1611
 * @since 1.0
1612
 *
1613
 * @param object $query WordPress Comment Query Object.
1614
 *
1615
 * @return void
1616
 */
1617
function give_hide_payment_notes( $query ) {
1618
	if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '>=' ) ) {
1619
		$types = isset( $query->query_vars['type__not_in'] ) ? $query->query_vars['type__not_in'] : array();
1620
		if ( ! is_array( $types ) ) {
1621
			$types = array( $types );
1622
		}
1623
		$types[]                           = 'give_payment_note';
1624
		$query->query_vars['type__not_in'] = $types;
1625
	}
1626
}
1627
1628
add_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1629
1630
/**
1631
 * Exclude notes (comments) on give_payment post type from showing in Recent Comments widgets
1632
 *
1633
 * @since 1.0
1634
 *
1635
 * @param array  $clauses          Comment clauses for comment query.
1636
 * @param object $wp_comment_query WordPress Comment Query Object.
1637
 *
1638
 * @return array $clauses Updated comment clauses.
1639
 */
1640
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...
1641
	if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '<' ) ) {
1642
		$clauses['where'] .= ' AND comment_type != "give_payment_note"';
1643
	}
1644
1645
	return $clauses;
1646
}
1647
1648
add_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10, 2 );
1649
1650
1651
/**
1652
 * Exclude notes (comments) on give_payment post type from showing in comment feeds
1653
 *
1654
 * @since 1.0
1655
 *
1656
 * @param string $where
1657
 * @param object $wp_comment_query WordPress Comment Query Object.
1658
 *
1659
 * @return string $where
1660
 */
1661
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...
1662
	global $wpdb;
1663
1664
	$where .= $wpdb->prepare( ' AND comment_type != %s', 'give_payment_note' );
1665
1666
	return $where;
1667
}
1668
1669
add_filter( 'comment_feed_where', 'give_hide_payment_notes_from_feeds', 10, 2 );
1670
1671
1672
/**
1673
 * Remove Give Comments from the wp_count_comments function
1674
 *
1675
 * @access public
1676
 * @since  1.0
1677
 *
1678
 * @param array $stats   (empty from core filter).
1679
 * @param int   $post_id Post ID.
1680
 *
1681
 * @return array Array of comment counts.
1682
 */
1683
function give_remove_payment_notes_in_comment_counts( $stats, $post_id ) {
1684
	global $wpdb, $pagenow;
1685
1686
	if ( 'index.php' != $pagenow ) {
1687
		return $stats;
1688
	}
1689
1690
	$post_id = (int) $post_id;
1691
1692
	if ( apply_filters( 'give_count_payment_notes_in_comments', false ) ) {
1693
		return $stats;
1694
	}
1695
1696
	$stats = wp_cache_get( "comments-{$post_id}", 'counts' );
1697
1698
	if ( false !== $stats ) {
1699
		return $stats;
1700
	}
1701
1702
	$where = 'WHERE comment_type != "give_payment_note"';
1703
1704
	if ( $post_id > 0 ) {
1705
		$where .= $wpdb->prepare( ' AND comment_post_ID = %d', $post_id );
1706
	}
1707
1708
	$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
1709
1710
	$total    = 0;
1711
	$approved = array(
1712
		'0'            => 'moderated',
0 ignored issues
show
introduced by
Detected usage of 0, possible slow query.
Loading history...
1713
		'1'            => 'approved',
1714
		'spam'         => 'spam',
1715
		'trash'        => 'trash',
1716
		'post-trashed' => 'post-trashed',
1717
	);
1718
	foreach ( (array) $count as $row ) {
1719
		// Don't count post-trashed toward totals.
1720
		if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
1721
			$total += $row['num_comments'];
1722
		}
1723
		if ( isset( $approved[ $row['comment_approved'] ] ) ) {
1724
			$stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
1725
		}
1726
	}
1727
1728
	$stats['total_comments'] = $total;
1729
	foreach ( $approved as $key ) {
1730
		if ( empty( $stats[ $key ] ) ) {
1731
			$stats[ $key ] = 0;
1732
		}
1733
	}
1734
1735
	$stats = (object) $stats;
1736
	wp_cache_set( "comments-{$post_id}", $stats, 'counts' );
1737
1738
	return $stats;
1739
}
1740
1741
add_filter( 'wp_count_comments', 'give_remove_payment_notes_in_comment_counts', 10, 2 );
1742
1743
1744
/**
1745
 * Filter where older than one week
1746
 *
1747
 * @access public
1748
 * @since  1.0
1749
 *
1750
 * @param string $where Where clause.
1751
 *
1752
 * @return string $where Modified where clause.
1753
 */
1754
function give_filter_where_older_than_week( $where = '' ) {
1755
	// Payments older than one week.
1756
	$start = date( 'Y-m-d', strtotime( '-7 days' ) );
1757
	$where .= " AND post_date <= '{$start}'";
1758
1759
	return $where;
1760
}
1761
1762
1763
/**
1764
 * Get Payment Form ID.
1765
 *
1766
 * Retrieves the form title and appends the level name if present.
1767
 *
1768
 * @since 1.5
1769
 *
1770
 * @param array  $payment_meta Payment meta data.
1771
 * @param bool   $only_level   If set to true will only return the level name if multi-level enabled.
1772
 * @param string $separator    The separator between the .
1773
 *
1774
 * @return string $form_title Returns the full title if $only_level is false, otherwise returns the levels title.
1775
 */
1776
function give_get_payment_form_title( $payment_meta, $only_level = false, $separator = '' ) {
1777
1778
	$form_id    = isset( $payment_meta['form_id'] ) ? $payment_meta['form_id'] : 0;
1779
	$price_id   = isset( $payment_meta['price_id'] ) ? $payment_meta['price_id'] : null;
1780
	$form_title = isset( $payment_meta['form_title'] ) ? $payment_meta['form_title'] : '';
1781
1782
	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...
introduced by
Found "== true". Use Yoda Condition checks, you must
Loading history...
1783
		$form_title = '';
1784
	}
1785
1786
	// If multi-level, append to the form title.
1787
	if ( give_has_variable_prices( $form_id ) ) {
1788
1789
		// Only add separator if there is a form title.
1790
		if ( ! empty( $form_title ) ) {
1791
			$form_title .= ' ' . $separator . ' ';
1792
		}
1793
1794
		$form_title .= '<span class="donation-level-text-wrap">';
1795
1796
		if ( $price_id == 'custom' ) {
0 ignored issues
show
introduced by
Found "== '". Use Yoda Condition checks, you must
Loading history...
1797
			$custom_amount_text = give_get_meta( $form_id, '_give_custom_amount_text', true );
1798
			$form_title         .= ! empty( $custom_amount_text ) ? $custom_amount_text : __( 'Custom Amount', 'give' );
1799
		} else {
1800
			$form_title .= give_get_price_option_name( $form_id, $price_id );
1801
		}
1802
1803
		$form_title .= '</span>';
1804
1805
	}
1806
1807
	return apply_filters( 'give_get_payment_form_title', $form_title, $payment_meta );
1808
1809
}
1810
1811
/**
1812
 * Get Price ID
1813
 *
1814
 * Retrieves the Price ID when provided a proper form ID and price (donation) total
1815
 *
1816
 * @param int    $form_id Form ID.
1817
 * @param string $price   Price ID.
1818
 *
1819
 * @return string $price_id
1820
 */
1821
function give_get_price_id( $form_id, $price ) {
1822
1823
	$price_id = 0;
1824
1825
	if ( give_has_variable_prices( $form_id ) ) {
1826
1827
		$levels = maybe_unserialize( give_get_meta( $form_id, '_give_donation_levels', true ) );
1828
1829
		foreach ( $levels as $level ) {
1830
1831
			$level_amount = (float) give_maybe_sanitize_amount( $level['_give_amount'] );
1832
1833
			// Check that this indeed the recurring price.
1834
			if ( $level_amount == $price ) {
1835
1836
				$price_id = $level['_give_id']['level_id'];
1837
1838
			}
1839
		}
1840
	}
1841
1842
	return $price_id;
1843
1844
}
1845
1846
/**
1847
 * Get/Print give form dropdown html
1848
 *
1849
 * This function is wrapper to public method forms_dropdown of Give_HTML_Elements class to get/print form dropdown html.
1850
 * Give_HTML_Elements is defined in includes/class-give-html-elements.php.
1851
 *
1852
 * @since 1.6
1853
 *
1854
 * @param array $args Arguments for form dropdown.
1855
 * @param bool  $echo This parameter decides if print form dropdown html output or not.
1856
 *
1857
 * @return string
1858
 */
1859
function give_get_form_dropdown( $args = array(), $echo = false ) {
1860
	$form_dropdown_html = Give()->html->forms_dropdown( $args );
1861
1862
	if ( ! $echo ) {
1863
		return $form_dropdown_html;
1864
	}
1865
1866
	echo $form_dropdown_html;
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$form_dropdown_html'
Loading history...
1867
}
1868
1869
/**
1870
 * Get/Print give form variable price dropdown html
1871
 *
1872
 * @since 1.6
1873
 *
1874
 * @param array $args Arguments for form dropdown.
1875
 * @param bool  $echo This parameter decide if print form dropdown html output or not.
1876
 *
1877
 * @return string|bool
1878
 */
1879
function give_get_form_variable_price_dropdown( $args = array(), $echo = false ) {
1880
1881
	// Check for give form id.
1882
	if ( empty( $args['id'] ) ) {
1883
		return false;
1884
	}
1885
1886
	$form = new Give_Donate_Form( $args['id'] );
1887
1888
	// Check if form has variable prices or not.
1889
	if ( ! $form->ID || ! $form->has_variable_prices() ) {
1890
		return false;
1891
	}
1892
1893
	$variable_prices        = $form->get_prices();
1894
	$variable_price_options = array();
1895
1896
	// Check if multi donation form support custom donation or not.
1897
	if ( $form->is_custom_price_mode() ) {
1898
		$variable_price_options['custom'] = _x( 'Custom', 'custom donation dropdown item', 'give' );
1899
	}
1900
1901
	// Get variable price and ID from variable price array.
1902
	foreach ( $variable_prices as $variable_price ) {
1903
		$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'], array( 'sanitize' => false ) ) );
1904
	}
1905
1906
	// Update options.
1907
	$args = array_merge( $args, array(
1908
		'options' => $variable_price_options,
1909
	) );
1910
1911
	// Generate select html.
1912
	$form_dropdown_html = Give()->html->select( $args );
1913
1914
	if ( ! $echo ) {
1915
		return $form_dropdown_html;
1916
	}
1917
1918
	echo $form_dropdown_html;
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$form_dropdown_html'
Loading history...
1919
}
1920
1921
/**
1922
 * Get the price_id from the payment meta.
1923
 *
1924
 * Some gateways use `give_price_id` and others were using just `price_id`;
1925
 * This checks for the difference and falls back to retrieving it from the form as a last resort.
1926
 *
1927
 * @since 1.8.6
1928
 *
1929
 * @param $payment_meta
1930
 *
1931
 * @return string
1932
 */
1933
function give_get_payment_meta_price_id( $payment_meta ) {
1934
1935
	if ( isset( $payment_meta['give_price_id'] ) ) {
1936
		$price_id = $payment_meta['give_price_id'];
1937
	} elseif ( isset( $payment_meta['price_id'] ) ) {
1938
		$price_id = $payment_meta['price_id'];
1939
	} else {
1940
		$price_id = give_get_price_id( $payment_meta['give_form_id'], $payment_meta['price'] );
1941
	}
1942
1943
	return apply_filters( 'give_get_payment_meta_price_id', $price_id );
1944
1945
}
1946