Completed
Push — tests ( 7f3eb9...4036fb )
by Ravinder
55:16 queued 35:10
created

functions.php ➔ give_create_payment()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 16
nc 2
nop 1
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 46 and the first side effect is on line 14.

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

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

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

Loading history...
2
/**
3
 * Payment Functions
4
 *
5
 * @package     Give
6
 * @subpackage  Payments
7
 * @copyright   Copyright (c) 2016, WordImpress
8
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
9
 * @since       1.0
10
 */
11
12
// Exit if accessed directly.
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Get Payments
19
 *
20
 * Retrieve payments from the database.
21
 *
22
 * Since 1.0, this function takes an array of arguments, instead of individual
23
 * parameters. All of the original parameters remain, but can be passed in any
24
 * order via the array.
25
 *
26
 * @since 1.0
27
 *
28
 * @param array $args     {
29
 *                        Optional. Array of arguments passed to payments query.
30
 *
31
 * @type int    $offset   The number of payments to offset before retrieval.
32
 *                            Default is 0.
33
 * @type int    $number   The number of payments to query for. Use -1 to request all
34
 *                            payments. Default is 20.
35
 * @type string $mode     Default is 'live'.
36
 * @type string $order    Designates ascending or descending order of payments.
37
 *                            Accepts 'ASC', 'DESC'. Default is 'DESC'.
38
 * @type string $orderby  Sort retrieved payments by parameter. Default is 'ID'.
39
 * @type string $status   The status of the payments. Default is 'any'.
40
 * @type string $user     User. Default is null.
41
 * @type string $meta_key Custom field key. Default is null.
42
 * }
43
 *
44
 * @return object $payments Payments retrieved from the database
45
 */
46
function give_get_payments( $args = array() ) {
47
48
	// Fallback to post objects to ensure backwards compatibility.
49
	if ( ! isset( $args['output'] ) ) {
50
		$args['output'] = 'posts';
51
	}
52
53
	$args     = apply_filters( 'give_get_payments_args', $args );
54
	$payments = new Give_Payments_Query( $args );
55
56
	return $payments->get_payments();
57
}
58
59
/**
60
 * Retrieve payment by a given field
61
 *
62
 * @since  1.0
63
 *
64
 * @param  string $field The field to retrieve the payment with.
65
 * @param  mixed  $value The value for $field.
66
 *
67
 * @return mixed
68
 */
69
function give_get_payment_by( $field = '', $value = '' ) {
70
71
	if ( empty( $field ) || empty( $value ) ) {
72
		return false;
73
	}
74
75
	switch ( strtolower( $field ) ) {
76
77
		case 'id':
78
			$payment = new Give_Payment( $value );
79
			$id      = $payment->ID;
80
81
			if ( empty( $id ) ) {
82
				return false;
83
			}
84
85
			break;
86
87
		case 'key':
88
			$payment = give_get_payments( array(
89
				'meta_key'       => '_give_payment_purchase_key',
90
				'meta_value'     => $value,
91
				'posts_per_page' => 1,
92
				'fields'         => 'ids',
93
			) );
94
95
			if ( $payment ) {
96
				$payment = new Give_Payment( $payment[0] );
97
			}
98
99
			break;
100
101
		case 'payment_number':
102
			$payment = give_get_payments( array(
103
				'meta_key'       => '_give_payment_number',
104
				'meta_value'     => $value,
105
				'posts_per_page' => 1,
106
				'fields'         => 'ids',
107
			) );
108
109
			if ( $payment ) {
110
				$payment = new Give_Payment( $payment[0] );
111
			}
112
113
			break;
114
115
		default:
116
			return false;
117
	}
118
119
	if ( $payment ) {
120
		return $payment;
121
	}
122
123
	return false;
124
}
125
126
/**
127
 * Insert Payment
128
 *
129
 * @since  1.0
130
 *
131
 * @param  array $payment_data Arguments passed.
132
 *
133
 * @return int|bool Payment ID if payment is inserted, false otherwise.
134
 */
135
function give_insert_payment( $payment_data = array() ) {
136
137
	if ( empty( $payment_data ) ) {
138
		return false;
139
	}
140
141
	$payment    = new Give_Payment();
142
	$gateway    = ! empty( $payment_data['gateway'] ) ? $payment_data['gateway'] : '';
143
	$gateway    = empty( $gateway ) && isset( $_POST['give-gateway'] ) ? $_POST['give-gateway'] : $gateway;
144
	$form_id    = isset( $payment_data['give_form_id'] ) ? $payment_data['give_form_id'] : 0;
145
	$price_id   = isset( $payment_data['give_price_id'] ) ? $payment_data['give_price_id'] : give_get_price_id( $payment_data['give_form_id'], $payment_data['price'] );
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
		'fees'     => isset( $payment_data['fees'] ) ? $payment_data['fees'] : array(),
172
	);
173
174
	$payment->add_donation( $payment->form_id, $args );
175
176
	// Set date if present.
177
	if ( isset( $payment_data['post_date'] ) ) {
178
		$payment->date = $payment_data['post_date'];
179
	}
180
181
	// Handle sequential payments.
182
	if ( give_get_option( 'enable_sequential' ) ) {
183
		$number          = give_get_next_payment_number();
184
		$payment->number = give_format_payment_number( $number );
185
		update_option( 'give_last_payment_number', $number );
186
	}
187
188
	// 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
209
	// Return false if no payment was inserted.
210
	return false;
211
212
}
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
		'give_form_title' => $payment_data['post_data']['give-form-title'],
230
		'give_form_id'    => $form_id,
231
		'give_price_id'   => $price_id,
232
		'date'            => $payment_data['date'],
233
		'user_email'      => $payment_data['user_email'],
234
		'purchase_key'    => $payment_data['purchase_key'],
235
		'currency'        => give_get_currency(),
236
		'user_info'       => $payment_data['user_info'],
237
		'status'          => 'pending',
238
		'gateway'         => 'paypal',
239
	);
240
241
	// Record the pending payment.
242
	return give_insert_payment( $insert_payment_data );
243
}
244
245
/**
246
 * Updates a payment status.
247
 *
248
 * @since  1.0
249
 *
250
 * @param  int    $payment_id Payment ID.
251
 * @param  string $new_status New Payment Status. Default is 'publish'.
252
 *
253
 * @return bool
254
 */
255
function give_update_payment_status( $payment_id, $new_status = 'publish' ) {
256
257
	$payment         = new Give_Payment( $payment_id );
258
	$payment->status = $new_status;
259
	$updated         = $payment->save();
260
261
	return $updated;
262
}
263
264
265
/**
266
 * Deletes a Donation
267
 *
268
 * @since  1.0
269
 * @global      $give_logs
270
 *
271
 * @param  int  $payment_id      Payment ID (default: 0).
272
 * @param  bool $update_customer If we should update the customer stats (default:true).
273
 *
274
 * @return void
275
 */
276
function give_delete_purchase( $payment_id = 0, $update_customer = true ) {
277
	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...
278
279
	$payment     = new Give_Payment( $payment_id );
280
	$amount      = give_get_payment_amount( $payment_id );
281
	$status      = $payment->post_status;
282
	$customer_id = give_get_payment_customer_id( $payment_id );
283
	$customer    = new Give_Customer( $customer_id );
284
285
	// Only undo donations that aren't these statuses.
286
	$dont_undo_statuses = apply_filters( 'give_undo_purchase_statuses', array(
287
		'pending',
288
		'cancelled',
289
	) );
290
291
	if ( ! in_array( $status, $dont_undo_statuses ) ) {
292
		give_undo_purchase( false, $payment_id );
293
	}
294
295
	if ( $status == 'publish' ) {
296
297
		// Only decrease earnings if they haven't already been decreased (or were never increased for this payment).
298
		give_decrease_total_earnings( $amount );
299
		// Clear the This Month earnings (this_monththis_month is NOT a typo).
300
		delete_transient( md5( 'give_earnings_this_monththis_month' ) );
301
302
		if ( $customer->id && $update_customer ) {
303
304
			// Decrement the stats for the donor.
305
			$customer->decrease_purchase_count();
306
			$customer->decrease_value( $amount );
307
308
		}
309
	}
310
311
	/**
312
	 * Fires before deleting payment.
313
	 *
314
	 * @since 1.0
315
	 *
316
	 * @param int $payment_id Payment ID.
317
	 */
318
	do_action( 'give_payment_delete', $payment_id );
319
320
	if ( $customer->id && $update_customer ) {
321
322
		// Remove the payment ID from the donor.
323
		$customer->remove_payment( $payment_id );
324
325
	}
326
327
	// Remove the payment.
328
	wp_delete_post( $payment_id, true );
329
330
	// Remove related sale log entries.
331
	$give_logs->delete_logs(
332
		null,
333
		'sale',
334
		array(
335
			array(
336
				'key'   => '_give_log_payment_id',
337
				'value' => $payment_id,
338
			),
339
		)
340
	);
341
342
	/**
343
	 * Fires after payment deleted.
344
	 *
345
	 * @since 1.0
346
	 *
347
	 * @param int $payment_id Payment ID.
348
	 */
349
	do_action( 'give_payment_deleted', $payment_id );
350
}
351
352
/**
353
 * Undo Donation
354
 *
355
 * Undoes a donation, including the decrease of donations and earning stats.
356
 * Used for when refunding or deleting a donation.
357
 *
358
 * @since  1.0
359
 *
360
 * @param  int|bool $form_id    Form ID (default: false).
361
 * @param  int      $payment_id Payment ID.
362
 *
363
 * @return void
364
 */
365
function give_undo_purchase( $form_id = false, $payment_id ) {
366
367
	if ( ! empty( $form_id ) ) {
368
		$form_id = false;
369
		_give_deprected_argument( 'form_id', 'give_undo_purchase', '1.5' );
370
	}
371
372
	$payment = new Give_Payment( $payment_id );
373
374
	$maybe_decrease_earnings = apply_filters( 'give_decrease_earnings_on_undo', true, $payment, $payment->form_id );
375
	if ( true === $maybe_decrease_earnings ) {
376
		// Decrease earnings.
377
		give_decrease_earnings( $payment->form_id, $payment->total );
378
	}
379
380
	$maybe_decrease_sales = apply_filters( 'give_decrease_sales_on_undo', true, $payment, $payment->form_id );
381
	if ( true === $maybe_decrease_sales ) {
382
		// Decrease donation count.
383
		give_decrease_purchase_count( $payment->form_id );
384
	}
385
386
}
387
388
389
/**
390
 * Count Payments
391
 *
392
 * Returns the total number of payments recorded.
393
 *
394
 * @since  1.0
395
 *
396
 * @param  array $args Arguments passed.
397
 *
398
 * @return array $count Number of payments sorted by payment status.
399
 */
400
function give_count_payments( $args = array() ) {
401
402
	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...
403
404
	$defaults = array(
405
		'user'       => null,
406
		's'          => null,
407
		'start-date' => null,
408
		'end-date'   => null,
409
		'form_id'    => null,
410
	);
411
412
	$args = wp_parse_args( $args, $defaults );
413
414
	$select = 'SELECT p.post_status,count( * ) AS num_posts';
415
	$join   = '';
416
	$where  = "WHERE p.post_type = 'give_payment'";
417
418
	// Count payments for a specific user.
419
	if ( ! empty( $args['user'] ) ) {
420
421
		if ( is_email( $args['user'] ) ) {
422
			$field = 'email';
423
		} elseif ( is_numeric( $args['user'] ) ) {
424
			$field = 'id';
425
		} else {
426
			$field = '';
427
		}
428
429
		$join = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
430
431
		if ( ! empty( $field ) ) {
432
			$where .= "
433
				AND m.meta_key = '_give_payment_user_{$field}'
434
				AND m.meta_value = '{$args['user']}'";
435
		}
436
437
		// Count payments for a search.
438
	} elseif ( ! empty( $args['s'] ) ) {
439
440
		if ( is_email( $args['s'] ) || strlen( $args['s'] ) == 32 ) {
441
442
			if ( is_email( $args['s'] ) ) {
443
				$field = '_give_payment_user_email';
444
			} else {
445
				$field = '_give_payment_purchase_key';
446
			}
447
448
			$join = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
449
			$where .= $wpdb->prepare( '
450
                AND m.meta_key = %s
451
                AND m.meta_value = %s',
452
				$field,
453
				$args['s']
454
			);
455
456
		} elseif ( '#' == substr( $args['s'], 0, 1 ) ) {
457
458
			$search = str_replace( '#:', '', $args['s'] );
459
			$search = str_replace( '#', '', $search );
460
461
			$select = 'SELECT p2.post_status,count( * ) AS num_posts ';
462
			$join   = "LEFT JOIN $wpdb->postmeta m ON m.meta_key = '_give_log_payment_id' AND m.post_id = p.ID ";
463
			$join .= "INNER JOIN $wpdb->posts p2 ON m.meta_value = p2.ID ";
464
			$where = "WHERE p.post_type = 'give_log' ";
465
			$where .= $wpdb->prepare( 'AND p.post_parent = %d} ', $search );
466
467
		} elseif ( is_numeric( $args['s'] ) ) {
468
469
			$join = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
470
			$where .= $wpdb->prepare( "
471
				AND m.meta_key = '_give_payment_user_id'
472
				AND m.meta_value = %d",
473
				$args['s']
474
			);
475
476
		} else {
477
			$search = $wpdb->esc_like( $args['s'] );
478
			$search = '%' . $search . '%';
479
480
			$where .= $wpdb->prepare( 'AND ((p.post_title LIKE %s) OR (p.post_content LIKE %s))', $search, $search );
481
		}
482
	}
483
484
	if ( ! empty( $args['form_id'] ) && is_numeric( $args['form_id'] ) ) {
485
486
		$where .= $wpdb->prepare( ' AND p.post_parent = %d', $args['form_id'] );
487
488
	}
489
	// Limit payments count by date.
490
	if ( ! empty( $args['start-date'] ) && false !== strpos( $args['start-date'], '/' ) ) {
491
492
		$date_parts = explode( '/', $args['start-date'] );
493
		$month      = ! empty( $date_parts[0] ) && is_numeric( $date_parts[0] ) ? $date_parts[0] : 0;
494
		$day        = ! empty( $date_parts[1] ) && is_numeric( $date_parts[1] ) ? $date_parts[1] : 0;
495
		$year       = ! empty( $date_parts[2] ) && is_numeric( $date_parts[2] ) ? $date_parts[2] : 0;
496
497
		$is_date = checkdate( $month, $day, $year );
498
		if ( false !== $is_date ) {
499
500
			$date = new DateTime( $args['start-date'] );
501
			$where .= $wpdb->prepare( " AND p.post_date >= '%s'", $date->format( 'Y-m-d' ) );
502
503
		}
504
505
		// Fixes an issue with the payments list table counts when no end date is specified (partiy with stats class).
506
		if ( empty( $args['end-date'] ) ) {
507
			$args['end-date'] = $args['start-date'];
508
		}
509
	}
510
511
	if ( ! empty( $args['end-date'] ) && false !== strpos( $args['end-date'], '/' ) ) {
512
513
		$date_parts = explode( '/', $args['end-date'] );
514
515
		$month = ! empty( $date_parts[0] ) ? $date_parts[0] : 0;
516
		$day   = ! empty( $date_parts[1] ) ? $date_parts[1] : 0;
517
		$year  = ! empty( $date_parts[2] ) ? $date_parts[2] : 0;
518
519
		$is_date = checkdate( $month, $day, $year );
520
		if ( false !== $is_date ) {
521
522
			$date = new DateTime( $args['end-date'] );
523
			$where .= $wpdb->prepare( " AND p.post_date <= '%s'", $date->format( 'Y-m-d' ) );
524
525
		}
526
	}
527
528
	$where = apply_filters( 'give_count_payments_where', $where );
529
	$join  = apply_filters( 'give_count_payments_join', $join );
530
531
	$query = "$select
532
		FROM $wpdb->posts p
533
		$join
534
		$where
535
		GROUP BY p.post_status
536
	";
537
538
	$cache_key = md5( $query );
539
540
	$count = wp_cache_get( $cache_key, 'counts' );
541
	if ( false !== $count ) {
542
		return $count;
543
	}
544
545
	$count = $wpdb->get_results( $query, ARRAY_A );
546
547
	$stats    = array();
548
	$statuses = get_post_stati();
549
	if ( isset( $statuses['private'] ) && empty( $args['s'] ) ) {
550
		unset( $statuses['private'] );
551
	}
552
553
	foreach ( $statuses as $state ) {
554
		$stats[ $state ] = 0;
555
	}
556
557
	foreach ( (array) $count as $row ) {
558
559
		if ( 'private' == $row['post_status'] && empty( $args['s'] ) ) {
560
			continue;
561
		}
562
563
		$stats[ $row['post_status'] ] = $row['num_posts'];
564
	}
565
566
	$stats = (object) $stats;
567
	wp_cache_set( $cache_key, $stats, 'counts' );
568
569
	return $stats;
570
}
571
572
573
/**
574
 * Check For Existing Payment
575
 *
576
 * @since  1.0
577
 *
578
 * @param  int $payment_id Payment ID
579
 *
580
 * @return bool $exists True if payment exists, false otherwise.
581
 */
582
function give_check_for_existing_payment( $payment_id ) {
583
	$exists  = false;
584
	$payment = new Give_Payment( $payment_id );
585
586
	if ( $payment_id === $payment->ID && 'publish' === $payment->status ) {
587
		$exists = true;
588
	}
589
590
	return $exists;
591
}
592
593
/**
594
 * Get Payment Status
595
 *
596
 * @since 1.0
597
 *
598
 * @param WP_Post|Give_Payment $payment      Payment object.
599
 * @param bool                 $return_label Whether to return the translated status label
600
 *                                           instead of status value. Default false.
601
 *
602
 * @return bool|mixed True if payment status exists, false otherwise.
603
 */
604
function give_get_payment_status( $payment, $return_label = false ) {
605
606
	if ( ! is_object( $payment ) || ! isset( $payment->post_status ) ) {
607
		return false;
608
	}
609
610
	$statuses = give_get_payment_statuses();
611
612
	if ( ! is_array( $statuses ) || empty( $statuses ) ) {
613
		return false;
614
	}
615
616
	// Get payment object if no already given.
617
	$payment = $payment instanceof Give_Payment ? $payment : new Give_Payment( $payment->ID );
618
619
	if ( array_key_exists( $payment->status, $statuses ) ) {
620
		if ( true === $return_label ) {
621
			// Return translated status label.
622
			return $statuses[ $payment->status ];
623
		} else {
624
			// Account that our 'publish' status is labeled 'Complete'
625
			$post_status = 'publish' == $payment->status ? 'Complete' : $payment->post_status;
626
627
			// Make sure we're matching cases, since they matter
628
			return array_search( strtolower( $post_status ), array_map( 'strtolower', $statuses ) );
629
		}
630
	}
631
632
	return false;
633
}
634
635
/**
636
 * Retrieves all available statuses for payments.
637
 *
638
 * @since  1.0
639
 *
640
 * @return array $payment_status All the available payment statuses.
641
 */
642
function give_get_payment_statuses() {
643
	$payment_statuses = array(
644
		'pending'     => __( 'Pending', 'give' ),
645
		'publish'     => __( 'Complete', 'give' ),
646
		'refunded'    => __( 'Refunded', 'give' ),
647
		'failed'      => __( 'Failed', 'give' ),
648
		'cancelled'   => __( 'Cancelled', 'give' ),
649
		'abandoned'   => __( 'Abandoned', 'give' ),
650
		'preapproval' => __( 'Pre-Approved', 'give' ),
651
		'revoked'     => __( 'Revoked', 'give' ),
652
	);
653
654
	return apply_filters( 'give_payment_statuses', $payment_statuses );
655
}
656
657
/**
658
 * Get Payment Status Keys
659
 *
660
 * Retrieves keys for all available statuses for payments
661
 *
662
 * @since  1.0
663
 *
664
 * @return array $payment_status All the available payment statuses.
665
 */
666
function give_get_payment_status_keys() {
667
	$statuses = array_keys( give_get_payment_statuses() );
668
	asort( $statuses );
669
670
	return array_values( $statuses );
671
}
672
673
/**
674
 * Get Earnings By Date
675
 *
676
 * @since  1.0
677
 *
678
 * @param  int $day       Day number. Default is null.
679
 * @param  int $month_num Month number. Default is null.
680
 * @param  int $year      Year number. Default is null.
681
 * @param  int $hour      Hour number. Default is null.
682
 *
683
 * @return int $earnings  Earnings
684
 */
685
function give_get_earnings_by_date( $day = null, $month_num, $year = null, $hour = null ) {
686
687
	// This is getting deprecated soon. Use Give_Payment_Stats with the get_earnings() method instead.
688
	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...
689
690
	$args = array(
691
		'post_type'              => 'give_payment',
692
		'nopaging'               => true,
693
		'year'                   => $year,
694
		'monthnum'               => $month_num,
695
		'post_status'            => array( 'publish' ),
696
		'fields'                 => 'ids',
697
		'update_post_term_cache' => false,
698
	);
699
	if ( ! empty( $day ) ) {
700
		$args['day'] = $day;
701
	}
702
703
	if ( ! empty( $hour ) ) {
704
		$args['hour'] = $hour;
705
	}
706
707
	$args = apply_filters( 'give_get_earnings_by_date_args', $args );
708
	$key  = 'give_stats_' . substr( md5( serialize( $args ) ), 0, 15 );
709
710
	if ( ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'give-refresh-reports' ) ) {
711
		$earnings = false;
712
	} else {
713
		$earnings = get_transient( $key );
714
	}
715
716
	if ( false === $earnings ) {
717
		$sales    = get_posts( $args );
718
		$earnings = 0;
719
		if ( $sales ) {
720
			$sales = implode( ',', $sales );
721
722
			$earnings = $wpdb->get_var( "SELECT SUM(meta_value) FROM $wpdb->postmeta WHERE meta_key = '_give_payment_total' AND post_id IN ({$sales})" );
723
724
		}
725
		// Cache the results for one hour.
726
		set_transient( $key, $earnings, HOUR_IN_SECONDS );
727
	}
728
729
	return round( $earnings, 2 );
730
}
731
732
/**
733
 * Get Donations (sales) By Date
734
 *
735
 * @since  1.0
736
 *
737
 * @param  int $day       Day number. Default is null.
738
 * @param  int $month_num Month number. Default is null.
739
 * @param  int $year      Year number. Default is null.
740
 * @param  int $hour      Hour number. Default is null.
741
 *
742
 * @return int $count     Sales
743
 */
744
function give_get_sales_by_date( $day = null, $month_num = null, $year = null, $hour = null ) {
745
746
	// This is getting deprecated soon. Use Give_Payment_Stats with the get_sales() method instead.
747
	$args = array(
748
		'post_type'              => 'give_payment',
749
		'nopaging'               => true,
750
		'year'                   => $year,
751
		'fields'                 => 'ids',
752
		'post_status'            => array( 'publish' ),
753
		'update_post_meta_cache' => false,
754
		'update_post_term_cache' => false,
755
	);
756
757
	$show_free = apply_filters( 'give_sales_by_date_show_free', true, $args );
758
759
	if ( false === $show_free ) {
760
		$args['meta_query'] = array(
761
			array(
762
				'key'     => '_give_payment_total',
763
				'value'   => 0,
764
				'compare' => '>',
765
				'type'    => 'NUMERIC',
766
			),
767
		);
768
	}
769
770
	if ( ! empty( $month_num ) ) {
771
		$args['monthnum'] = $month_num;
772
	}
773
774
	if ( ! empty( $day ) ) {
775
		$args['day'] = $day;
776
	}
777
778
	if ( ! empty( $hour ) ) {
779
		$args['hour'] = $hour;
780
	}
781
782
	$args = apply_filters( 'give_get_sales_by_date_args', $args );
783
784
	$key = 'give_stats_' . substr( md5( serialize( $args ) ), 0, 15 );
785
786
	if ( ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'give-refresh-reports' ) ) {
787
		$count = false;
788
	} else {
789
		$count = get_transient( $key );
790
	}
791
792
	if ( false === $count ) {
793
		$sales = new WP_Query( $args );
794
		$count = (int) $sales->post_count;
795
		// Cache the results for one hour.
796
		set_transient( $key, $count, HOUR_IN_SECONDS );
797
	}
798
799
	return $count;
800
}
801
802
/**
803
 * Checks whether a payment has been marked as complete.
804
 *
805
 * @since  1.0
806
 *
807
 * @param  int $payment_id Payment ID to check against.
808
 *
809
 * @return bool $ret True if complete, false otherwise.
810
 */
811
function give_is_payment_complete( $payment_id ) {
812
	$payment = new Give_Payment( $payment_id );
813
814
	$ret = false;
815
816
	if ( $payment->ID > 0 ) {
817
818
		if ( (int) $payment_id === (int) $payment->ID && 'publish' == $payment->status ) {
819
			$ret = true;
820
		}
821
	}
822
823
	return apply_filters( 'give_is_payment_complete', $ret, $payment_id, $payment->post_status );
824
}
825
826
/**
827
 * Get Total Donations.
828
 *
829
 * @since  1.0
830
 *
831
 * @return int $count Total sales.
832
 */
833
function give_get_total_sales() {
834
835
	$payments = give_count_payments();
836
837
	return $payments->publish;
838
}
839
840
/**
841
 * Get Total Earnings
842
 *
843
 * @since  1.0
844
 *
845
 * @return float $total Total earnings.
846
 */
847
function give_get_total_earnings() {
848
849
	$total = get_option( 'give_earnings_total', false );
850
851
	// If no total stored in DB, use old method of calculating total earnings.
852
	if ( false === $total ) {
853
854
		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...
855
856
		$total = get_transient( 'give_earnings_total' );
857
858
		if ( false === $total ) {
859
860
			$total = (float) 0;
861
862
			$args = apply_filters( 'give_get_total_earnings_args', array(
863
				'offset' => 0,
864
				'number' => - 1,
865
				'status' => array( 'publish' ),
866
				'fields' => 'ids',
867
			) );
868
869
			$payments = give_get_payments( $args );
870
			if ( $payments ) {
871
872
				/**
873
				 * If performing a donation, we need to skip the very last payment in the database,
874
				 * since it calls give_increase_total_earnings() on completion,
875
				 * which results in duplicated earnings for the very first donation.
876
				 */
877
				if ( did_action( 'give_update_payment_status' ) ) {
878
					array_pop( $payments );
879
				}
880
881
				if ( ! empty( $payments ) ) {
882
					$payments = implode( ',', $payments );
883
					$total += $wpdb->get_var( "SELECT SUM(meta_value) FROM $wpdb->postmeta WHERE meta_key = '_give_payment_total' AND post_id IN({$payments})" );
884
				}
885
			}
886
887
			// Cache results for 1 day. This cache is cleared automatically when a payment is made.
888
			set_transient( 'give_earnings_total', $total, 86400 );
889
890
			// Store the total for the first time.
891
			update_option( 'give_earnings_total', $total );
892
		}
893
	}
894
895
	if ( $total < 0 ) {
896
		$total = 0; // Don't ever show negative earnings.
897
	}
898
899
	return apply_filters( 'give_total_earnings', round( $total, give_currency_decimal_filter() ) );
900
}
901
902
/**
903
 * Increase the Total Earnings
904
 *
905
 * @since  1.0
906
 *
907
 * @param  int $amount   The amount you would like to increase the total earnings by.
908
 *                       Default is 0.
909
 *
910
 * @return float $total  Total earnings.
911
 */
912
function give_increase_total_earnings( $amount = 0 ) {
913
	$total = give_get_total_earnings();
914
	$total += $amount;
915
	update_option( 'give_earnings_total', $total );
916
917
	return $total;
918
}
919
920
/**
921
 * Decrease the Total Earnings
922
 *
923
 * @since 1.0
924
 *
925
 * @param int $amount The amount you would like to decrease the total earnings by.
926
 *
927
 * @return float $total Total earnings.
928
 */
929
function give_decrease_total_earnings( $amount = 0 ) {
930
	$total = give_get_total_earnings();
931
	$total -= $amount;
932
	if ( $total < 0 ) {
933
		$total = 0;
934
	}
935
	update_option( 'give_earnings_total', $total );
936
937
	return $total;
938
}
939
940
/**
941
 * Get Payment Meta for a specific Payment
942
 *
943
 * @since 1.0
944
 *
945
 * @param int    $payment_id Payment ID.
946
 * @param string $meta_key   The meta key to pull.
947
 * @param bool   $single     Pull single meta entry or as an object.
948
 *
949
 * @return mixed $meta Payment Meta.
950
 */
951
function give_get_payment_meta( $payment_id = 0, $meta_key = '_give_payment_meta', $single = true ) {
952
	$payment = new Give_Payment( $payment_id );
953
954
	return $payment->get_meta( $meta_key, $single );
955
}
956
957
/**
958
 * Update the meta for a payment
959
 *
960
 * @param  int    $payment_id Payment ID.
961
 * @param  string $meta_key   Meta key to update.
962
 * @param  string $meta_value Value to update to.
963
 * @param  string $prev_value Previous value.
964
 *
965
 * @return mixed Meta ID if successful, false if unsuccessful.
966
 */
967
function give_update_payment_meta( $payment_id = 0, $meta_key = '', $meta_value = '', $prev_value = '' ) {
968
	$payment = new Give_Payment( $payment_id );
969
970
	return $payment->update_meta( $meta_key, $meta_value, $prev_value );
971
}
972
973
/**
974
 * Get the user_info Key from Payment Meta
975
 *
976
 * @since 1.0
977
 *
978
 * @param int $payment_id Payment ID.
979
 *
980
 * @return string $user_info User Info Meta Values.
981
 */
982
function give_get_payment_meta_user_info( $payment_id ) {
983
	$payment = new Give_Payment( $payment_id );
984
985
	return $payment->user_info;
986
}
987
988
/**
989
 * Get the donations Key from Payment Meta
990
 *
991
 * Retrieves the form_id from a (Previously titled give_get_payment_meta_donations)
992
 *
993
 * @since 1.0
994
 *
995
 * @param int $payment_id Payment ID.
996
 *
997
 * @return int $form_id Form ID.
998
 */
999
function give_get_payment_form_id( $payment_id ) {
1000
	$payment = new Give_Payment( $payment_id );
1001
1002
	return $payment->form_id;
1003
}
1004
1005
/**
1006
 * Get the user email associated with a payment
1007
 *
1008
 * @since 1.0
1009
 *
1010
 * @param int $payment_id Payment ID.
1011
 *
1012
 * @return string $email User email.
1013
 */
1014
function give_get_payment_user_email( $payment_id ) {
1015
	$payment = new Give_Payment( $payment_id );
1016
1017
	return $payment->email;
1018
}
1019
1020
/**
1021
 * Is the payment provided associated with a user account
1022
 *
1023
 * @since  1.3
1024
 *
1025
 * @param  int $payment_id The payment ID.
1026
 *
1027
 * @return bool $is_guest_payment If the payment is associated with a user (false) or not (true)
1028
 */
1029
function give_is_guest_payment( $payment_id ) {
1030
	$payment_user_id  = give_get_payment_user_id( $payment_id );
1031
	$is_guest_payment = ! empty( $payment_user_id ) && $payment_user_id > 0 ? false : true;
1032
1033
	return (bool) apply_filters( 'give_is_guest_payment', $is_guest_payment, $payment_id );
1034
}
1035
1036
/**
1037
 * Get the user ID associated with a payment
1038
 *
1039
 * @since 1.3
1040
 *
1041
 * @param int $payment_id Payment ID.
1042
 *
1043
 * @return int $user_id User ID.
1044
 */
1045
function give_get_payment_user_id( $payment_id ) {
1046
	$payment = new Give_Payment( $payment_id );
1047
1048
	return $payment->user_id;
1049
}
1050
1051
/**
1052
 * Get the donor ID associated with a payment
1053
 *
1054
 * @since 1.0
1055
 *
1056
 * @param int $payment_id Payment ID.
1057
 *
1058
 * @return int $customer_id Customer ID.
1059
 */
1060
function give_get_payment_customer_id( $payment_id ) {
1061
	$payment = new Give_Payment( $payment_id );
1062
1063
	return $payment->customer_id;
1064
}
1065
1066
/**
1067
 * Get the IP address used to make a donation
1068
 *
1069
 * @since 1.0
1070
 *
1071
 * @param int $payment_id Payment ID.
1072
 *
1073
 * @return string $ip User IP.
1074
 */
1075
function give_get_payment_user_ip( $payment_id ) {
1076
	$payment = new Give_Payment( $payment_id );
1077
1078
	return $payment->ip;
1079
}
1080
1081
/**
1082
 * Get the date a payment was completed
1083
 *
1084
 * @since 1.0
1085
 *
1086
 * @param int $payment_id Payment ID.
1087
 *
1088
 * @return string $date The date the payment was completed.
1089
 */
1090
function give_get_payment_completed_date( $payment_id = 0 ) {
1091
	$payment = new Give_Payment( $payment_id );
1092
1093
	return $payment->completed_date;
1094
}
1095
1096
/**
1097
 * Get the gateway associated with a payment
1098
 *
1099
 * @since 1.0
1100
 *
1101
 * @param int $payment_id Payment ID.
1102
 *
1103
 * @return string $gateway Gateway.
1104
 */
1105
function give_get_payment_gateway( $payment_id ) {
1106
	$payment = new Give_Payment( $payment_id );
1107
1108
	return $payment->gateway;
1109
}
1110
1111
/**
1112
 * Get the currency code a payment was made in
1113
 *
1114
 * @since 1.0
1115
 *
1116
 * @param int $payment_id Payment ID.
1117
 *
1118
 * @return string $currency The currency code.
1119
 */
1120
function give_get_payment_currency_code( $payment_id = 0 ) {
1121
	$payment = new Give_Payment( $payment_id );
1122
1123
	return $payment->currency;
1124
}
1125
1126
/**
1127
 * Get the currency name a payment was made in
1128
 *
1129
 * @since 1.0
1130
 *
1131
 * @param int $payment_id Payment ID.
1132
 *
1133
 * @return string $currency The currency name.
1134
 */
1135
function give_get_payment_currency( $payment_id = 0 ) {
1136
	$currency = give_get_payment_currency_code( $payment_id );
1137
1138
	return apply_filters( 'give_payment_currency', give_get_currency_name( $currency ), $payment_id );
1139
}
1140
1141
/**
1142
 * Get the key for a donation
1143
 *
1144
 * @since 1.0
1145
 *
1146
 * @param int $payment_id Payment ID.
1147
 *
1148
 * @return string $key Donation key.
1149
 */
1150
function give_get_payment_key( $payment_id = 0 ) {
1151
	$payment = new Give_Payment( $payment_id );
1152
1153
	return $payment->key;
1154
}
1155
1156
/**
1157
 * Get the payment order number
1158
 *
1159
 * This will return the payment ID if sequential order numbers are not enabled or the order number does not exist
1160
 *
1161
 * @since 1.0
1162
 *
1163
 * @param int $payment_id Payment ID.
1164
 *
1165
 * @return string $number Payment order number.
1166
 */
1167
function give_get_payment_number( $payment_id = 0 ) {
1168
	$payment = new Give_Payment( $payment_id );
1169
1170
	return $payment->number;
1171
}
1172
1173
/**
1174
 * Formats the payment number with the prefix and postfix
1175
 *
1176
 * @since  1.3
1177
 *
1178
 * @param  int $number The payment number to format.
1179
 *
1180
 * @return string      The formatted payment number.
1181
 */
1182
function give_format_payment_number( $number ) {
1183
1184
	if ( ! give_get_option( 'enable_sequential' ) ) {
1185
		return $number;
1186
	}
1187
1188
	if ( ! is_numeric( $number ) ) {
1189
		return $number;
1190
	}
1191
1192
	$prefix  = give_get_option( 'sequential_prefix' );
1193
	$number  = absint( $number );
1194
	$postfix = give_get_option( 'sequential_postfix' );
1195
1196
	$formatted_number = $prefix . $number . $postfix;
1197
1198
	return apply_filters( 'give_format_payment_number', $formatted_number, $prefix, $number, $postfix );
1199
}
1200
1201
/**
1202
 * Gets the next available order number
1203
 *
1204
 * This is used when inserting a new payment
1205
 *
1206
 * @since 1.0
1207
 * @return string $number The next available payment number.
1208
 */
1209
function give_get_next_payment_number() {
1210
1211
	if ( ! give_get_option( 'enable_sequential' ) ) {
1212
		return false;
1213
	}
1214
1215
	$number           = get_option( 'give_last_payment_number' );
1216
	$start            = give_get_option( 'sequential_start', 1 );
1217
	$increment_number = true;
1218
1219
	if ( false !== $number ) {
1220
1221
		if ( empty( $number ) ) {
1222
1223
			$number           = $start;
1224
			$increment_number = false;
1225
1226
		}
1227
	} else {
1228
1229
		// This case handles the first addition of the new option, as well as if it get's deleted for any reason.
1230
		$payments     = new Give_Payments_Query( array(
1231
			'number'  => 1,
1232
			'order'   => 'DESC',
1233
			'orderby' => 'ID',
1234
			'output'  => 'posts',
1235
			'fields'  => 'ids',
1236
		) );
1237
		$last_payment = $payments->get_payments();
1238
1239
		if ( ! empty( $last_payment ) ) {
1240
1241
			$number = give_get_payment_number( $last_payment[0] );
1242
1243
		}
1244
1245
		if ( ! empty( $number ) && $number !== (int) $last_payment[0] ) {
1246
1247
			$number = give_remove_payment_prefix_postfix( $number );
1248
1249
		} else {
1250
1251
			$number           = $start;
1252
			$increment_number = false;
1253
		}
1254
	}
1255
1256
	$increment_number = apply_filters( 'give_increment_payment_number', $increment_number, $number );
1257
1258
	if ( $increment_number ) {
1259
		$number ++;
1260
	}
1261
1262
	return apply_filters( 'give_get_next_payment_number', $number );
1263
}
1264
1265
/**
1266
 * Given a given a number, remove the pre/postfix
1267
 *
1268
 * @since  1.3
1269
 *
1270
 * @param  string $number The formatted Current Number to increment.
1271
 *
1272
 * @return string The new Payment number without prefix and postfix.
1273
 */
1274
function give_remove_payment_prefix_postfix( $number ) {
1275
1276
	$prefix  = give_get_option( 'sequential_prefix' );
1277
	$postfix = give_get_option( 'sequential_postfix' );
1278
1279
	// Remove prefix.
1280
	$number = preg_replace( '/' . $prefix . '/', '', $number, 1 );
1281
1282
	// Remove the postfix.
1283
	$length      = strlen( $number );
1284
	$postfix_pos = strrpos( $number, $postfix );
1285
	if ( false !== $postfix_pos ) {
1286
		$number = substr_replace( $number, '', $postfix_pos, $length );
1287
	}
1288
1289
	// Ensure it's a whole number.
1290
	$number = intval( $number );
1291
1292
	return apply_filters( 'give_remove_payment_prefix_postfix', $number, $prefix, $postfix );
1293
1294
}
1295
1296
1297
/**
1298
 * Get Payment Amount
1299
 *
1300
 * Get the fully formatted payment amount. The payment amount is retrieved using give_get_payment_amount() and is then sent through give_currency_filter() and  give_format_amount() to format the amount correctly.
1301
 *
1302
 * @since       1.0
1303
 *
1304
 * @param int $payment_id Payment ID.
1305
 *
1306
 * @return string $amount Fully formatted payment amount.
1307
 */
1308
function give_payment_amount( $payment_id = 0 ) {
1309
	$amount = give_get_payment_amount( $payment_id );
1310
1311
	return give_currency_filter( give_format_amount( $amount ), give_get_payment_currency_code( $payment_id ) );
1312
}
1313
1314
/**
1315
 * Get the amount associated with a payment
1316
 *
1317
 * @access public
1318
 * @since  1.0
1319
 *
1320
 * @param int $payment_id Payment ID.
1321
 *
1322
 * @return mixed|void
1323
 */
1324
function give_get_payment_amount( $payment_id ) {
1325
1326
	$payment = new Give_Payment( $payment_id );
1327
1328
	return apply_filters( 'give_payment_amount', floatval( $payment->total ), $payment_id );
1329
}
1330
1331
/**
1332
 * Payment Subtotal
1333
 *
1334
 * Retrieves subtotal for payment (this is the amount before fees) and then returns a full formatted amount. This function essentially calls give_get_payment_subtotal()
1335
 *
1336
 * @since 1.5
1337
 *
1338
 * @param int $payment_id Payment ID.
1339
 *
1340
 * @see   give_get_payment_subtotal()
1341
 *
1342
 * @return array Fully formatted payment subtotal.
1343
 */
1344
function give_payment_subtotal( $payment_id = 0 ) {
1345
	$subtotal = give_get_payment_subtotal( $payment_id );
1346
1347
	return give_currency_filter( give_format_amount( $subtotal ), give_get_payment_currency_code( $payment_id ) );
1348
}
1349
1350
/**
1351
 * Get Payment Subtotal
1352
 *
1353
 * Retrieves subtotal for payment (this is the amount before fees) and then returns a non formatted amount.
1354
 *
1355
 * @since 1.5
1356
 *
1357
 * @param int $payment_id Payment ID.
1358
 *
1359
 * @return float $subtotal Subtotal for payment (non formatted).
1360
 */
1361
function give_get_payment_subtotal( $payment_id = 0 ) {
1362
	$payment = new G_Payment( $payment_id );
1363
1364
	return $payment->subtotal;
1365
}
1366
1367
/**
1368
 * Retrieves arbitrary fees for the payment
1369
 *
1370
 * @since 1.5
1371
 *
1372
 * @param int    $payment_id Payment ID.
1373
 * @param string $type       Fee type.
1374
 *
1375
 * @return mixed array if payment fees found, false otherwise.
1376
 */
1377
function give_get_payment_fees( $payment_id = 0, $type = 'all' ) {
1378
	$payment = new Give_Payment( $payment_id );
1379
1380
	return $payment->get_fees( $type );
1381
}
1382
1383
/**
1384
 * Retrieves the donation ID
1385
 *
1386
 * @since  1.0
1387
 *
1388
 * @param int $payment_id Payment ID.
1389
 *
1390
 * @return string The donation ID.
1391
 */
1392
function give_get_payment_transaction_id( $payment_id = 0 ) {
1393
	$payment = new Give_Payment( $payment_id );
1394
1395
	return $payment->transaction_id;
1396
}
1397
1398
/**
1399
 * Sets a Transaction ID in post meta for the given Payment ID.
1400
 *
1401
 * @since  1.0
1402
 *
1403
 * @param int    $payment_id     Payment ID.
1404
 * @param string $transaction_id The transaction ID from the gateway.
1405
 *
1406
 * @return bool|mixed
1407
 */
1408
function give_set_payment_transaction_id( $payment_id = 0, $transaction_id = '' ) {
1409
1410
	if ( empty( $payment_id ) || empty( $transaction_id ) ) {
1411
		return false;
1412
	}
1413
1414
	$transaction_id = apply_filters( 'give_set_payment_transaction_id', $transaction_id, $payment_id );
1415
1416
	return give_update_payment_meta( $payment_id, '_give_payment_transaction_id', $transaction_id );
1417
}
1418
1419
/**
1420
 * Retrieve the donation ID based on the key
1421
 *
1422
 * @since 1.0
1423
 * @global object $wpdb Used to query the database using the WordPress Database API.
1424
 *
1425
 * @param string  $key  the key to search for.
1426
 *
1427
 * @return int $purchase Donation ID.
1428
 */
1429
function give_get_purchase_id_by_key( $key ) {
1430
	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...
1431
1432
	$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 ) );
1433
1434
	if ( $purchase != null ) {
1435
		return $purchase;
1436
	}
1437
1438
	return 0;
1439
}
1440
1441
1442
/**
1443
 * Retrieve the donation ID based on the transaction ID
1444
 *
1445
 * @since 1.3
1446
 * @global object $wpdb Used to query the database using the WordPress Database API.
1447
 *
1448
 * @param string  $key  The transaction ID to search for.
1449
 *
1450
 * @return int $purchase Donation ID.
1451
 */
1452
function give_get_purchase_id_by_transaction_id( $key ) {
1453
	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...
1454
1455
	$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 ) );
1456
1457
	if ( $purchase != null ) {
1458
		return $purchase;
1459
	}
1460
1461
	return 0;
1462
}
1463
1464
/**
1465
 * Retrieve all notes attached to a donation
1466
 *
1467
 * @since 1.0
1468
 *
1469
 * @param int    $payment_id The donation ID to retrieve notes for.
1470
 * @param string $search     Search for notes that contain a search term.
1471
 *
1472
 * @return array $notes Donation Notes
1473
 */
1474
function give_get_payment_notes( $payment_id = 0, $search = '' ) {
1475
1476
	if ( empty( $payment_id ) && empty( $search ) ) {
1477
		return false;
1478
	}
1479
1480
	remove_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1481
	remove_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10 );
1482
1483
	$notes = get_comments( array( 'post_id' => $payment_id, 'order' => 'ASC', 'search' => $search ) );
1484
1485
	add_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1486
	add_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10, 2 );
1487
1488
	return $notes;
1489
}
1490
1491
1492
/**
1493
 * Add a note to a payment
1494
 *
1495
 * @since 1.0
1496
 *
1497
 * @param int    $payment_id The payment ID to store a note for.
1498
 * @param string $note       The note to store.
1499
 *
1500
 * @return int The new note ID
1501
 */
1502
function give_insert_payment_note( $payment_id = 0, $note = '' ) {
1503
	if ( empty( $payment_id ) ) {
1504
		return false;
1505
	}
1506
1507
	/**
1508
	 * Fires before inserting payment note.
1509
	 *
1510
	 * @since 1.0
1511
	 *
1512
	 * @param int    $payment_id Payment ID.
1513
	 * @param string $note       The note.
1514
	 */
1515
	do_action( 'give_pre_insert_payment_note', $payment_id, $note );
1516
1517
	$note_id = wp_insert_comment( wp_filter_comment( array(
1518
		'comment_post_ID'      => $payment_id,
1519
		'comment_content'      => $note,
1520
		'user_id'              => is_admin() ? get_current_user_id() : 0,
1521
		'comment_date'         => current_time( 'mysql' ),
1522
		'comment_date_gmt'     => current_time( 'mysql', 1 ),
1523
		'comment_approved'     => 1,
1524
		'comment_parent'       => 0,
1525
		'comment_author'       => '',
1526
		'comment_author_IP'    => '',
1527
		'comment_author_url'   => '',
1528
		'comment_author_email' => '',
1529
		'comment_type'         => 'give_payment_note',
1530
1531
	) ) );
1532
1533
	/**
1534
	 * Fires after payment note inserted.
1535
	 *
1536
	 * @since 1.0
1537
	 *
1538
	 * @param int    $note_id    Note ID.
1539
	 * @param int    $payment_id Payment ID.
1540
	 * @param string $note       The note.
1541
	 */
1542
	do_action( 'give_insert_payment_note', $note_id, $payment_id, $note );
1543
1544
	return $note_id;
1545
}
1546
1547
/**
1548
 * Deletes a payment note
1549
 *
1550
 * @since 1.0
1551
 *
1552
 * @param int $comment_id The comment ID to delete.
1553
 * @param int $payment_id The payment ID the note is connected to.
1554
 *
1555
 * @return bool True on success, false otherwise.
1556
 */
1557
function give_delete_payment_note( $comment_id = 0, $payment_id = 0 ) {
1558
	if ( empty( $comment_id ) ) {
1559
		return false;
1560
	}
1561
1562
	/**
1563
	 * Fires before deleting donation note.
1564
	 *
1565
	 * @since 1.0
1566
	 *
1567
	 * @param int $comment_id Note ID.
1568
	 * @param int $payment_id Payment ID.
1569
	 */
1570
	do_action( 'give_pre_delete_payment_note', $comment_id, $payment_id );
1571
1572
	$ret = wp_delete_comment( $comment_id, true );
1573
1574
	/**
1575
	 * Fires after donation note deleted.
1576
	 *
1577
	 * @since 1.0
1578
	 *
1579
	 * @param int $comment_id Note ID.
1580
	 * @param int $payment_id Payment ID.
1581
	 */
1582
	do_action( 'give_post_delete_payment_note', $comment_id, $payment_id );
1583
1584
	return $ret;
1585
}
1586
1587
/**
1588
 * Gets the payment note HTML
1589
 *
1590
 * @since 1.0
1591
 *
1592
 * @param object|int $note       The comment object or ID.
1593
 * @param int        $payment_id The payment ID the note is connected to.
1594
 *
1595
 * @return string
1596
 */
1597
function give_get_payment_note_html( $note, $payment_id = 0 ) {
1598
1599
	if ( is_numeric( $note ) ) {
1600
		$note = get_comment( $note );
1601
	}
1602
1603
	if ( ! empty( $note->user_id ) ) {
1604
		$user = get_userdata( $note->user_id );
1605
		$user = $user->display_name;
1606
	} else {
1607
		$user = esc_html__( 'System', 'give' );
1608
	}
1609
1610
	$date_format = give_date_format() . ', ' . get_option( 'time_format' );
1611
1612
	$delete_note_url = wp_nonce_url( add_query_arg( array(
1613
		'give-action' => 'delete_payment_note',
1614
		'note_id'     => $note->comment_ID,
1615
		'payment_id'  => $payment_id,
1616
	) ),
1617
		'give_delete_payment_note_' . $note->comment_ID
1618
	);
1619
1620
	$note_html = '<div class="give-payment-note" id="give-payment-note-' . $note->comment_ID . '">';
1621
	$note_html .= '<p>';
1622
	$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/>';
1623
	$note_html .= $note->comment_content;
1624
	$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>';
1625
	$note_html .= '</p>';
1626
	$note_html .= '</div>';
1627
1628
	return $note_html;
1629
1630
}
1631
1632
/**
1633
 * Exclude notes (comments) on give_payment post type from showing in Recent
1634
 * Comments widgets
1635
 *
1636
 * @since 1.0
1637
 *
1638
 * @param object $query WordPress Comment Query Object.
1639
 *
1640
 * @return void
1641
 */
1642
function give_hide_payment_notes( $query ) {
1643
	if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '>=' ) ) {
1644
		$types = isset( $query->query_vars['type__not_in'] ) ? $query->query_vars['type__not_in'] : array();
1645
		if ( ! is_array( $types ) ) {
1646
			$types = array( $types );
1647
		}
1648
		$types[]                           = 'give_payment_note';
1649
		$query->query_vars['type__not_in'] = $types;
1650
	}
1651
}
1652
1653
add_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1654
1655
/**
1656
 * Exclude notes (comments) on give_payment post type from showing in Recent Comments widgets
1657
 *
1658
 * @since 1.0
1659
 *
1660
 * @param array  $clauses          Comment clauses for comment query.
1661
 * @param object $wp_comment_query WordPress Comment Query Object.
1662
 *
1663
 * @return array $clauses Updated comment clauses.
1664
 */
1665
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...
1666
	if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '<' ) ) {
1667
		$clauses['where'] .= ' AND comment_type != "give_payment_note"';
1668
	}
1669
1670
	return $clauses;
1671
}
1672
1673
add_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10, 2 );
1674
1675
1676
/**
1677
 * Exclude notes (comments) on give_payment post type from showing in comment feeds
1678
 *
1679
 * @since 1.0
1680
 *
1681
 * @param string $where
1682
 * @param object $wp_comment_query WordPress Comment Query Object.
1683
 *
1684
 * @return string $where
1685
 */
1686
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...
1687
	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...
1688
1689
	$where .= $wpdb->prepare( ' AND comment_type != %s', 'give_payment_note' );
1690
1691
	return $where;
1692
}
1693
1694
add_filter( 'comment_feed_where', 'give_hide_payment_notes_from_feeds', 10, 2 );
1695
1696
1697
/**
1698
 * Remove Give Comments from the wp_count_comments function
1699
 *
1700
 * @access public
1701
 * @since  1.0
1702
 *
1703
 * @param array $stats   (empty from core filter).
1704
 * @param int   $post_id Post ID.
1705
 *
1706
 * @return array Array of comment counts.
1707
 */
1708
function give_remove_payment_notes_in_comment_counts( $stats, $post_id ) {
1709
	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...
1710
1711
	if ( 'index.php' != $pagenow ) {
1712
		return $stats;
1713
	}
1714
1715
	$post_id = (int) $post_id;
1716
1717
	if ( apply_filters( 'give_count_payment_notes_in_comments', false ) ) {
1718
		return $stats;
1719
	}
1720
1721
	$stats = wp_cache_get( "comments-{$post_id}", 'counts' );
1722
1723
	if ( false !== $stats ) {
1724
		return $stats;
1725
	}
1726
1727
	$where = 'WHERE comment_type != "give_payment_note"';
1728
1729
	if ( $post_id > 0 ) {
1730
		$where .= $wpdb->prepare( ' AND comment_post_ID = %d', $post_id );
1731
	}
1732
1733
	$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A );
1734
1735
	$total    = 0;
1736
	$approved = array(
1737
		'0'            => 'moderated',
1738
		'1'            => 'approved',
1739
		'spam'         => 'spam',
1740
		'trash'        => 'trash',
1741
		'post-trashed' => 'post-trashed',
1742
	);
1743
	foreach ( (array) $count as $row ) {
1744
		// Don't count post-trashed toward totals.
1745
		if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
1746
			$total += $row['num_comments'];
1747
		}
1748
		if ( isset( $approved[ $row['comment_approved'] ] ) ) {
1749
			$stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
1750
		}
1751
	}
1752
1753
	$stats['total_comments'] = $total;
1754
	foreach ( $approved as $key ) {
1755
		if ( empty( $stats[ $key ] ) ) {
1756
			$stats[ $key ] = 0;
1757
		}
1758
	}
1759
1760
	$stats = (object) $stats;
1761
	wp_cache_set( "comments-{$post_id}", $stats, 'counts' );
1762
1763
	return $stats;
1764
}
1765
1766
add_filter( 'wp_count_comments', 'give_remove_payment_notes_in_comment_counts', 10, 2 );
1767
1768
1769
/**
1770
 * Filter where older than one week
1771
 *
1772
 * @access public
1773
 * @since  1.0
1774
 *
1775
 * @param string $where Where clause.
1776
 *
1777
 * @return string $where Modified where clause.
1778
 */
1779
function give_filter_where_older_than_week( $where = '' ) {
1780
	// Payments older than one week.
1781
	$start = date( 'Y-m-d', strtotime( '-7 days' ) );
1782
	$where .= " AND post_date <= '{$start}'";
1783
1784
	return $where;
1785
}
1786
1787
1788
/**
1789
 * Get Payment Form ID.
1790
 *
1791
 * Retrieves the form title and appends the level name if present.
1792
 *
1793
 * @since 1.5
1794
 *
1795
 * @param array  $payment_meta       Payment meta data.
1796
 * @param bool   $only_level         If set to true will only return the level name if multi-level enabled.
1797
 * @param string $separator          The separator between the .
1798
 *
1799
 * @return string $form_title Returns the full title if $only_level is false, otherwise returns the levels title.
1800
 */
1801
function give_get_payment_form_title( $payment_meta, $only_level = false, $separator = '' ) {
1802
1803
	$form_id    = isset( $payment_meta['form_id'] ) ? $payment_meta['form_id'] : 0;
1804
	$price_id   = isset( $payment_meta['price_id'] ) ? $payment_meta['price_id'] : null;
1805
	$form_title = isset( $payment_meta['form_title'] ) ? $payment_meta['form_title'] : '';
1806
1807
	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...
1808
		$form_title = '';
1809
	}
1810
1811
	//If multi-level, append to the form title.
1812
	if ( give_has_variable_prices( $form_id ) ) {
1813
1814
		//Only add separator if there is a form title.
1815
		if ( ! empty( $form_title ) ) {
1816
			$form_title .= ' ' . $separator . ' ';
1817
		}
1818
1819
		$form_title .= '<span class="donation-level-text-wrap">';
1820
1821
		if ( $price_id == 'custom' ) {
1822
			$custom_amount_text = get_post_meta( $form_id, '_give_custom_amount_text', true );
1823
			$form_title .= ! empty( $custom_amount_text ) ? $custom_amount_text : __( 'Custom Amount', 'give' );
1824
		} else {
1825
			$form_title .= give_get_price_option_name( $form_id, $price_id );
1826
		}
1827
1828
		$form_title .= '</span>';
1829
1830
	}
1831
1832
	return apply_filters( 'give_get_payment_form_title', $form_title, $payment_meta );
1833
1834
}
1835
1836
/**
1837
 * Get Price ID
1838
 *
1839
 * Retrieves the Price ID when provided a proper form ID and price (donation) total
1840
 *
1841
 * @param int    $form_id Form ID.
1842
 * @param string $price   Price ID.
1843
 *
1844
 * @return string $price_id
1845
 */
1846
function give_get_price_id( $form_id, $price ) {
1847
1848
	$price_id = 0;
1849
1850
	if ( give_has_variable_prices( $form_id ) ) {
1851
1852
		$levels = maybe_unserialize( get_post_meta( $form_id, '_give_donation_levels', true ) );
1853
1854
		foreach ( $levels as $level ) {
1855
1856
			$level_amount = (float) give_sanitize_amount( $level['_give_amount'] );
1857
1858
			// Check that this indeed the recurring price.
1859
			if ( $level_amount == $price ) {
1860
1861
				$price_id = $level['_give_id']['level_id'];
1862
1863
			}
1864
		}
1865
	}
1866
1867
	return $price_id;
1868
1869
}
1870
1871
/**
1872
 * Get/Print give form dropdown html
1873
 *
1874
 * This function is wrapper to public method forms_dropdown of Give_HTML_Elements class to get/print form dropdown html.
1875
 * Give_HTML_Elements is defined in includes/class-give-html-elements.php.
1876
 *
1877
 * @since 1.6
1878
 *
1879
 * @param array $args Arguments for form dropdown.
1880
 * @param bool  $echo This parameter decides if print form dropdown html output or not.
1881
 *
1882
 * @return string|void
1883
 */
1884
function give_get_form_dropdown( $args = array(), $echo = false ) {
1885
	$form_dropdown_html = Give()->html->forms_dropdown( $args );
1886
1887
	if ( ! $echo ) {
1888
		return $form_dropdown_html;
1889
	}
1890
1891
	echo $form_dropdown_html;
1892
}
1893
1894
/**
1895
 * Get/Print give form variable price dropdown html
1896
 *
1897
 * @since 1.6
1898
 *
1899
 * @param array $args Arguments for form dropdown.
1900
 * @param bool  $echo This parameter decide if print form dropdown html output or not.
1901
 *
1902
 * @return string|bool
1903
 */
1904
function give_get_form_variable_price_dropdown( $args = array(), $echo = false ) {
1905
1906
	// Check for give form id.
1907
	if ( empty( $args['id'] ) ) {
1908
		return false;
1909
	}
1910
1911
	$form = new Give_Donate_Form( $args['id'] );
1912
1913
	// Check if form has variable prices or not.
1914
	if ( ! $form->ID || ! $form->has_variable_prices() ) {
1915
		return false;
1916
	}
1917
1918
	$variable_prices        = $form->get_prices();
1919
	$variable_price_options = array();
1920
1921
	// Check if multi donation form support custom donation or not.
1922
	if ( $form->is_custom_price_mode() ) {
1923
		$variable_price_options['custom'] = _x( 'Custom', 'custom donation dropdown item', 'give' );
1924
	}
1925
1926
	// Get variable price and ID from variable price array.
1927
	foreach ( $variable_prices as $variable_price ) {
1928
		$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'] ) );
1929
	}
1930
1931
	// Update options.
1932
	$args = array_merge( $args, array( 'options' => $variable_price_options ) );
1933
1934
	// Generate select html.
1935
	$form_dropdown_html = Give()->html->select( $args );
1936
1937
	if ( ! $echo ) {
1938
		return $form_dropdown_html;
1939
	}
1940
1941
	echo $form_dropdown_html;
1942
}