Completed
Pull Request — master (#1610)
by Devin
20:19 queued 17:04
created

functions.php ➔ give_get_payment_meta_price_id()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
ccs 0
cts 0
cp 0
crap 12
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 42
 * @type string $orderby  Sort retrieved payments by parameter. Default is 'ID'.
39 42
 * @type string $status   The status of the payments. Default is 'any'.
40 42
 * @type string $user     User. Default is null.
41
 * @type string $meta_key Custom field key. Default is null.
42 42
 * }
43 42
 *
44
 * @return object $payments Payments retrieved from the database
0 ignored issues
show
Documentation introduced by
Should the return type not be array?

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...
45 42
 */
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 42
 * Retrieve payment by a given field
61
 *
62
 * @since  1.0
63
 *
64 42
 * @param  string $field The field to retrieve the payment with.
65
 * @param  mixed  $value The value for $field.
66 42
 *
67 42
 * @return mixed
68 42
 */
69
function give_get_payment_by( $field = '', $value = '' ) {
70 42
71
	if ( empty( $field ) || empty( $value ) ) {
72
		return false;
73
	}
74 42
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 42
				'fields'         => 'ids',
107
			) );
108 42
109 42
			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 52
/**
127
 * Insert Payment
128
 *
129
 * @since  1.0
130 52
 *
131 52
 * @param  array $payment_data Arguments passed.
132 52
 *
133 52
 * @return int|bool Payment ID if payment is inserted, false otherwise.
134 52
 */
135 52
function give_insert_payment( $payment_data = array() ) {
136
137
	if ( empty( $payment_data ) ) {
138 52
		return false;
139 52
	}
140 52
141 52
	$payment    = new Give_Payment();
142 52
	$gateway    = ! empty( $payment_data['gateway'] ) ? $payment_data['gateway'] : '';
143 52
	$gateway    = empty( $gateway ) && isset( $_POST['give-gateway'] ) ? $_POST['give-gateway'] : $gateway;
144 52
	$form_id    = isset( $payment_data['give_form_id'] ) ? $payment_data['give_form_id'] : 0;
145 52
	$price_id   = give_get_payment_meta_price_id( $payment_data );
146 52
	$form_title = isset( $payment_data['give_form_title'] ) ? $payment_data['give_form_title'] : get_the_title( $form_id );
147 52
148 52
	// Set properties.
149 52
	$payment->total          = $payment_data['price'];
150 52
	$payment->status         = ! empty( $payment_data['status'] ) ? $payment_data['status'] : 'pending';
151 52
	$payment->currency       = ! empty( $payment_data['currency'] ) ? $payment_data['currency'] : give_get_currency();
152 52
	$payment->user_info      = $payment_data['user_info'];
153 52
	$payment->gateway        = $gateway;
154 52
	$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 52
	$payment->email          = $payment_data['user_email'];
159 52
	$payment->first_name     = $payment_data['user_info']['first_name'];
160 52
	$payment->last_name      = $payment_data['user_info']['last_name'];
161 52
	$payment->email          = $payment_data['user_info']['email'];
162
	$payment->ip             = give_get_ip();
163 52
	$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 52
167
	// Add the donation.
168
	$args = array(
169
		'price'    => $payment->total,
170
		'price_id' => $payment->price_id,
171 52
		'fees'     => isset( $payment_data['fees'] ) ? $payment_data['fees'] : array(),
172 20
	);
173 20
174 20
	$payment->add_donation( $payment->form_id, $args );
175 20
176
	// Set date if present.
177
	if ( isset( $payment_data['post_date'] ) ) {
178 52
		$payment->date = $payment_data['post_date'];
179
	}
180
181 52
	// Handle sequential payments.
182
	if ( give_get_option( 'enable_sequential' ) ) {
183
		$number          = give_get_next_payment_number();
184 52
		$payment->number = give_format_payment_number( $number );
185
		update_option( 'give_last_payment_number', $number );
186
	}
187 52
188 52
	// Clear the user's donation cache.
189
	delete_transient( 'give_user_' . $payment_data['user_info']['id'] . '_purchases' );
190
191
	// Save payment.
192
	$payment->save();
193
194
	/**
195
	 * Fires while inserting payments.
196
	 *
197
	 * @since 1.0
198
	 *
199
	 * @param int   $payment_id   The payment ID.
200
	 * @param array $payment_data Arguments passed.
201
	 */
202
	do_action( 'give_insert_payment', $payment->ID, $payment_data );
203
204
	// Return payment ID upon success.
205
	if ( ! empty( $payment->ID ) ) {
206
		return $payment->ID;
207
	}
208 35
209 35
	// Return false if no payment was inserted.
210 35
	return false;
211
212 35
}
213
214
/**
215
 * Create payment.
216
 *
217
 * @param $payment_data
218
 *
219
 * @return bool|int
220
 */
221
function give_create_payment( $payment_data ) {
222
223
	$form_id  = intval( $payment_data['post_data']['give-form-id'] );
224
	$price_id = isset( $payment_data['post_data']['give-price-id'] ) ? $payment_data['post_data']['give-price-id'] : '';
225
226
	// Collect payment data.
227
	$insert_payment_data = array(
228
		'price'           => $payment_data['price'],
229 31
		'give_form_title' => $payment_data['post_data']['give-form-title'],
230
		'give_form_id'    => $form_id,
231 31
		'give_price_id'   => $price_id,
232 31
		'date'            => $payment_data['date'],
233 31
		'user_email'      => $payment_data['user_email'],
234 31
		'purchase_key'    => $payment_data['purchase_key'],
235 31
		'currency'        => give_get_currency(),
236
		'user_info'       => $payment_data['user_info'],
237
		'status'          => 'pending',
238 31
		'gateway'         => 'paypal',
239 31
	);
240
241 31
	/**
242
	 * Filter the payment params.
243 31
	 *
244 16
	 * @since 1.8
245 16
	 *
246
	 * @param array $insert_payment_data
247 31
	 */
248
	$insert_payment_data = apply_filters( 'give_create_payment', $insert_payment_data );
249
250 14
	// Record the pending payment.
251
	return give_insert_payment( $insert_payment_data );
252 14
}
253
254 14
/**
255
 * Updates a payment status.
256
 *
257
 * @since  1.0
258
 *
259
 * @param  int    $payment_id Payment ID.
260
 * @param  string $new_status New Payment Status. Default is 'publish'.
261 14
 *
262
 * @return bool
263 31
 */
264
function give_update_payment_status( $payment_id, $new_status = 'publish' ) {
265 31
266
	$payment         = new Give_Payment( $payment_id );
267
	$payment->status = $new_status;
268 1
	$updated         = $payment->save();
269
270 1
	return $updated;
271
}
272
273 31
274
/**
275
 * Deletes a Donation
276 31
 *
277 31
 * @since  1.0
278 31
 * @global      $give_logs
279
 *
280
 * @param  int  $payment_id      Payment ID (default: 0).
281 31
 * @param  bool $update_customer If we should update the customer stats (default:true).
282
 *
283 31
 * @return void
284 31
 */
285 31
function give_delete_purchase( $payment_id = 0, $update_customer = true ) {
286
	global $give_logs;
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...
287 31
288 31
	$payment     = new Give_Payment( $payment_id );
289
	$amount      = give_get_payment_amount( $payment_id );
290
	$status      = $payment->post_status;
291
	$customer_id = give_get_payment_customer_id( $payment_id );
292
	$customer    = new Give_Customer( $customer_id );
293
294
	// Only undo donations that aren't these statuses.
295
	$dont_undo_statuses = apply_filters( 'give_undo_purchase_statuses', array(
296
		'pending',
297
		'cancelled',
298
	) );
299
300
	if ( ! in_array( $status, $dont_undo_statuses ) ) {
301
		give_undo_purchase( false, $payment_id );
302 20
	}
303
304
	if ( $status == 'publish' ) {
305
306
		// Only decrease earnings if they haven't already been decreased (or were never increased for this payment).
307 20
		give_decrease_total_earnings( $amount );
308
		// Clear the This Month earnings (this_monththis_month is NOT a typo).
309 20
		delete_transient( md5( 'give_earnings_this_monththis_month' ) );
310 20
311
		if ( $customer->id && $update_customer ) {
312 18
313 18
			// Decrement the stats for the donor.
314
			$customer->decrease_purchase_count();
315 20
			$customer->decrease_value( $amount );
316 20
317
		}
318 18
	}
319 18
320
	/**
321 20
	 * Fires before deleting payment.
322
	 *
323
	 * @since 1.0
324
	 *
325
	 * @param int $payment_id Payment ID.
326
	 */
327
	do_action( 'give_payment_delete', $payment_id );
328
329
	if ( $customer->id && $update_customer ) {
330
331
		// Remove the payment ID from the donor.
332
		$customer->remove_payment( $payment_id );
333
334
	}
335
336
	// Remove the payment.
337 6
	wp_delete_post( $payment_id, true );
338
339
	// Remove related sale log entries.
340 6
	$give_logs->delete_logs(
341 6
		null,
342 6
		'sale',
343 6
		array(
344 6
			array(
345 6
				'key'   => '_give_log_payment_id',
346
				'value' => $payment_id,
347 6
			),
348
		)
349 6
	);
350 6
351 6
	/**
352
	 * Fires after payment deleted.
353
	 *
354 6
	 * @since 1.0
355
	 *
356
	 * @param int $payment_id Payment ID.
357
	 */
358
	do_action( 'give_payment_deleted', $payment_id );
359
}
360
361
/**
362
 * Undo Donation
363
 *
364
 * Undoes a donation, including the decrease of donations and earning stats.
365
 * Used for when refunding or deleting a donation.
366
 *
367
 * @since  1.0
368
 *
369
 * @param  int|bool $form_id    Form ID (default: false).
370
 * @param  int      $payment_id Payment ID.
371
 *
372
 * @return void
373 6
 */
374
function give_undo_purchase( $form_id = false, $payment_id ) {
375
376
	if ( ! empty( $form_id ) ) {
377
		$form_id = false;
378
		_give_deprected_argument( 'form_id', 'give_undo_purchase', '1.5' );
379
	}
380
381
	$payment = new Give_Payment( $payment_id );
382
383
	$maybe_decrease_earnings = apply_filters( 'give_decrease_earnings_on_undo', true, $payment, $payment->form_id );
384
	if ( true === $maybe_decrease_earnings ) {
385
		// Decrease earnings.
386
		give_decrease_earnings( $payment->form_id, $payment->total );
387
	}
388
389
	$maybe_decrease_sales = apply_filters( 'give_decrease_sales_on_undo', true, $payment, $payment->form_id );
390
	if ( true === $maybe_decrease_sales ) {
391
		// Decrease donation count.
392
		give_decrease_purchase_count( $payment->form_id );
393
	}
394
395
}
396
397
398
/**
399
 * Count Payments
400
 *
401
 * Returns the total number of payments recorded.
402
 *
403
 * @since  1.0
404
 *
405
 * @param  array $args Arguments passed.
406
 *
407
 * @return array $count Number of payments sorted by payment status.
408
 */
409
function give_count_payments( $args = array() ) {
410
411
	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...
412
413
	$defaults = array(
414
		'user'       => null,
415
		's'          => null,
416
		'start-date' => null,
417
		'end-date'   => null,
418
		'form_id'    => null,
419
	);
420 6
421
	$args = wp_parse_args( $args, $defaults );
422
423
	$select = 'SELECT p.post_status,count( * ) AS num_posts';
424
	$join   = '';
425
	$where  = "WHERE p.post_type = 'give_payment'";
426 6
427
	// Count payments for a specific user.
428
	if ( ! empty( $args['user'] ) ) {
429
430
		if ( is_email( $args['user'] ) ) {
431
			$field = 'email';
432
		} elseif ( is_numeric( $args['user'] ) ) {
433
			$field = 'id';
434
		} else {
435
			$field = '';
436
		}
437
438
		$join = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
439
440
		if ( ! empty( $field ) ) {
441
			$where .= "
442
				AND m.meta_key = '_give_payment_user_{$field}'
443
				AND m.meta_value = '{$args['user']}'";
444
		}
445
446
		// Count payments for a search.
447
	} elseif ( ! empty( $args['s'] ) ) {
448 6
449
		if ( is_email( $args['s'] ) || strlen( $args['s'] ) == 32 ) {
450
451
			if ( is_email( $args['s'] ) ) {
452
				$field = '_give_payment_user_email';
453
			} else {
454
				$field = '_give_payment_purchase_key';
455
			}
456
457
			$join  = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
458
			$where .= $wpdb->prepare( '
459
                AND m.meta_key = %s
460
                AND m.meta_value = %s',
461
				$field,
462
				$args['s']
463
			);
464
465
		} elseif ( '#' == substr( $args['s'], 0, 1 ) ) {
466 6
467 6
			$search = str_replace( '#:', '', $args['s'] );
468
			$search = str_replace( '#', '', $search );
469
470 6
			$select = 'SELECT p2.post_status,count( * ) AS num_posts ';
471 6
			$join   = "LEFT JOIN $wpdb->postmeta m ON m.meta_key = '_give_log_payment_id' AND m.post_id = p.ID ";
472 6
			$join   .= "INNER JOIN $wpdb->posts p2 ON m.meta_value = p2.ID ";
473
			$where  = "WHERE p.post_type = 'give_log' ";
474 6
			$where  .= $wpdb->prepare( 'AND p.post_parent = %d} ', $search );
475
476 6
		} elseif ( is_numeric( $args['s'] ) ) {
477
478 6
			$join  = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
479 6
			$where .= $wpdb->prepare( "
480
				AND m.meta_key = '_give_payment_user_id'
481
				AND m.meta_value = %d",
482
				$args['s']
483 6
			);
484
485 6
		} else {
486 6
			$search = $wpdb->esc_like( $args['s'] );
487 6
			$search = '%' . $search . '%';
488 6
489 6
			$where .= $wpdb->prepare( 'AND ((p.post_title LIKE %s) OR (p.post_content LIKE %s))', $search, $search );
490
		}
491 6
	}
492 6
493 6
	if ( ! empty( $args['form_id'] ) && is_numeric( $args['form_id'] ) ) {
494
495 6
		$where .= $wpdb->prepare( ' AND p.post_parent = %d', $args['form_id'] );
496
497 6
	}
498
	// Limit payments count by date.
499
	if ( ! empty( $args['start-date'] ) && false !== strpos( $args['start-date'], '/' ) ) {
500
501 6
		$date_parts = explode( '/', $args['start-date'] );
502 6
		$month      = ! empty( $date_parts[0] ) && is_numeric( $date_parts[0] ) ? $date_parts[0] : 0;
503
		$day        = ! empty( $date_parts[1] ) && is_numeric( $date_parts[1] ) ? $date_parts[1] : 0;
504 6
		$year       = ! empty( $date_parts[2] ) && is_numeric( $date_parts[2] ) ? $date_parts[2] : 0;
505 6
506
		$is_date = checkdate( $month, $day, $year );
507 6
		if ( false !== $is_date ) {
508
509
			$date  = new DateTime( $args['start-date'] );
510
			$where .= $wpdb->prepare( " AND p.post_date >= '%s'", $date->format( 'Y-m-d' ) );
511
512
		}
513
514
		// Fixes an issue with the payments list table counts when no end date is specified (partiy with stats class).
515
		if ( empty( $args['end-date'] ) ) {
516
			$args['end-date'] = $args['start-date'];
517
		}
518
	}
519
520
	if ( ! empty( $args['end-date'] ) && false !== strpos( $args['end-date'], '/' ) ) {
521
522
		$date_parts = explode( '/', $args['end-date'] );
523
524
		$month = ! empty( $date_parts[0] ) ? $date_parts[0] : 0;
525
		$day   = ! empty( $date_parts[1] ) ? $date_parts[1] : 0;
526
		$year  = ! empty( $date_parts[2] ) ? $date_parts[2] : 0;
527
528
		$is_date = checkdate( $month, $day, $year );
529
		if ( false !== $is_date ) {
530
531
			$date  = new DateTime( $args['end-date'] );
532
			$where .= $wpdb->prepare( " AND p.post_date <= '%s'", $date->format( 'Y-m-d' ) );
533
534
		}
535
	}
536
537
	$where = apply_filters( 'give_count_payments_where', $where );
538
	$join  = apply_filters( 'give_count_payments_join', $join );
539
540
	$query = "$select
541
		FROM $wpdb->posts p
542
		$join
543
		$where
544
		GROUP BY p.post_status
545
	";
546
547
	$cache_key = md5( $query );
548
549
	$count = wp_cache_get( $cache_key, 'counts' );
550
	if ( false !== $count ) {
551
		return $count;
552
	}
553
554
	$count = $wpdb->get_results( $query, ARRAY_A );
555
556
	$stats    = array();
557
	$statuses = get_post_stati();
558
	if ( isset( $statuses['private'] ) && empty( $args['s'] ) ) {
559
		unset( $statuses['private'] );
560
	}
561
562
	foreach ( $statuses as $state ) {
563
		$stats[ $state ] = 0;
564
	}
565
566
	foreach ( (array) $count as $row ) {
567
568
		if ( 'private' == $row['post_status'] && empty( $args['s'] ) ) {
569
			continue;
570
		}
571
572
		$stats[ $row['post_status'] ] = $row['num_posts'];
573
	}
574
575
	$stats = (object) $stats;
576
	wp_cache_set( $cache_key, $stats, 'counts' );
577
578
	return $stats;
579 52
}
580 52
581 52
582 52
/**
583 52
 * Check For Existing Payment
584 52
 *
585 52
 * @since  1.0
586 52
 *
587 52
 * @param  int $payment_id Payment ID
588
 *
589 52
 * @return bool $exists True if payment exists, false otherwise.
590
 */
591
function give_check_for_existing_payment( $payment_id ) {
592
	$exists  = false;
593
	$payment = new Give_Payment( $payment_id );
594
595
	if ( $payment_id === $payment->ID && 'publish' === $payment->status ) {
596
		$exists = true;
597
	}
598
599
	return $exists;
600
}
601 52
602 52
/**
603
 * Get Payment Status
604 52
 *
605
 * @since 1.0
606
 *
607
 * @param WP_Post|Give_Payment $payment      Payment object.
608
 * @param bool                 $return_label Whether to return the translated status label
609
 *                                           instead of status value. Default false.
610
 *
611
 * @return bool|mixed True if payment status exists, false otherwise.
612
 */
613
function give_get_payment_status( $payment, $return_label = false ) {
614
615
	if ( ! is_object( $payment ) || ! isset( $payment->post_status ) ) {
616
		return false;
617
	}
618
619
	$statuses = give_get_payment_statuses();
620
621
	if ( ! is_array( $statuses ) || empty( $statuses ) ) {
622
		return false;
623
	}
624
625
	// Get payment object if no already given.
626
	$payment = $payment instanceof Give_Payment ? $payment : new Give_Payment( $payment->ID );
627
628
	if ( array_key_exists( $payment->status, $statuses ) ) {
629
		if ( true === $return_label ) {
630
			// Return translated status label.
631
			return $statuses[ $payment->status ];
632
		} else {
633
			// Account that our 'publish' status is labeled 'Complete'
634
			$post_status = 'publish' == $payment->status ? 'Complete' : $payment->post_status;
635
636
			// Make sure we're matching cases, since they matter
637
			return array_search( strtolower( $post_status ), array_map( 'strtolower', $statuses ) );
638
		}
639
	}
640
641
	return false;
642
}
643
644
/**
645
 * Retrieves all available statuses for payments.
646
 *
647
 * @since  1.0
648
 *
649
 * @return array $payment_status All the available payment statuses.
650
 */
651
function give_get_payment_statuses() {
652
	$payment_statuses = array(
653
		'pending'     => __( 'Pending', 'give' ),
654
		'publish'     => __( 'Complete', 'give' ),
655
		'refunded'    => __( 'Refunded', 'give' ),
656
		'failed'      => __( 'Failed', 'give' ),
657
		'cancelled'   => __( 'Cancelled', 'give' ),
658
		'abandoned'   => __( 'Abandoned', 'give' ),
659
		'preapproval' => __( 'Pre-Approved', 'give' ),
660
		'revoked'     => __( 'Revoked', 'give' ),
661
	);
662
663
	return apply_filters( 'give_payment_statuses', $payment_statuses );
664
}
665
666
/**
667
 * Get Payment Status Keys
668
 *
669
 * Retrieves keys for all available statuses for payments
670
 *
671
 * @since  1.0
672
 *
673
 * @return array $payment_status All the available payment statuses.
674
 */
675
function give_get_payment_status_keys() {
676
	$statuses = array_keys( give_get_payment_statuses() );
677
	asort( $statuses );
678
679
	return array_values( $statuses );
680
}
681
682
/**
683
 * Get Earnings By Date
684
 *
685
 * @since  1.0
686
 *
687
 * @param  int $day       Day number. Default is null.
688
 * @param  int $month_num Month number. Default is null.
689
 * @param  int $year      Year number. Default is null.
690
 * @param  int $hour      Hour number. Default is null.
691
 *
692
 * @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...
693
 */
694
function give_get_earnings_by_date( $day = null, $month_num, $year = null, $hour = null ) {
695
696
	// This is getting deprecated soon. Use Give_Payment_Stats with the get_earnings() method instead.
697
	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...
698
699
	$args = array(
700
		'post_type'              => 'give_payment',
701
		'nopaging'               => true,
702
		'year'                   => $year,
703
		'monthnum'               => $month_num,
704
		'post_status'            => array( 'publish' ),
705
		'fields'                 => 'ids',
706
		'update_post_term_cache' => false,
707
	);
708
	if ( ! empty( $day ) ) {
709
		$args['day'] = $day;
710
	}
711
712
	if ( ! empty( $hour ) ) {
713
		$args['hour'] = $hour;
714
	}
715
716
	$args = apply_filters( 'give_get_earnings_by_date_args', $args );
717
	$key  = 'give_stats_' . substr( md5( serialize( $args ) ), 0, 15 );
718
719
	if ( ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'give-refresh-reports' ) ) {
720
		$earnings = false;
721
	} else {
722
		$earnings = get_transient( $key );
723
	}
724
725
	if ( false === $earnings ) {
726
		$sales    = get_posts( $args );
727
		$earnings = 0;
728
		if ( $sales ) {
729
			$sales = implode( ',', $sales );
730
731
			$earnings = $wpdb->get_var( "SELECT SUM(meta_value) FROM $wpdb->postmeta WHERE meta_key = '_give_payment_total' AND post_id IN ({$sales})" );
732
733
		}
734
		// Cache the results for one hour.
735
		set_transient( $key, $earnings, HOUR_IN_SECONDS );
736
	}
737
738
	return round( $earnings, 2 );
739
}
740
741
/**
742
 * Get Donations (sales) By Date
743
 *
744
 * @since  1.0
745
 *
746
 * @param  int $day       Day number. Default is null.
747
 * @param  int $month_num Month number. Default is null.
748
 * @param  int $year      Year number. Default is null.
749
 * @param  int $hour      Hour number. Default is null.
750
 *
751
 * @return int $count     Sales
752
 */
753
function give_get_sales_by_date( $day = null, $month_num = null, $year = null, $hour = null ) {
754
755
	// This is getting deprecated soon. Use Give_Payment_Stats with the get_sales() method instead.
756
	$args = array(
757
		'post_type'              => 'give_payment',
758
		'nopaging'               => true,
759
		'year'                   => $year,
760
		'fields'                 => 'ids',
761
		'post_status'            => array( 'publish' ),
762
		'update_post_meta_cache' => false,
763
		'update_post_term_cache' => false,
764
	);
765
766
	$show_free = apply_filters( 'give_sales_by_date_show_free', true, $args );
767
768
	if ( false === $show_free ) {
769
		$args['meta_query'] = array(
770 5
			array(
771
				'key'     => '_give_payment_total',
772 5
				'value'   => 0,
773
				'compare' => '>',
774
				'type'    => 'NUMERIC',
775
			),
776
		);
777
	}
778
779
	if ( ! empty( $month_num ) ) {
780
		$args['monthnum'] = $month_num;
781
	}
782
783 42
	if ( ! empty( $day ) ) {
784
		$args['day'] = $day;
785
	}
786 42
787
	if ( ! empty( $hour ) ) {
788 42
		$args['hour'] = $hour;
789
	}
790 42
791
	$args = apply_filters( 'give_get_sales_by_date_args', $args );
792 42
793
	$key = 'give_stats_' . substr( md5( serialize( $args ) ), 0, 15 );
794 42
795
	if ( ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'give-refresh-reports' ) ) {
796 42
		$count = false;
797 42
	} else {
798 42
		$count = get_transient( $key );
799 42
	}
800
801 42
	if ( false === $count ) {
802
		$sales = new WP_Query( $args );
803
		$count = (int) $sales->post_count;
804 42
		// Cache the results for one hour.
805 42
		set_transient( $key, $count, HOUR_IN_SECONDS );
806
	}
807
808
	return $count;
809
}
810
811
/**
812
 * Checks whether a payment has been marked as complete.
813 42
 *
814 42
 * @since  1.0
815 42
 *
816
 * @param  int $payment_id Payment ID to check against.
817 42
 *
818
 * @return bool $ret True if complete, false otherwise.
819
 */
820
function give_is_payment_complete( $payment_id ) {
821
	$payment = new Give_Payment( $payment_id );
822 42
823
	$ret = false;
824
825 42
	if ( $payment->ID > 0 ) {
826
827
		if ( (int) $payment_id === (int) $payment->ID && 'publish' == $payment->status ) {
828 42
			$ret = true;
829 42
		}
830 42
	}
831
832 42
	return apply_filters( 'give_is_payment_complete', $ret, $payment_id, $payment->post_status );
833
}
834
835
/**
836 42
 * Get Total Donations.
837
 *
838
 * @since  1.0
839
 *
840
 * @return int $count Total sales.
841
 */
842
function give_get_total_sales() {
843
844
	$payments = give_count_payments();
845
846
	return $payments->publish;
847
}
848
849 42
/**
850 42
 * Get Total Earnings
851 42
 *
852
 * @since  1.0
853 42
 *
854
 * @return float $total Total earnings.
855
 */
856
function give_get_total_earnings() {
857
858
	$total = get_option( 'give_earnings_total', false );
859
860
	// If no total stored in DB, use old method of calculating total earnings.
861
	if ( false === $total ) {
862
863
		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...
864
865
		$total = get_transient( 'give_earnings_total' );
866 19
867 19
		if ( false === $total ) {
868 19
869
			$total = (float) 0;
870
871 19
			$args = apply_filters( 'give_get_total_earnings_args', array(
872
				'offset' => 0,
873 19
				'number' => - 1,
874
				'status' => array( 'publish' ),
875
				'fields' => 'ids',
876
			) );
877
878
			$payments = give_get_payments( $args );
879
			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...
880
881
				/**
882
				 * If performing a donation, we need to skip the very last payment in the database,
883
				 * since it calls give_increase_total_earnings() on completion,
884
				 * which results in duplicated earnings for the very first donation.
885
				 */
886
				if ( did_action( 'give_update_payment_status' ) ) {
887
					array_pop( $payments );
888 42
				}
889
890 42
				if ( ! empty( $payments ) ) {
891
					$payments = implode( ',', $payments );
892
					$total    += $wpdb->get_var( "SELECT SUM(meta_value) FROM $wpdb->postmeta WHERE meta_key = '_give_payment_total' AND post_id IN({$payments})" );
893
				}
894
			}
895
896
			// Cache results for 1 day. This cache is cleared automatically when a payment is made.
897
			set_transient( 'give_earnings_total', $total, 86400 );
898
899
			// Store the total for the first time.
900
			update_option( 'give_earnings_total', $total );
901
		}
902
	}
903
904 18
	if ( $total < 0 ) {
905
		$total = 0; // Don't ever show negative earnings.
906 18
	}
907
908
	return apply_filters( 'give_total_earnings', round( $total, give_currency_decimal_filter() ) );
909
}
910
911
/**
912
 * Increase the Total Earnings
913
 *
914
 * @since  1.0
915
 *
916
 * @param  int $amount   The amount you would like to increase the total earnings by.
917
 *                       Default is 0.
918
 *
919
 * @return float $total  Total earnings.
920
 */
921
function give_increase_total_earnings( $amount = 0 ) {
922
	$total = give_get_total_earnings();
923
	$total += $amount;
924
	update_option( 'give_earnings_total', $total );
925
926
	return $total;
927
}
928
929
/**
930
 * Decrease the Total Earnings
931
 *
932
 * @since 1.0
933
 *
934
 * @param int $amount The amount you would like to decrease the total earnings by.
935
 *
936
 * @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...
937
 */
938
function give_decrease_total_earnings( $amount = 0 ) {
939
	$total = give_get_total_earnings();
940
	$total -= $amount;
941
	if ( $total < 0 ) {
942
		$total = 0;
943
	}
944
	update_option( 'give_earnings_total', $total );
945
946
	return $total;
947
}
948
949
/**
950 42
 * Get Payment Meta for a specific Payment
951
 *
952 42
 * @since 1.0
953
 *
954
 * @param int    $payment_id Payment ID.
955
 * @param string $meta_key   The meta key to pull.
956
 * @param bool   $single     Pull single meta entry or as an object.
957
 *
958
 * @return mixed $meta Payment Meta.
959
 */
960
function give_get_payment_meta( $payment_id = 0, $meta_key = '_give_payment_meta', $single = true ) {
961
	$payment = new Give_Payment( $payment_id );
962
963
	return $payment->get_meta( $meta_key, $single );
964
}
965
966
/**
967
 * Update the meta for a payment
968
 *
969
 * @param  int    $payment_id Payment ID.
970
 * @param  string $meta_key   Meta key to update.
971
 * @param  string $meta_value Value to update to.
972
 * @param  string $prev_value Previous value.
973
 *
974
 * @return mixed Meta ID if successful, false if unsuccessful.
975
 */
976
function give_update_payment_meta( $payment_id = 0, $meta_key = '', $meta_value = '', $prev_value = '' ) {
977
	$payment = new Give_Payment( $payment_id );
978
979
	return $payment->update_meta( $meta_key, $meta_value, $prev_value );
980
}
981
982
/**
983
 * Get the user_info Key from Payment Meta
984
 *
985
 * @since 1.0
986
 *
987
 * @param int $payment_id Payment ID.
988
 *
989
 * @return string $user_info User Info Meta Values.
0 ignored issues
show
Documentation introduced by
Should the return type not be array?

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...
990
 */
991
function give_get_payment_meta_user_info( $payment_id ) {
992
	$payment = new Give_Payment( $payment_id );
993
994
	return $payment->user_info;
995
}
996 31
997
/**
998 31
 * Get the donations Key from Payment Meta
999
 *
1000
 * Retrieves the form_id from a (Previously titled give_get_payment_meta_donations)
1001
 *
1002
 * @since 1.0
1003
 *
1004
 * @param int $payment_id Payment ID.
1005
 *
1006
 * @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...
1007
 */
1008
function give_get_payment_form_id( $payment_id ) {
1009
	$payment = new Give_Payment( $payment_id );
1010
1011
	return $payment->form_id;
1012
}
1013
1014
/**
1015
 * Get the user email associated with a payment
1016
 *
1017
 * @since 1.0
1018
 *
1019
 * @param int $payment_id Payment ID.
1020
 *
1021
 * @return string $email User email.
1022
 */
1023
function give_get_payment_user_email( $payment_id ) {
1024
	$payment = new Give_Payment( $payment_id );
1025
1026
	return $payment->email;
1027
}
1028
1029
/**
1030
 * Is the payment provided associated with a user account
1031
 *
1032
 * @since  1.3
1033
 *
1034
 * @param  int $payment_id The payment ID.
1035
 *
1036
 * @return bool $is_guest_payment If the payment is associated with a user (false) or not (true)
1037
 */
1038
function give_is_guest_payment( $payment_id ) {
1039
	$payment_user_id  = give_get_payment_user_id( $payment_id );
1040
	$is_guest_payment = ! empty( $payment_user_id ) && $payment_user_id > 0 ? false : true;
1041
1042
	return (bool) apply_filters( 'give_is_guest_payment', $is_guest_payment, $payment_id );
1043
}
1044
1045
/**
1046
 * Get the user ID associated with a payment
1047
 *
1048
 * @since 1.3
1049
 *
1050
 * @param int $payment_id Payment ID.
1051
 *
1052
 * @return int $user_id User ID.
1053
 */
1054
function give_get_payment_user_id( $payment_id ) {
1055
	$payment = new Give_Payment( $payment_id );
1056
1057
	return $payment->user_id;
1058
}
1059
1060
/**
1061
 * Get the donor ID associated with a payment
1062
 *
1063
 * @since 1.0
1064
 *
1065
 * @param int $payment_id Payment ID.
1066
 *
1067
 * @return int $customer_id Customer ID.
1068
 */
1069
function give_get_payment_customer_id( $payment_id ) {
1070
	$payment = new Give_Payment( $payment_id );
1071
1072
	return $payment->customer_id;
1073
}
1074
1075
/**
1076
 * Get the IP address used to make a donation
1077
 *
1078
 * @since 1.0
1079
 *
1080
 * @param int $payment_id Payment ID.
1081
 *
1082
 * @return string $ip User IP.
1083
 */
1084
function give_get_payment_user_ip( $payment_id ) {
1085
	$payment = new Give_Payment( $payment_id );
1086 52
1087
	return $payment->ip;
1088 52
}
1089
1090
/**
1091
 * Get the date a payment was completed
1092
 *
1093
 * @since 1.0
1094
 *
1095
 * @param int $payment_id Payment ID.
1096
 *
1097
 * @return string $date The date the payment was completed.
1098
 */
1099
function give_get_payment_completed_date( $payment_id = 0 ) {
1100
	$payment = new Give_Payment( $payment_id );
1101
1102
	return $payment->completed_date;
1103
}
1104
1105
/**
1106
 * Get the gateway associated with a payment
1107
 *
1108
 * @since 1.0
1109
 *
1110
 * @param int $payment_id Payment ID.
1111
 *
1112
 * @return string $gateway Gateway.
1113
 */
1114
function give_get_payment_gateway( $payment_id ) {
1115
	$payment = new Give_Payment( $payment_id );
1116
1117
	return $payment->gateway;
1118
}
1119 20
1120
/**
1121
 * Get the currency code a payment was made in
1122
 *
1123 20
 * @since 1.0
1124
 *
1125
 * @param int $payment_id Payment ID.
1126
 *
1127 20
 * @return string $currency The currency code.
1128 20
 */
1129 20
function give_get_payment_currency_code( $payment_id = 0 ) {
1130
	$payment = new Give_Payment( $payment_id );
1131 20
1132
	return $payment->currency;
1133 20
}
1134
1135
/**
1136
 * Get the currency name a payment was made in
1137
 *
1138
 * @since 1.0
1139
 *
1140
 * @param int $payment_id Payment ID.
1141
 *
1142
 * @return string $currency The currency name.
1143
 */
1144
function give_get_payment_currency( $payment_id = 0 ) {
1145
	$currency = give_get_payment_currency_code( $payment_id );
1146 20
1147
	return apply_filters( 'give_payment_currency', give_get_currency_name( $currency ), $payment_id );
1148
}
1149
1150 20
/**
1151 20
 * Get the key for a donation
1152 20
 *
1153
 * @since 1.0
1154 20
 *
1155
 * @param int $payment_id Payment ID.
1156 2
 *
1157
 * @return string $key Donation key.
1158
 */
1159
function give_get_payment_key( $payment_id = 0 ) {
1160
	$payment = new Give_Payment( $payment_id );
1161
1162
	return $payment->key;
1163 2
}
1164
1165
/**
1166 20
 * Get the payment order number
1167 20
 *
1168 20
 * This will return the payment ID if sequential order numbers are not enabled or the order number does not exist
1169 20
 *
1170 20
 * @since 1.0
1171
 *
1172 20
 * @param int $payment_id Payment ID.
1173 20
 *
1174
 * @return string $number Payment order number.
1175 20
 */
1176
function give_get_payment_number( $payment_id = 0 ) {
1177
	$payment = new Give_Payment( $payment_id );
1178
1179
	return $payment->number;
1180
}
1181 20
1182
/**
1183
 * Formats the payment number with the prefix and postfix
1184
 *
1185
 * @since  1.3
1186
 *
1187 20
 * @param  int $number The payment number to format.
1188 20
 *
1189
 * @return string      The formatted payment number.
1190
 */
1191
function give_format_payment_number( $number ) {
1192
1193 20
	if ( ! give_get_option( 'enable_sequential' ) ) {
1194
		return $number;
1195 20
	}
1196 2
1197 2
	if ( ! is_numeric( $number ) ) {
1198
		return $number;
1199 20
	}
1200
1201
	$prefix  = give_get_option( 'sequential_prefix' );
1202
	$number  = absint( $number );
1203
	$postfix = give_get_option( 'sequential_postfix' );
1204
1205
	$formatted_number = $prefix . $number . $postfix;
1206
1207
	return apply_filters( 'give_format_payment_number', $formatted_number, $prefix, $number, $postfix );
1208
}
1209
1210
/**
1211
 * Gets the next available order number
1212
 *
1213
 * This is used when inserting a new payment
1214
 *
1215
 * @since 1.0
1216
 * @return string $number The next available payment number.
1217
 */
1218
function give_get_next_payment_number() {
1219
1220
	if ( ! give_get_option( 'enable_sequential' ) ) {
1221
		return false;
1222
	}
1223
1224
	$number           = get_option( 'give_last_payment_number' );
1225
	$start            = give_get_option( 'sequential_start', 1 );
1226
	$increment_number = true;
1227
1228
	if ( false !== $number ) {
1229
1230
		if ( empty( $number ) ) {
1231
1232
			$number           = $start;
1233
			$increment_number = false;
1234
1235
		}
1236
	} else {
1237
1238
		// This case handles the first addition of the new option, as well as if it get's deleted for any reason.
1239
		$payments     = new Give_Payments_Query( array(
1240
			'number'  => 1,
1241
			'order'   => 'DESC',
1242
			'orderby' => 'ID',
1243
			'output'  => 'posts',
1244
			'fields'  => 'ids',
1245
		) );
1246
		$last_payment = $payments->get_payments();
1247
1248
		if ( ! empty( $last_payment ) ) {
1249
1250
			$number = give_get_payment_number( $last_payment[0] );
1251
1252
		}
1253
1254
		if ( ! empty( $number ) && $number !== (int) $last_payment[0] ) {
1255
1256
			$number = give_remove_payment_prefix_postfix( $number );
1257
1258
		} else {
1259
1260
			$number           = $start;
1261
			$increment_number = false;
1262
		}
1263 52
	}
1264
1265 52
	$increment_number = apply_filters( 'give_increment_payment_number', $increment_number, $number );
1266
1267
	if ( $increment_number ) {
1268
		$number ++;
1269
	}
1270
1271
	return apply_filters( 'give_get_next_payment_number', $number );
1272
}
1273
1274
/**
1275
 * Given a given a number, remove the pre/postfix
1276
 *
1277
 * @since  1.3
1278
 *
1279
 * @param  string $number The formatted Current Number to increment.
1280
 *
1281
 * @return string The new Payment number without prefix and postfix.
1282
 */
1283
function give_remove_payment_prefix_postfix( $number ) {
1284
1285
	$prefix  = give_get_option( 'sequential_prefix' );
1286
	$postfix = give_get_option( 'sequential_postfix' );
1287
1288
	// Remove prefix.
1289
	$number = preg_replace( '/' . $prefix . '/', '', $number, 1 );
1290
1291
	// Remove the postfix.
1292
	$length      = strlen( $number );
1293
	$postfix_pos = strrpos( $number, $postfix );
1294
	if ( false !== $postfix_pos ) {
1295
		$number = substr_replace( $number, '', $postfix_pos, $length );
1296
	}
1297
1298
	// Ensure it's a whole number.
1299
	$number = intval( $number );
1300
1301
	return apply_filters( 'give_remove_payment_prefix_postfix', $number, $prefix, $postfix );
1302
1303
}
1304
1305
1306
/**
1307
 * Get Payment Amount
1308
 *
1309
 * Get the fully formatted payment amount. The payment amount is retrieved using give_get_payment_amount() and is then
1310
 * sent through give_currency_filter() and  give_format_amount() to format the amount correctly.
1311
 *
1312
 * @since       1.0
1313
 *
1314
 * @param int $payment_id Payment ID.
1315
 *
1316
 * @return string $amount Fully formatted payment amount.
1317
 */
1318
function give_payment_amount( $payment_id = 0 ) {
1319
	$amount = give_get_payment_amount( $payment_id );
1320
1321
	return give_currency_filter( give_format_amount( $amount ), give_get_payment_currency_code( $payment_id ) );
1322
}
1323
1324
/**
1325
 * Get the amount associated with a payment
1326
 *
1327
 * @access public
1328
 * @since  1.0
1329
 *
1330
 * @param int $payment_id Payment ID.
1331
 *
1332
 * @return mixed|void
1333
 */
1334
function give_get_payment_amount( $payment_id ) {
1335
1336
	$payment = new Give_Payment( $payment_id );
1337
1338
	return apply_filters( 'give_payment_amount', floatval( $payment->total ), $payment_id );
1339
}
1340
1341
/**
1342
 * Payment Subtotal
1343
 *
1344
 * Retrieves subtotal for payment (this is the amount before fees) and then returns a full formatted amount. This
1345
 * function essentially calls give_get_payment_subtotal()
1346
 *
1347 18
 * @since 1.5
1348
 *
1349
 * @param int $payment_id Payment ID.
1350
 *
1351 18
 * @see   give_get_payment_subtotal()
1352
 *
1353 18
 * @return array Fully formatted payment subtotal.
1354
 */
1355
function give_payment_subtotal( $payment_id = 0 ) {
1356
	$subtotal = give_get_payment_subtotal( $payment_id );
1357
1358
	return give_currency_filter( give_format_amount( $subtotal ), give_get_payment_currency_code( $payment_id ) );
1359
}
1360
1361
/**
1362
 * Get Payment Subtotal
1363
 *
1364
 * Retrieves subtotal for payment (this is the amount before fees) and then returns a non formatted amount.
1365
 *
1366
 * @since 1.5
1367
 *
1368
 * @param int $payment_id Payment ID.
1369
 *
1370
 * @return float $subtotal Subtotal for payment (non formatted).
1371
 */
1372
function give_get_payment_subtotal( $payment_id = 0 ) {
1373
	$payment = new G_Payment( $payment_id );
1374
1375
	return $payment->subtotal;
1376
}
1377
1378
/**
1379
 * Retrieves arbitrary fees for the payment
1380
 *
1381
 * @since 1.5
1382
 *
1383
 * @param int    $payment_id Payment ID.
1384
 * @param string $type       Fee type.
1385
 *
1386
 * @return mixed array if payment fees found, false otherwise.
1387
 */
1388
function give_get_payment_fees( $payment_id = 0, $type = 'all' ) {
1389
	$payment = new Give_Payment( $payment_id );
1390
1391
	return $payment->get_fees( $type );
1392
}
1393
1394
/**
1395
 * Retrieves the donation ID
1396
 *
1397
 * @since  1.0
1398
 *
1399
 * @param int $payment_id Payment ID.
1400
 *
1401
 * @return string The donation ID.
1402
 */
1403
function give_get_payment_transaction_id( $payment_id = 0 ) {
1404
	$payment = new Give_Payment( $payment_id );
1405
1406
	return $payment->transaction_id;
1407
}
1408
1409
/**
1410
 * Sets a Transaction ID in post meta for the given Payment ID.
1411
 *
1412
 * @since  1.0
1413
 *
1414
 * @param int    $payment_id     Payment ID.
1415
 * @param string $transaction_id The transaction ID from the gateway.
1416
 *
1417
 * @return bool|mixed
1418
 */
1419
function give_set_payment_transaction_id( $payment_id = 0, $transaction_id = '' ) {
1420
1421
	if ( empty( $payment_id ) || empty( $transaction_id ) ) {
1422
		return false;
1423
	}
1424
1425
	$transaction_id = apply_filters( 'give_set_payment_transaction_id', $transaction_id, $payment_id );
1426
1427
	return give_update_payment_meta( $payment_id, '_give_payment_transaction_id', $transaction_id );
1428
}
1429
1430
/**
1431
 * Retrieve the donation ID based on the key
1432
 *
1433
 * @since 1.0
1434
 * @global object $wpdb Used to query the database using the WordPress Database API.
1435
 *
1436
 * @param string  $key  the key to search for.
1437
 *
1438
 * @return int $purchase Donation ID.
1439
 */
1440
function give_get_purchase_id_by_key( $key ) {
1441
	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...
1442 52
1443
	$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 ) );
1444
1445
	if ( $purchase != null ) {
1446 52
		return $purchase;
1447
	}
1448 52
1449 52
	return 0;
1450 52
}
1451 52
1452 52
1453 52
/**
1454 52
 * Retrieve the donation ID based on the transaction ID
1455 52
 *
1456 52
 * @since 1.3
1457 52
 * @global object $wpdb Used to query the database using the WordPress Database API.
1458 52
 *
1459 52
 * @param string  $key  The transaction ID to search for.
1460
 *
1461
 * @return int $purchase Donation ID.
1462 52
 */
1463
function give_get_purchase_id_by_transaction_id( $key ) {
1464 52
	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...
1465
1466 52
	$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 ) );
1467
1468
	if ( $purchase != null ) {
1469
		return $purchase;
1470
	}
1471
1472
	return 0;
1473
}
1474
1475
/**
1476
 * Retrieve all notes attached to a donation
1477
 *
1478
 * @since 1.0
1479
 *
1480
 * @param int    $payment_id The donation ID to retrieve notes for.
1481
 * @param string $search     Search for notes that contain a search term.
1482
 *
1483
 * @return array $notes Donation Notes
1484
 */
1485
function give_get_payment_notes( $payment_id = 0, $search = '' ) {
1486
1487
	if ( empty( $payment_id ) && empty( $search ) ) {
1488
		return false;
1489
	}
1490
1491
	remove_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1492
	remove_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10 );
1493
1494
	$notes = get_comments( array( 'post_id' => $payment_id, 'order' => 'ASC', 'search' => $search ) );
1495
1496
	add_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1497
	add_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10, 2 );
1498
1499
	return $notes;
1500
}
1501
1502
1503
/**
1504
 * Add a note to a payment
1505
 *
1506
 * @since 1.0
1507
 *
1508
 * @param int    $payment_id The payment ID to store a note for.
1509
 * @param string $note       The note to store.
1510
 *
1511
 * @return int The new note ID
1512
 */
1513
function give_insert_payment_note( $payment_id = 0, $note = '' ) {
1514
	if ( empty( $payment_id ) ) {
1515
		return false;
1516
	}
1517
1518
	/**
1519
	 * Fires before inserting payment note.
1520
	 *
1521
	 * @since 1.0
1522
	 *
1523
	 * @param int    $payment_id Payment ID.
1524
	 * @param string $note       The note.
1525
	 */
1526
	do_action( 'give_pre_insert_payment_note', $payment_id, $note );
1527
1528
	$note_id = wp_insert_comment( wp_filter_comment( array(
1529
		'comment_post_ID'      => $payment_id,
1530
		'comment_content'      => $note,
1531
		'user_id'              => is_admin() ? get_current_user_id() : 0,
1532
		'comment_date'         => current_time( 'mysql' ),
1533
		'comment_date_gmt'     => current_time( 'mysql', 1 ),
1534
		'comment_approved'     => 1,
1535
		'comment_parent'       => 0,
1536
		'comment_author'       => '',
1537
		'comment_author_IP'    => '',
1538
		'comment_author_url'   => '',
1539
		'comment_author_email' => '',
1540
		'comment_type'         => 'give_payment_note',
1541
1542
	) ) );
1543
1544
	/**
1545
	 * Fires after payment note inserted.
1546
	 *
1547
	 * @since 1.0
1548
	 *
1549
	 * @param int    $note_id    Note ID.
1550
	 * @param int    $payment_id Payment ID.
1551
	 * @param string $note       The note.
1552
	 */
1553
	do_action( 'give_insert_payment_note', $note_id, $payment_id, $note );
1554
1555
	return $note_id;
1556
}
1557
1558
/**
1559
 * Deletes a payment note
1560
 *
1561
 * @since 1.0
1562
 *
1563
 * @param int $comment_id The comment ID to delete.
1564
 * @param int $payment_id The payment ID the note is connected to.
1565
 *
1566
 * @return bool True on success, false otherwise.
1567
 */
1568
function give_delete_payment_note( $comment_id = 0, $payment_id = 0 ) {
1569
	if ( empty( $comment_id ) ) {
1570
		return false;
1571
	}
1572
1573
	/**
1574
	 * Fires before deleting donation note.
1575
	 *
1576
	 * @since 1.0
1577
	 *
1578
	 * @param int $comment_id Note ID.
1579
	 * @param int $payment_id Payment ID.
1580
	 */
1581
	do_action( 'give_pre_delete_payment_note', $comment_id, $payment_id );
1582
1583
	$ret = wp_delete_comment( $comment_id, true );
1584
1585
	/**
1586
	 * Fires after donation note deleted.
1587
	 *
1588
	 * @since 1.0
1589
	 *
1590
	 * @param int $comment_id Note ID.
1591
	 * @param int $payment_id Payment ID.
1592
	 */
1593
	do_action( 'give_post_delete_payment_note', $comment_id, $payment_id );
1594
1595
	return $ret;
1596
}
1597
1598
/**
1599
 * Gets the payment note HTML
1600
 *
1601
 * @since 1.0
1602
 *
1603
 * @param object|int $note       The comment object or ID.
1604
 * @param int        $payment_id The payment ID the note is connected to.
1605
 *
1606
 * @return string
1607
 */
1608
function give_get_payment_note_html( $note, $payment_id = 0 ) {
1609
1610
	if ( is_numeric( $note ) ) {
1611
		$note = get_comment( $note );
1612
	}
1613
1614
	if ( ! empty( $note->user_id ) ) {
1615
		$user = get_userdata( $note->user_id );
1616
		$user = $user->display_name;
1617
	} else {
1618
		$user = esc_html__( 'System', 'give' );
1619
	}
1620
1621
	$date_format = give_date_format() . ', ' . get_option( 'time_format' );
1622
1623
	$delete_note_url = wp_nonce_url( add_query_arg( array(
1624
		'give-action' => 'delete_payment_note',
1625
		'note_id'     => $note->comment_ID,
1626
		'payment_id'  => $payment_id,
1627
	) ),
1628
		'give_delete_payment_note_' . $note->comment_ID
1629
	);
1630
1631
	$note_html = '<div class="give-payment-note" id="give-payment-note-' . $note->comment_ID . '">';
1632
	$note_html .= '<p>';
1633
	$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/>';
1634
	$note_html .= $note->comment_content;
1635
	$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>';
1636
	$note_html .= '</p>';
1637
	$note_html .= '</div>';
1638
1639
	return $note_html;
1640
1641
}
1642
1643
/**
1644
 * Exclude notes (comments) on give_payment post type from showing in Recent
1645
 * Comments widgets
1646
 *
1647
 * @since 1.0
1648
 *
1649
 * @param object $query WordPress Comment Query Object.
1650
 *
1651
 * @return void
1652
 */
1653
function give_hide_payment_notes( $query ) {
1654
	if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '>=' ) ) {
1655
		$types = isset( $query->query_vars['type__not_in'] ) ? $query->query_vars['type__not_in'] : array();
1656
		if ( ! is_array( $types ) ) {
1657
			$types = array( $types );
1658
		}
1659
		$types[]                           = 'give_payment_note';
1660
		$query->query_vars['type__not_in'] = $types;
1661
	}
1662
}
1663
1664
add_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1665
1666
/**
1667
 * Exclude notes (comments) on give_payment post type from showing in Recent Comments widgets
1668
 *
1669
 * @since 1.0
1670
 *
1671
 * @param array  $clauses          Comment clauses for comment query.
1672
 * @param object $wp_comment_query WordPress Comment Query Object.
1673
 *
1674
 * @return array $clauses Updated comment clauses.
1675
 */
1676
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...
1677
	if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '<' ) ) {
1678
		$clauses['where'] .= ' AND comment_type != "give_payment_note"';
1679
	}
1680
1681
	return $clauses;
1682
}
1683
1684
add_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10, 2 );
1685
1686
1687
/**
1688
 * Exclude notes (comments) on give_payment post type from showing in comment feeds
1689
 *
1690
 * @since 1.0
1691
 *
1692
 * @param string $where
1693
 * @param object $wp_comment_query WordPress Comment Query Object.
1694
 *
1695
 * @return string $where
1696
 */
1697
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...
1698
	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...
1699
1700
	$where .= $wpdb->prepare( ' AND comment_type != %s', 'give_payment_note' );
1701
1702
	return $where;
1703
}
1704
1705
add_filter( 'comment_feed_where', 'give_hide_payment_notes_from_feeds', 10, 2 );
1706
1707
1708 42
/**
1709 42
 * Remove Give Comments from the wp_count_comments function
1710 42
 *
1711
 * @access public
1712 42
 * @since  1.0
1713
 *
1714
 * @param array $stats   (empty from core filter).
1715
 * @param int   $post_id Post ID.
1716 42
 *
1717
 * @return array Array of comment counts.
1718 34
 */
1719 34
function give_remove_payment_notes_in_comment_counts( $stats, $post_id ) {
1720 34
	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...
1721 34
1722
	if ( 'index.php' != $pagenow ) {
1723 34
		return $stats;
1724
	}
1725
1726
	$post_id = (int) $post_id;
1727
1728
	if ( apply_filters( 'give_count_payment_notes_in_comments', false ) ) {
1729 34
		return $stats;
1730
	}
1731
1732 34
	$stats = wp_cache_get( "comments-{$post_id}", 'counts' );
1733
1734 34
	if ( false !== $stats ) {
1735
		return $stats;
1736 42
	}
1737
1738
	$where = 'WHERE comment_type != "give_payment_note"';
1739
1740
	if ( $post_id > 0 ) {
1741
		$where .= $wpdb->prepare( ' AND comment_post_ID = %d', $post_id );
1742
	}
1743
1744
	$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A );
1745
1746
	$total    = 0;
1747
	$approved = array(
1748
		'0'            => 'moderated',
1749
		'1'            => 'approved',
1750
		'spam'         => 'spam',
1751
		'trash'        => 'trash',
1752 52
		'post-trashed' => 'post-trashed',
1753
	);
1754 52
	foreach ( (array) $count as $row ) {
1755
		// Don't count post-trashed toward totals.
1756 32
		if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
1757
			$total += $row['num_comments'];
1758 32
		}
1759
		if ( isset( $approved[ $row['comment_approved'] ] ) ) {
1760 32
			$stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
1761
		}
1762
	}
1763 32
1764
	$stats['total_comments'] = $total;
1765 32
	foreach ( $approved as $key ) {
1766
		if ( empty( $stats[ $key ] ) ) {
1767 32
			$stats[ $key ] = 0;
1768
		}
1769 32
	}
1770
1771 32
	$stats = (object) $stats;
1772
	wp_cache_set( "comments-{$post_id}", $stats, 'counts' );
1773 52
1774
	return $stats;
1775
}
1776
1777
add_filter( 'wp_count_comments', 'give_remove_payment_notes_in_comment_counts', 10, 2 );
1778
1779
1780
/**
1781
 * Filter where older than one week
1782
 *
1783
 * @access public
1784
 * @since  1.0
1785
 *
1786
 * @param string $where Where clause.
1787
 *
1788
 * @return string $where Modified where clause.
1789
 */
1790
function give_filter_where_older_than_week( $where = '' ) {
1791
	// Payments older than one week.
1792
	$start = date( 'Y-m-d', strtotime( '-7 days' ) );
1793
	$where .= " AND post_date <= '{$start}'";
1794
1795
	return $where;
1796
}
1797
1798
1799
/**
1800
 * Get Payment Form ID.
1801
 *
1802
 * Retrieves the form title and appends the level name if present.
1803
 *
1804
 * @since 1.5
1805
 *
1806
 * @param array  $payment_meta Payment meta data.
1807
 * @param bool   $only_level   If set to true will only return the level name if multi-level enabled.
1808
 * @param string $separator    The separator between the .
1809
 *
1810
 * @return string $form_title Returns the full title if $only_level is false, otherwise returns the levels title.
1811
 */
1812
function give_get_payment_form_title( $payment_meta, $only_level = false, $separator = '' ) {
1813
1814
	$form_id    = isset( $payment_meta['form_id'] ) ? $payment_meta['form_id'] : 0;
1815
	$price_id   = isset( $payment_meta['price_id'] ) ? $payment_meta['price_id'] : null;
1816
	$form_title = isset( $payment_meta['form_title'] ) ? $payment_meta['form_title'] : '';
1817
1818
	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...
1819
		$form_title = '';
1820
	}
1821
1822
	//If multi-level, append to the form title.
1823
	if ( give_has_variable_prices( $form_id ) ) {
1824
1825
		//Only add separator if there is a form title.
1826
		if ( ! empty( $form_title ) ) {
1827
			$form_title .= ' ' . $separator . ' ';
1828
		}
1829
1830
		$form_title .= '<span class="donation-level-text-wrap">';
1831
1832
		if ( $price_id == 'custom' ) {
1833
			$custom_amount_text = get_post_meta( $form_id, '_give_custom_amount_text', true );
1834
			$form_title         .= ! empty( $custom_amount_text ) ? $custom_amount_text : __( 'Custom Amount', 'give' );
1835
		} else {
1836
			$form_title .= give_get_price_option_name( $form_id, $price_id );
1837
		}
1838
1839
		$form_title .= '</span>';
1840
1841
	}
1842
1843
	return apply_filters( 'give_get_payment_form_title', $form_title, $payment_meta );
1844
1845
}
1846
1847
/**
1848
 * Get Price ID
1849
 *
1850
 * Retrieves the Price ID when provided a proper form ID and price (donation) total
1851
 *
1852
 * @param int    $form_id Form ID.
1853
 * @param string $price   Price ID.
1854
 *
1855
 * @return string $price_id
1856
 */
1857
function give_get_price_id( $form_id, $price ) {
1858
1859
	$price_id = 0;
1860
1861
	if ( give_has_variable_prices( $form_id ) ) {
1862
1863
		$levels = maybe_unserialize( get_post_meta( $form_id, '_give_donation_levels', true ) );
1864
1865
		foreach ( $levels as $level ) {
1866
1867
			$level_amount = (float) give_sanitize_amount( $level['_give_amount'] );
1868
1869
			// Check that this indeed the recurring price.
1870
			if ( $level_amount == $price ) {
1871
1872
				$price_id = $level['_give_id']['level_id'];
1873
1874
			}
1875
		}
1876
	}
1877
1878
	return $price_id;
1879
1880
}
1881
1882
/**
1883
 * Get/Print give form dropdown html
1884
 *
1885
 * This function is wrapper to public method forms_dropdown of Give_HTML_Elements class to get/print form dropdown html.
1886
 * Give_HTML_Elements is defined in includes/class-give-html-elements.php.
1887
 *
1888
 * @since 1.6
1889
 *
1890
 * @param array $args Arguments for form dropdown.
1891
 * @param bool  $echo This parameter decides if print form dropdown html output or not.
1892
 *
1893
 * @return string|void
1894
 */
1895
function give_get_form_dropdown( $args = array(), $echo = false ) {
1896
	$form_dropdown_html = Give()->html->forms_dropdown( $args );
1897
1898
	if ( ! $echo ) {
1899
		return $form_dropdown_html;
1900
	}
1901
1902
	echo $form_dropdown_html;
1903
}
1904
1905
/**
1906
 * Get/Print give form variable price dropdown html
1907
 *
1908
 * @since 1.6
1909
 *
1910
 * @param array $args Arguments for form dropdown.
1911
 * @param bool  $echo This parameter decide if print form dropdown html output or not.
1912
 *
1913
 * @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...
1914
 */
1915
function give_get_form_variable_price_dropdown( $args = array(), $echo = false ) {
1916
1917
	// Check for give form id.
1918
	if ( empty( $args['id'] ) ) {
1919
		return false;
1920
	}
1921
1922
	$form = new Give_Donate_Form( $args['id'] );
1923
1924
	// Check if form has variable prices or not.
1925
	if ( ! $form->ID || ! $form->has_variable_prices() ) {
1926
		return false;
1927
	}
1928
1929
	$variable_prices        = $form->get_prices();
1930
	$variable_price_options = array();
1931
1932
	// Check if multi donation form support custom donation or not.
1933
	if ( $form->is_custom_price_mode() ) {
1934
		$variable_price_options['custom'] = _x( 'Custom', 'custom donation dropdown item', 'give' );
1935
	}
1936
1937
	// Get variable price and ID from variable price array.
1938
	foreach ( $variable_prices as $variable_price ) {
1939
		$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'] ) );
1940
	}
1941
1942
	// Update options.
1943
	$args = array_merge( $args, array( 'options' => $variable_price_options ) );
1944
1945
	// Generate select html.
1946
	$form_dropdown_html = Give()->html->select( $args );
1947
1948
	if ( ! $echo ) {
1949
		return $form_dropdown_html;
1950
	}
1951
1952
	echo $form_dropdown_html;
1953
}
1954
1955
/**
1956
 * Get the price_id from the payment meta.
1957
 *
1958
 * Some gateways use `give_price_id` and others were using just `price_id`;
1959
 * This checks for the difference and falls back to retrieving it from the form as a last resort.
1960
 *
1961
 * @since 1.8.6
1962
 *
1963
 * @param $payment_meta
1964
 *
1965
 * @return string
1966
 */
1967
function give_get_payment_meta_price_id( $payment_meta ) {
1968
1969
	if(isset($payment_meta['give_price_id'])) {
1970
		$price_id =  $payment_meta['give_price_id'];
1971
	} elseif(isset($payment_meta['price_id'])) {
1972
		$price_id =  $payment_meta['price_id'];
1973
	} else {
1974
		$price_id = give_get_price_id( $payment_meta['give_form_id'], $payment_meta['price'] );
1975
	}
1976
1977
	return apply_filters('give_get_payment_meta_price_id', $price_id);
1978
1979
}