Test Failed
Pull Request — master (#2551)
by Devin
04:51
created

functions.php ➔ give_get_donation_id_by_key()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 10

Duplication

Lines 23
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 10
nc 2
nop 1
dl 23
loc 23
rs 9.0856
c 0
b 0
f 0
ccs 0
cts 5
cp 0
crap 6
1
<?php
2
/**
3
 * Payment Functions
4
 *
5
 * @package     Give
6
 * @subpackage  Payments
7
 * @copyright   Copyright (c) 2016, WordImpress
8
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
9
 * @since       1.0
10
 */
11
12
// Exit if accessed directly.
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Get Payments
19
 *
20
 * Retrieve payments from the database.
21
 *
22
 * Since 1.0, this function takes an array of arguments, instead of individual
23
 * parameters. All of the original parameters remain, but can be passed in any
24
 * order via the array.
25
 *
26
 * @since 1.0
27
 *
28
 * @param array $args     {
29
 *                        Optional. Array of arguments passed to payments query.
30
 *
31
 * @type int    $offset   The number of payments to offset before retrieval.
32
 *                            Default is 0.
33
 * @type int    $number   The number of payments to query for. Use -1 to request all
34
 *                            payments. Default is 20.
35
 * @type string $mode     Default is 'live'.
36
 * @type string $order    Designates ascending or descending order of payments.
37
 *                            Accepts 'ASC', 'DESC'. Default is 'DESC'.
38 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 array $payments Payments retrieved from the database
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 View Code Duplication
		case 'key':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
88
			$payment = give_get_payments( array(
89
				'meta_key'       => '_give_payment_purchase_key',
0 ignored issues
show
introduced by
Detected usage of meta_key, possible slow query.
Loading history...
90
				'meta_value'     => $value,
0 ignored issues
show
introduced by
Detected usage of meta_value, possible slow query.
Loading history...
91
				'posts_per_page' => 1,
92
				'fields'         => 'ids',
93
			) );
94
95
			if ( $payment ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $payment of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
96
				$payment = new Give_Payment( $payment[0] );
97
			}
98
99
			break;
100
101 View Code Duplication
		case 'payment_number':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
102
			$payment = give_get_payments( array(
103
				'meta_key'       => '_give_payment_number',
0 ignored issues
show
introduced by
Detected usage of meta_key, possible slow query.
Loading history...
104
				'meta_value'     => $value,
0 ignored issues
show
introduced by
Detected usage of meta_value, possible slow query.
Loading history...
105
				'posts_per_page' => 1,
106 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
	}// End switch().
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
	/**
142 52
	 * Fire the filter on donation data before insert.
143 52
	 *
144 52
	 * @since 1.8.15
145 52
	 *
146 52
	 * @param array $payment_data Arguments passed.
147 52
	 */
148 52
	$payment_data = apply_filters( 'give_pre_insert_payment', $payment_data );
149 52
150 52
	$payment    = new Give_Payment();
151 52
	$gateway    = ! empty( $payment_data['gateway'] ) ? $payment_data['gateway'] : '';
152 52
	$gateway    = empty( $gateway ) && isset( $_POST['give-gateway'] ) ? $_POST['give-gateway'] : $gateway;
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
153 52
	$form_id    = isset( $payment_data['give_form_id'] ) ? $payment_data['give_form_id'] : 0;
154 52
	$price_id   = give_get_payment_meta_price_id( $payment_data );
155
	$form_title = isset( $payment_data['give_form_title'] ) ? $payment_data['give_form_title'] : get_the_title( $form_id );
156
157
	// Set properties.
158 52
	$payment->total          = $payment_data['price'];
159 52
	$payment->status         = ! empty( $payment_data['status'] ) ? $payment_data['status'] : 'pending';
160 52
	$payment->currency       = ! empty( $payment_data['currency'] ) ? $payment_data['currency'] : give_get_currency( $payment_data['give_form_id'], $payment_data );
161 52
	$payment->user_info      = $payment_data['user_info'];
162
	$payment->gateway        = $gateway;
163 52
	$payment->form_title     = $form_title;
164
	$payment->form_id        = $form_id;
165
	$payment->price_id       = $price_id;
166 52
	$payment->donor_id       = ( ! empty( $payment_data['donor_id'] ) ? $payment_data['donor_id'] : '' );
167
	$payment->user_id        = $payment_data['user_info']['id'];
168
	$payment->email          = $payment_data['user_email'];
169
	$payment->first_name     = $payment_data['user_info']['first_name'];
170
	$payment->last_name      = $payment_data['user_info']['last_name'];
171 52
	$payment->email          = $payment_data['user_info']['email'];
172 20
	$payment->ip             = give_get_ip();
0 ignored issues
show
Documentation Bug introduced by
It seems like give_get_ip() can also be of type array. However, the property $ip is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
173 20
	$payment->key            = $payment_data['purchase_key'];
174 20
	$payment->mode           = ( ! empty( $payment_data['mode'] ) ? (string) $payment_data['mode'] : ( give_is_test_mode() ? 'test' : 'live' ) );
175 20
	$payment->parent_payment = ! empty( $payment_data['parent'] ) ? absint( $payment_data['parent'] ) : '';
176
177
	// Add the donation.
178 52
	$args = array(
179
		'price'    => $payment->total,
180
		'price_id' => $payment->price_id,
181 52
	);
182
183
	$payment->add_donation( $payment->form_id, $args );
184 52
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
185
186
	// Set date if present.
187 52
	if ( isset( $payment_data['post_date'] ) ) {
188 52
		$payment->date = $payment_data['post_date'];
189
	}
190
191
	// Handle sequential payments.
192
	if ( give_get_option( 'enable_sequential' ) ) {
193
		$number          = give_get_next_payment_number();
194
		$payment->number = give_format_payment_number( $number );
195
		update_option( 'give_last_payment_number', $number );
196
	}
197
198
	// Save payment.
199
	$payment->save();
200
201
	/**
202
	 * Fires while inserting payments.
203
	 *
204
	 * @since 1.0
205
	 *
206
	 * @param int   $payment_id   The payment ID.
207
	 * @param array $payment_data Arguments passed.
208 35
	 */
209 35
	do_action( 'give_insert_payment', $payment->ID, $payment_data );
210 35
211
	// Return payment ID upon success.
212 35
	if ( ! empty( $payment->ID ) ) {
213
		return $payment->ID;
214
	}
215
216
	// Return false if no payment was inserted.
217
	return false;
218
219
}
220
221
/**
222
 * Create payment.
223
 *
224
 * @param $payment_data
225
 *
226
 * @return bool|int
227
 */
228
function give_create_payment( $payment_data ) {
229 31
230
	$form_id  = intval( $payment_data['post_data']['give-form-id'] );
231 31
	$price_id = isset( $payment_data['post_data']['give-price-id'] ) ? $payment_data['post_data']['give-price-id'] : '';
232 31
233 31
	// Collect payment data.
234 31
	$insert_payment_data = array(
235 31
		'price'           => $payment_data['price'],
236
		'give_form_title' => $payment_data['post_data']['give-form-title'],
237
		'give_form_id'    => $form_id,
238 31
		'give_price_id'   => $price_id,
239 31
		'date'            => $payment_data['date'],
240
		'user_email'      => $payment_data['user_email'],
241 31
		'purchase_key'    => $payment_data['purchase_key'],
242
		'currency'        => give_get_currency( $form_id, $payment_data ),
243 31
		'user_info'       => $payment_data['user_info'],
244 16
		'status'          => 'pending',
245 16
		'gateway'         => 'paypal',
246
	);
247 31
248
	/**
249
	 * Filter the payment params.
250 14
	 *
251
	 * @since 1.8
252 14
	 *
253
	 * @param array $insert_payment_data
254 14
	 */
255
	$insert_payment_data = apply_filters( 'give_create_payment', $insert_payment_data );
256
257
	// Record the pending payment.
258
	return give_insert_payment( $insert_payment_data );
259
}
260
261 14
/**
262
 * Updates a payment status.
263 31
 *
264
 * @param  int    $payment_id Payment ID.
265 31
 * @param  string $new_status New Payment Status. Default is 'publish'.
266
 *
267
 * @since  1.0
268 1
 *
269
 * @return bool
270 1
 */
271
function give_update_payment_status( $payment_id, $new_status = 'publish' ) {
272
273 31
	$updated = false;
274
	$payment = new Give_Payment( $payment_id );
275
276 31
	if ( $payment && $payment->ID > 0 ) {
277 31
278 31
		$payment->status = $new_status;
279
		$updated         = $payment->save();
280
281 31
	}
282
283 31
	return $updated;
284 31
}
285 31
286
287 31
/**
288 31
 * Deletes a Donation
289
 *
290
 * @param  int  $payment_id   Payment ID (default: 0).
291
 * @param  bool $update_donor If we should update the donor stats (default:true).
292
 *
293
 * @since  1.0
294
 * @global      $give_logs
295
 *
296
 * @return void
297
 */
298
function give_delete_donation( $payment_id = 0, $update_donor = true ) {
299
300
	global $give_logs;
301
302 20
	$payment  = new Give_Payment( $payment_id );
303
304
	// Bailout.
305
	if( ! $payment->ID ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
306
		return;
307 20
	}
308
309 20
	$amount   = give_donation_amount( $payment_id );
310 20
	$status   = $payment->post_status;
311
	$donor_id = give_get_payment_donor_id( $payment_id );
312 18
	$donor    = new Give_Donor( $donor_id );
0 ignored issues
show
Documentation introduced by
$donor_id is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
313 18
314
	// Only undo donations that aren't these statuses.
315 20
	$dont_undo_statuses = apply_filters( 'give_undo_donation_statuses', array(
316 20
		'pending',
317
		'cancelled',
318 18
	) );
319 18
320
	if ( ! in_array( $status, $dont_undo_statuses ) ) {
321 20
		give_undo_donation( $payment_id );
322
	}
323
324
	// Only undo donations that aren't these statuses.
325
	$status_to_decrease_stats = apply_filters( 'give_decrease_donor_statuses', array( 'publish' ) );
326
327
	if ( in_array( $status, $status_to_decrease_stats ) ) {
328
329
		// Only decrease earnings if they haven't already been decreased (or were never increased for this payment).
330
		give_decrease_total_earnings( $amount );
331
332
		// @todo: Refresh only range related stat cache
333
		give_delete_donation_stats();
334
335
		if ( $donor->id && $update_donor ) {
336
337 6
			// Decrement the stats for the donor.
338
			$donor->decrease_donation_count();
339
			$donor->decrease_value( $amount );
340 6
341 6
		}
342 6
	}
343 6
344 6
	/**
345 6
	 * Fires before deleting payment.
346
	 *
347 6
	 * @param int $payment_id Payment ID.
348
	 *
349 6
	 * @since 1.0
350 6
	 */
351 6
	do_action( 'give_payment_delete', $payment_id );
352
353
	if ( $donor->id && $update_donor ) {
354 6
		// Remove the payment ID from the donor.
355
		$donor->remove_payment( $payment_id );
356
	}
357
358
	// Remove the payment.
359
	wp_delete_post( $payment_id, true );
360
361
	// Remove related sale log entries.
362
	$give_logs->delete_logs( null, 'sale', array(
363
		array(
364
			'key'   => '_give_log_payment_id',
365
			'value' => $payment_id,
366
		),
367
	) );
368
369
	/**
370
	 * Fires after payment deleted.
371
	 *
372
	 * @param int $payment_id Payment ID.
373 6
	 *
374
	 * @since 1.0
375
	 */
376
	do_action( 'give_payment_deleted', $payment_id );
377
}
378
379
/**
380
 * Undo Donation
381
 *
382
 * Undoes a donation, including the decrease of donations and earning stats.
383
 * Used for when refunding or deleting a donation.
384
 *
385
 * @param  int $payment_id Payment ID.
386
 *
387
 * @since  1.0
388
 *
389
 * @return void
390
 */
391
function give_undo_donation( $payment_id ) {
392
393
	$payment = new Give_Payment( $payment_id );
394
395
	$maybe_decrease_earnings = apply_filters( 'give_decrease_earnings_on_undo', true, $payment, $payment->form_id );
396
	if ( true === $maybe_decrease_earnings ) {
397
		// Decrease earnings.
398
		give_decrease_form_earnings( $payment->form_id, $payment->total );
399
	}
400
401
	$maybe_decrease_donations = apply_filters( 'give_decrease_donations_on_undo', true, $payment, $payment->form_id );
402
	if ( true === $maybe_decrease_donations ) {
403
		// Decrease donation count.
404
		give_decrease_donation_count( $payment->form_id );
405
	}
406
407
}
408
409
410
/**
411
 * Count Payments
412
 *
413
 * Returns the total number of payments recorded.
414
 *
415
 * @param  array $args Arguments passed.
416
 *
417
 * @since  1.0
418
 *
419
 * @return object $stats Contains the number of payments per payment status.
420 6
 */
421
function give_count_payments( $args = array() ) {
422
	// Backward compatibility.
423
	if( ! empty( $args['start-date'] ) ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
424
		$args['start_date'] = $args['start-date'];
425
		unset( $args['start-date'] );
426 6
	}
427
428
	if( ! empty( $args['end-date'] ) ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
429
		$args['end_date'] = $args['end-date'];
430
		unset( $args['end-date'] );
431
	}
432
433
	if( ! empty( $args['form_id'] ) ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
434
		$args['give_forms'] = $args['form_id'];
435
		unset( $args['form_id'] );
436
	}
437
438
	// Extract all donations
439
	$args['number']      = - 1;
440
	$args['group_by']    = 'post_status';
441
	$args['count']       = 'true';
442
443
	$donations_obj = new Give_Payments_Query( $args );
444
	$donations_count = $donations_obj->get_payment_by_group();
445
446
	/**
447
	 * Filter the payment counts group by status
448 6
	 *
449
	 * @since 1.0
450
	 */
451
	return (object) apply_filters( 'give_count_payments', $donations_count, $args, $donations_obj );
452
}
453
454
455
/**
456
 * Check For Existing Payment
457
 *
458
 * @param  int $payment_id Payment ID.
459
 *
460
 * @since  1.0
461
 *
462
 * @return bool $exists True if payment exists, false otherwise.
463
 */
464
function give_check_for_existing_payment( $payment_id ) {
465
	$exists  = false;
466 6
	$payment = new Give_Payment( $payment_id );
467 6
468
	if ( $payment_id === $payment->ID && 'publish' === $payment->status ) {
469
		$exists = true;
470 6
	}
471 6
472 6
	return $exists;
473
}
474 6
475
/**
476 6
 * Get Payment Status
477
 *
478 6
 * @param WP_Post|Give_Payment|int $payment      Payment object or payment ID.
479 6
 * @param bool                     $return_label Whether to return the translated status label instead of status value. Default false.
480
 *
481
 * @since 1.0
482
 *
483 6
 * @return bool|mixed True if payment status exists, false otherwise.
484
 */
485 6
function give_get_payment_status( $payment, $return_label = false ) {
486 6
487 6
	if ( is_numeric( $payment ) ) {
488 6
489 6
		$payment = new Give_Payment( $payment );
490
491 6
		if ( ! $payment->ID > 0 ) {
492 6
			return false;
493 6
		}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
494
495 6
	}
496
497 6
	if ( ! is_object( $payment ) || ! isset( $payment->post_status ) ) {
498
		return false;
499
	}
500
501 6
	$statuses = give_get_payment_statuses();
502 6
503
	if ( ! is_array( $statuses ) || empty( $statuses ) ) {
504 6
		return false;
505 6
	}
506
507 6
	// Get payment object if not already given.
508
	$payment = $payment instanceof Give_Payment ? $payment : new Give_Payment( $payment->ID );
509
510
	if ( array_key_exists( $payment->status, $statuses ) ) {
511
		if ( true === $return_label ) {
512
			// Return translated status label.
513
			return $statuses[ $payment->status ];
514
		} else {
515
			// Account that our 'publish' status is labeled 'Complete'
516
			$post_status = 'publish' === $payment->status ? 'Complete' : $payment->post_status;
517
518
			// Make sure we're matching cases, since they matter
519
			return array_search( strtolower( $post_status ), array_map( 'strtolower', $statuses ) );
520
		}
521
	}
522
523
	return false;
524
}
525
526
/**
527
 * Retrieves all available statuses for payments.
528
 *
529
 * @since  1.0
530
 *
531
 * @return array $payment_status All the available payment statuses.
532
 */
533
function give_get_payment_statuses() {
534
	$payment_statuses = array(
535
		'pending'     => __( 'Pending', 'give' ),
536
		'publish'     => __( 'Complete', 'give' ),
537
		'refunded'    => __( 'Refunded', 'give' ),
538
		'failed'      => __( 'Failed', 'give' ),
539
		'cancelled'   => __( 'Cancelled', 'give' ),
540
		'abandoned'   => __( 'Abandoned', 'give' ),
541
		'preapproval' => __( 'Pre-Approved', 'give' ),
542
		'processing'  => __( 'Processing', 'give' ),
543
		'revoked'     => __( 'Revoked', 'give' ),
544
	);
545
546
	return apply_filters( 'give_payment_statuses', $payment_statuses );
547
}
548
549
/**
550
 * Get Payment Status Keys
551
 *
552
 * Retrieves keys for all available statuses for payments
553
 *
554
 * @since 1.0
555
 *
556
 * @return array $payment_status All the available payment statuses.
557
 */
558
function give_get_payment_status_keys() {
559
	$statuses = array_keys( give_get_payment_statuses() );
560
	asort( $statuses );
561
562
	return array_values( $statuses );
563
}
564
565
/**
566
 * Get Earnings By Date
567
 *
568
 * @param int $day       Day number. Default is null.
569
 * @param int $month_num Month number. Default is null.
570
 * @param int $year      Year number. Default is null.
571
 * @param int $hour      Hour number. Default is null.
572
 *
573
 * @since 1.0
574
 *
575
 * @return int $earnings Earnings
576
 */
577
function give_get_earnings_by_date( $day = null, $month_num, $year = null, $hour = null ) {
578
579 52
	// This is getting deprecated soon. Use Give_Payment_Stats with the get_earnings() method instead.
580 52
	global $wpdb;
581 52
582 52
	$args = array(
583 52
		'post_type'              => 'give_payment',
584 52
		'nopaging'               => true,
0 ignored issues
show
introduced by
Disabling pagination is prohibited in VIP context, do not set nopaging to true ever.
Loading history...
585 52
		'year'                   => $year,
586 52
		'monthnum'               => $month_num,
587 52
		'post_status'            => array( 'publish' ),
588
		'fields'                 => 'ids',
589 52
		'update_post_term_cache' => false,
590
	);
591
	if ( ! empty( $day ) ) {
592
		$args['day'] = $day;
593
	}
594
595
	if ( isset( $hour ) ) {
596
		$args['hour'] = $hour;
597
	}
598
599
	$args = apply_filters( 'give_get_earnings_by_date_args', $args );
600
	$key  = Give_Cache::get_key( 'give_stats', $args );
601 52
602 52 View Code Duplication
	if ( ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'give-refresh-reports' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
603
		$earnings = false;
604 52
	} else {
605
		$earnings = Give_Cache::get( $key );
606
	}
607
608
	if ( false === $earnings ) {
609
		$donations = get_posts( $args );
610
		$earnings  = 0;
611
		if ( $donations ) {
612
			$donations      = implode( ',', $donations );
613
			$earning_totals = $wpdb->get_var( "SELECT SUM(meta_value) FROM $wpdb->postmeta WHERE meta_key = '_give_payment_total' AND post_id IN ({$donations})" );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
introduced by
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
614
615
			/**
616
			 * Filter The earnings by dates.
617
			 *
618
			 * @since 1.8.17
619
			 *
620
			 * @param float $earning_totals Total earnings between the dates.
621
			 * @param array $donations      Donations lists.
622
			 * @param array $args           Donation query args.
623
			 */
624
			$earnings = apply_filters( 'give_get_earnings_by_date', $earning_totals, $donations, $args );
625
		}
626
		// Cache the results for one hour.
627
		Give_Cache::set( $key, $earnings, HOUR_IN_SECONDS );
628
	}
629
630
	return round( $earnings, 2 );
631
}
632
633
/**
634
 * Get Donations (sales) By Date
635
 *
636
 * @param int $day       Day number. Default is null.
637
 * @param int $month_num Month number. Default is null.
638
 * @param int $year      Year number. Default is null.
639
 * @param int $hour      Hour number. Default is null.
640
 *
641
 * @since 1.0
642
 *
643
 * @return int $count Sales
644
 */
645
function give_get_sales_by_date( $day = null, $month_num = null, $year = null, $hour = null ) {
646
647
	// This is getting deprecated soon. Use Give_Payment_Stats with the get_sales() method instead.
648
	$args = array(
649
		'post_type'              => 'give_payment',
650
		'nopaging'               => true,
0 ignored issues
show
introduced by
Disabling pagination is prohibited in VIP context, do not set nopaging to true ever.
Loading history...
651
		'year'                   => $year,
652
		'fields'                 => 'ids',
653
		'post_status'            => array( 'publish' ),
654
		'update_post_meta_cache' => false,
655
		'update_post_term_cache' => false,
656
	);
657
658
	$show_free = apply_filters( 'give_sales_by_date_show_free', true, $args );
659
660
	if ( false === $show_free ) {
661
		$args['meta_query'] = array(
0 ignored issues
show
introduced by
Detected usage of meta_query, possible slow query.
Loading history...
662
			array(
663
				'key'     => '_give_payment_total',
664
				'value'   => 0,
665
				'compare' => '>',
666
				'type'    => 'NUMERIC',
667
			),
668
		);
669
	}
670
671
	if ( ! empty( $month_num ) ) {
672
		$args['monthnum'] = $month_num;
673
	}
674
675
	if ( ! empty( $day ) ) {
676
		$args['day'] = $day;
677
	}
678
679
	if ( isset( $hour ) ) {
680
		$args['hour'] = $hour;
681
	}
682
683
	$args = apply_filters( 'give_get_sales_by_date_args', $args );
684
685
	$key = Give_Cache::get_key( 'give_stats', $args );
686
687 View Code Duplication
	if ( ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'give-refresh-reports' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

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

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1357
	global $wpdb;
1358
1359
	$purchase = $wpdb->get_var(
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
introduced by
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
1360
		$wpdb->prepare(
1361
			"
1362
				SELECT post_id
1363
				FROM $wpdb->postmeta
1364
				WHERE meta_key = '_give_payment_purchase_key'
1365
				AND meta_value = %s
1366
				ORDER BY post_id DESC
1367
				LIMIT 1
1368
				",
1369
			$key
1370
		)
1371
	);
1372
1373
	if ( $purchase != null ) {
1374
		return $purchase;
1375
	}
1376
1377
	return 0;
1378
}
1379
1380
1381
/**
1382
 * Retrieve the donation ID based on the transaction ID
1383
 *
1384
 * @param string  $key  The transaction ID to search for.
1385
 *
1386
 * @since 1.3
1387
 * @global object $wpdb Used to query the database using the WordPress Database API.
1388
 *
1389
 * @return int $purchase Donation ID.
1390
 */
1391 View Code Duplication
function give_get_purchase_id_by_transaction_id( $key ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1392
	global $wpdb;
1393
1394
	$purchase = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_give_payment_transaction_id' AND meta_value = %s LIMIT 1", $key ) );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
introduced by
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
1395
1396
	if ( $purchase != null ) {
1397
		return $purchase;
1398
	}
1399
1400
	return 0;
1401
}
1402
1403
/**
1404
 * Retrieve all notes attached to a donation
1405
 *
1406
 * @param int    $payment_id The donation ID to retrieve notes for.
1407
 * @param string $search     Search for notes that contain a search term.
1408
 *
1409
 * @since 1.0
1410
 *
1411
 * @return array $notes Donation Notes
1412
 */
1413
function give_get_payment_notes( $payment_id = 0, $search = '' ) {
1414
1415
	if ( empty( $payment_id ) && empty( $search ) ) {
1416
		return false;
1417
	}
1418
1419
	remove_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1420
	remove_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10 );
1421
1422
	$notes = get_comments( array(
1423
		'post_id' => $payment_id,
1424
		'order'   => 'ASC',
1425
		'search'  => $search,
1426
	) );
1427
1428
	add_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1429
	add_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10, 2 );
1430
1431
	return $notes;
1432
}
1433
1434
1435
/**
1436
 * Add a note to a payment
1437
 *
1438
 * @param int    $payment_id The payment ID to store a note for.
1439
 * @param string $note       The note to store.
1440
 *
1441
 * @since 1.0
1442 52
 *
1443
 * @return int The new note ID
1444
 */
1445
function give_insert_payment_note( $payment_id = 0, $note = '' ) {
1446 52
	if ( empty( $payment_id ) ) {
1447
		return false;
1448 52
	}
1449 52
1450 52
	/**
1451 52
	 * Fires before inserting payment note.
1452 52
	 *
1453 52
	 * @param int    $payment_id Payment ID.
1454 52
	 * @param string $note       The note.
1455 52
	 *
1456 52
	 * @since 1.0
1457 52
	 */
1458 52
	do_action( 'give_pre_insert_payment_note', $payment_id, $note );
1459 52
1460
	$note_id = wp_insert_comment( wp_filter_comment( array(
1461
		'comment_post_ID'      => $payment_id,
1462 52
		'comment_content'      => $note,
1463
		'user_id'              => is_admin() ? get_current_user_id() : 0,
1464 52
		'comment_date'         => current_time( 'mysql' ),
1465
		'comment_date_gmt'     => current_time( 'mysql', 1 ),
1466 52
		'comment_approved'     => 1,
1467
		'comment_parent'       => 0,
1468
		'comment_author'       => '',
1469
		'comment_author_IP'    => '',
1470
		'comment_author_url'   => '',
1471
		'comment_author_email' => '',
1472
		'comment_type'         => 'give_payment_note',
1473
1474
	) ) );
1475
1476
	/**
1477
	 * Fires after payment note inserted.
1478
	 *
1479
	 * @param int    $note_id    Note ID.
1480
	 * @param int    $payment_id Payment ID.
1481
	 * @param string $note       The note.
1482
	 *
1483
	 * @since 1.0
1484
	 */
1485
	do_action( 'give_insert_payment_note', $note_id, $payment_id, $note );
1486
1487
	return $note_id;
1488
}
1489
1490
/**
1491
 * Deletes a payment note
1492
 *
1493
 * @param int $comment_id The comment ID to delete.
1494
 * @param int $payment_id The payment ID the note is connected to.
1495
 *
1496
 * @since 1.0
1497
 *
1498
 * @return bool True on success, false otherwise.
1499
 */
1500
function give_delete_payment_note( $comment_id = 0, $payment_id = 0 ) {
1501
	if ( empty( $comment_id ) ) {
1502
		return false;
1503
	}
1504
1505
	/**
1506
	 * Fires before deleting donation note.
1507
	 *
1508
	 * @param int $comment_id Note ID.
1509
	 * @param int $payment_id Payment ID.
1510
	 *
1511
	 * @since 1.0
1512
	 */
1513
	do_action( 'give_pre_delete_payment_note', $comment_id, $payment_id );
1514
1515
	$ret = wp_delete_comment( $comment_id, true );
1516
1517
	/**
1518
	 * Fires after donation note deleted.
1519
	 *
1520
	 * @param int $comment_id Note ID.
1521
	 * @param int $payment_id Payment ID.
1522
	 *
1523
	 * @since 1.0
1524
	 */
1525
	do_action( 'give_post_delete_payment_note', $comment_id, $payment_id );
1526
1527
	return $ret;
1528
}
1529
1530
/**
1531
 * Gets the payment note HTML
1532
 *
1533
 * @param object|int $note       The comment object or ID.
1534
 * @param int        $payment_id The payment ID the note is connected to.
1535
 *
1536
 * @since 1.0
1537
 *
1538
 * @return string
1539
 */
1540
function give_get_payment_note_html( $note, $payment_id = 0 ) {
1541
1542
	if ( is_numeric( $note ) ) {
1543
		$note = get_comment( $note );
1544
	}
1545
1546
	if ( ! empty( $note->user_id ) ) {
1547
		$user = get_userdata( $note->user_id );
1548
		$user = $user->display_name;
1549
	} else {
1550
		$user = __( 'System', 'give' );
1551
	}
1552
1553
	$date_format = give_date_format() . ', ' . get_option( 'time_format' );
1554
1555
	$delete_note_url = wp_nonce_url( add_query_arg( array(
1556
		'give-action' => 'delete_payment_note',
1557
		'note_id'     => $note->comment_ID,
1558
		'payment_id'  => $payment_id,
1559
	) ), 'give_delete_payment_note_' . $note->comment_ID );
1560
1561
	$note_html = '<div class="give-payment-note" id="give-payment-note-' . $note->comment_ID . '">';
1562
	$note_html .= '<p>';
1563
	$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/>';
1564
	$note_html .= $note->comment_content;
1565
	$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="' . __( 'Delete this donation note.', 'give' ) . '">' . __( 'Delete', 'give' ) . '</a>';
0 ignored issues
show
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw '__'
Loading history...
1566
	$note_html .= '</p>';
1567
	$note_html .= '</div>';
1568
1569
	return $note_html;
1570
1571
}
1572
1573
/**
1574
 * Exclude notes (comments) on give_payment post type from showing in Recent
1575
 * Comments widgets
1576
 *
1577
 * @param object $query WordPress Comment Query Object.
1578
 *
1579
 * @since 1.0
1580
 *
1581
 * @return void
1582
 */
1583
function give_hide_payment_notes( $query ) {
1584
	if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '>=' ) ) {
1585
		$types = isset( $query->query_vars['type__not_in'] ) ? $query->query_vars['type__not_in'] : array();
1586
		if ( ! is_array( $types ) ) {
1587
			$types = array( $types );
1588
		}
1589
		$types[]                           = 'give_payment_note';
1590
		$query->query_vars['type__not_in'] = $types;
1591
	}
1592
}
1593
1594
add_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1595
1596
/**
1597
 * Exclude notes (comments) on give_payment post type from showing in Recent Comments widgets
1598
 *
1599
 * @param array  $clauses          Comment clauses for comment query.
1600
 * @param object $wp_comment_query WordPress Comment Query Object.
1601
 *
1602
 * @since 1.0
1603
 *
1604
 * @return array $clauses Updated comment clauses.
1605
 */
1606
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...
1607
	if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '<' ) ) {
1608
		$clauses['where'] .= ' AND comment_type != "give_payment_note"';
1609
	}
1610
1611
	return $clauses;
1612
}
1613
1614
add_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10, 2 );
1615
1616
1617
/**
1618
 * Exclude notes (comments) on give_payment post type from showing in comment feeds
1619
 *
1620
 * @param string $where
1621
 * @param object $wp_comment_query WordPress Comment Query Object.
1622
 *
1623
 * @since 1.0
1624
 *
1625
 * @return string $where
1626
 */
1627
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...
1628
	global $wpdb;
1629
1630
	$where .= $wpdb->prepare( ' AND comment_type != %s', 'give_payment_note' );
1631
1632
	return $where;
1633
}
1634
1635
add_filter( 'comment_feed_where', 'give_hide_payment_notes_from_feeds', 10, 2 );
1636
1637
1638
/**
1639
 * Remove Give Comments from the wp_count_comments function
1640
 *
1641
 * @param array $stats   (empty from core filter).
1642
 * @param int   $post_id Post ID.
1643
 *
1644
 * @access public
1645
 * @since  1.0
1646
 *
1647
 * @return array|object Array of comment counts.
1648
 */
1649
function give_remove_payment_notes_in_comment_counts( $stats, $post_id ) {
1650
	global $wpdb, $pagenow;
1651
1652
	if ( 'index.php' != $pagenow ) {
1653
		return $stats;
1654
	}
1655
1656
	$post_id = (int) $post_id;
1657
1658
	if ( apply_filters( 'give_count_payment_notes_in_comments', false ) ) {
1659
		return $stats;
1660
	}
1661
1662
	$stats = wp_cache_get( "comments-{$post_id}", 'counts' );
1663
1664
	if ( false !== $stats ) {
1665
		return $stats;
1666
	}
1667
1668
	$where = 'WHERE comment_type != "give_payment_note"';
1669
1670
	if ( $post_id > 0 ) {
1671
		$where .= $wpdb->prepare( ' AND comment_post_ID = %d', $post_id );
1672
	}
1673
1674
	$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
1675
1676
	$total    = 0;
1677
	$approved = array(
1678
		'0'            => 'moderated',
0 ignored issues
show
introduced by
Detected usage of 0, possible slow query.
Loading history...
1679
		'1'            => 'approved',
1680
		'spam'         => 'spam',
1681
		'trash'        => 'trash',
1682
		'post-trashed' => 'post-trashed',
1683
	);
1684
	foreach ( (array) $count as $row ) {
1685
		// Don't count post-trashed toward totals.
1686
		if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
1687
			$total += $row['num_comments'];
1688
		}
1689
		if ( isset( $approved[ $row['comment_approved'] ] ) ) {
1690
			$stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
1691
		}
1692
	}
1693
1694
	$stats['total_comments'] = $total;
1695
	foreach ( $approved as $key ) {
1696
		if ( empty( $stats[ $key ] ) ) {
1697
			$stats[ $key ] = 0;
1698
		}
1699
	}
1700
1701
	$stats = (object) $stats;
1702
	wp_cache_set( "comments-{$post_id}", $stats, 'counts' );
1703
1704
	return $stats;
1705
}
1706
1707
add_filter( 'wp_count_comments', 'give_remove_payment_notes_in_comment_counts', 10, 2 );
1708 42
1709 42
1710 42
/**
1711
 * Filter where older than one week
1712 42
 *
1713
 * @param string $where Where clause.
1714
 *
1715
 * @access public
1716 42
 * @since  1.0
1717
 *
1718 34
 * @return string $where Modified where clause.
1719 34
 */
1720 34
function give_filter_where_older_than_week( $where = '' ) {
1721 34
	// Payments older than one week.
1722
	$start = date( 'Y-m-d', strtotime( '-7 days' ) );
1723 34
	$where .= " AND post_date <= '{$start}'";
1724
1725
	return $where;
1726
}
1727
1728
1729 34
/**
1730
 * Get Payment Form ID.
1731
 *
1732 34
 * Retrieves the form title and appends the level name if present.
1733
 *
1734 34
 * @param array  $payment_meta Payment meta data.
1735
 * @param bool   $only_level   If set to true will only return the level name if multi-level enabled.
1736 42
 * @param string $separator    The separator between the .
1737
 *
1738
 * @since 1.5
1739
 *
1740
 * @return string $form_title Returns the full title if $only_level is false, otherwise returns the levels title.
1741
 */
1742
function give_get_payment_form_title( $payment_meta, $only_level = false, $separator = '' ) {
1743
1744
	$form_id     = isset( $payment_meta['form_id'] ) ? $payment_meta['form_id'] : 0;
1745
	$price_id    = isset( $payment_meta['price_id'] ) ? $payment_meta['price_id'] : null;
1746
	$form_title  = isset( $payment_meta['form_title'] ) ? $payment_meta['form_title'] : '';
1747
	$level_label = '';
1748
1749
	if ( $only_level == true ) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
introduced by
Found "== true". Use Yoda Condition checks, you must
Loading history...
1750
		$form_title = '';
1751
	}
1752 52
1753
	if ( 'custom' === $price_id ) {
1754 52
		$custom_amount_text = give_get_meta( $form_id, '_give_custom_amount_text', true );
1755
		$level_label        = ! empty( $custom_amount_text ) ? $custom_amount_text : __( 'Custom Amount', 'give' );
1756 32
	} elseif ( give_has_variable_prices( $form_id ) ) {
1757
		$level_label = give_get_price_option_name( $form_id, $price_id );
1758 32
	}
1759
1760 32
	// Only add separator if there is a form title.
1761
	if (
1762
		! empty( $form_title ) &&
1763 32
		! empty( $level_label )
1764
	) {
1765 32
		$form_title .= ' ' . $separator . ' ';
1766
	}
1767 32
1768
	$form_title .= "<span class=\"donation-level-text-wrap\">{$level_label}</span>";
1769 32
1770
	return apply_filters( 'give_get_payment_form_title', $form_title, $payment_meta );
1771 32
1772
}
1773 52
1774
/**
1775
 * Get Price ID
1776
 *
1777
 * Retrieves the Price ID when provided a proper form ID and price (donation) total
1778
 *
1779
 * @param int    $form_id Form ID.
1780
 * @param string $price   Price ID.
1781
 *
1782
 * @return string $price_id
1783
 */
1784
function give_get_price_id( $form_id, $price ) {
1785
	$price_id = null;
1786
1787
	if ( give_has_variable_prices( $form_id ) ) {
1788
1789
		$levels = give_get_meta( $form_id, '_give_donation_levels', true );
1790
1791
		foreach ( $levels as $level ) {
1792
1793
			$level_amount = give_maybe_sanitize_amount( $level['_give_amount'] );
1794
1795
			// Check that this indeed the recurring price.
1796
			if ( $level_amount == $price ) {
1797
1798
				$price_id = $level['_give_id']['level_id'];
1799
				break;
1800
1801
			}
1802
		}
1803
1804
		if ( is_null( $price_id ) && give_is_custom_price_mode( $form_id ) ) {
1805
			$price_id = 'custom';
1806
		}
1807
	}
1808
1809
	// Price ID must be numeric or string.
1810
	$price_id = ! is_numeric( $price_id ) && ! is_string( $price_id ) ? 0 : $price_id;
1811
1812
	return $price_id;
1813
}
1814
1815
/**
1816
 * Get/Print give form dropdown html
1817
 *
1818
 * This function is wrapper to public method forms_dropdown of Give_HTML_Elements class to get/print form dropdown html.
1819
 * Give_HTML_Elements is defined in includes/class-give-html-elements.php.
1820
 *
1821
 * @param array $args Arguments for form dropdown.
1822
 * @param bool  $echo This parameter decides if print form dropdown html output or not.
1823
 *
1824
 * @since 1.6
1825
 *
1826
 * @return string
1827
 */
1828
function give_get_form_dropdown( $args = array(), $echo = false ) {
1829
	$form_dropdown_html = Give()->html->forms_dropdown( $args );
1830
1831
	if ( ! $echo ) {
1832
		return $form_dropdown_html;
1833
	}
1834
1835
	echo $form_dropdown_html;
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$form_dropdown_html'
Loading history...
1836
}
1837
1838
/**
1839
 * Get/Print give form variable price dropdown html
1840
 *
1841
 * @param array $args Arguments for form dropdown.
1842
 * @param bool  $echo This parameter decide if print form dropdown html output or not.
1843
 *
1844
 * @since 1.6
1845
 *
1846
 * @return string|bool
1847
 */
1848
function give_get_form_variable_price_dropdown( $args = array(), $echo = false ) {
1849
1850
	// Check for give form id.
1851
	if ( empty( $args['id'] ) ) {
1852
		return false;
1853
	}
1854
1855
	$form = new Give_Donate_Form( $args['id'] );
1856
1857
	// Check if form has variable prices or not.
1858
	if ( ! $form->ID || ! $form->has_variable_prices() ) {
1859
		return false;
1860
	}
1861
1862
	$variable_prices        = $form->get_prices();
1863
	$variable_price_options = array();
1864
1865
	// Check if multi donation form support custom donation or not.
1866
	if ( $form->is_custom_price_mode() ) {
1867
		$variable_price_options['custom'] = _x( 'Custom', 'custom donation dropdown item', 'give' );
1868
	}
1869
1870
	// Get variable price and ID from variable price array.
1871
	foreach ( $variable_prices as $variable_price ) {
1872
		$variable_price_options[ $variable_price['_give_id']['level_id'] ] = ! empty( $variable_price['_give_text'] ) ? $variable_price['_give_text'] : give_currency_filter( give_format_amount( $variable_price['_give_amount'], array( 'sanitize' => false ) ) );
1873
	}
1874
1875
	// Update options.
1876
	$args = array_merge( $args, array(
1877
		'options' => $variable_price_options,
1878
	) );
1879
1880
	// Generate select html.
1881
	$form_dropdown_html = Give()->html->select( $args );
1882
1883
	if ( ! $echo ) {
1884
		return $form_dropdown_html;
1885
	}
1886
1887
	echo $form_dropdown_html;
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$form_dropdown_html'
Loading history...
1888
}
1889
1890
/**
1891
 * Get the price_id from the payment meta.
1892
 *
1893
 * Some gateways use `give_price_id` and others were using just `price_id`;
1894
 * This checks for the difference and falls back to retrieving it from the form as a last resort.
1895
 *
1896
 * @param array $payment_meta Payment Meta.
1897
 *
1898
 * @since 1.8.6
1899
 *
1900
 * @return string
1901
 */
1902
function give_get_payment_meta_price_id( $payment_meta ) {
1903
1904
	if ( isset( $payment_meta['give_price_id'] ) ) {
1905
		$price_id = $payment_meta['give_price_id'];
1906
	} elseif ( isset( $payment_meta['price_id'] ) ) {
1907
		$price_id = $payment_meta['price_id'];
1908
	} else {
1909
		$price_id = give_get_price_id( $payment_meta['give_form_id'], $payment_meta['price'] );
1910
	}
1911
1912
	return apply_filters( 'give_get_payment_meta_price_id', $price_id );
1913
1914
}
1915