Completed
Push — master ( 10354b...44551c )
by Devin
29:37 queued 13:08
created

functions.php ➔ give_count_payments()   F

Complexity

Conditions 33
Paths > 20000

Size

Total Lines 148
Code Lines 82

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 1122
Metric Value
cc 33
eloc 82
nc 624767
nop 1
dl 0
loc 148
ccs 0
cts 88
cp 0
crap 1122
rs 2

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 35 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     http://opensource.org/licenses/gpl-1.0.php 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
 * $offset = 0, $number = 20, $mode = 'live', $orderby = 'ID', $order = 'DESC',
27
 * $user = null, $status = 'any', $meta_key = null
28
 *
29
 * @since 1.0
30
 *
31
 * @param array $args Arguments passed to get payments
32
 *
33
 * @return object $payments Payments retrieved from the database
34
 */
35
function give_get_payments( $args = array() ) {
36
37
	// Fallback to post objects to ensure backwards compatibility
38 34
	if ( ! isset( $args['output'] ) ) {
39 34
		$args['output'] = 'posts';
40 34
	}
41
42 34
	$args     = apply_filters( 'give_get_payments_args', $args );
43 34
	$payments = new Give_Payments_Query( $args );
44
45 34
	return $payments->get_payments();
46
}
47
48
/**
49
 * Retrieve payment by a given field
50
 *
51
 * @since       1.0
52
 *
53
 * @param       string $field The field to retrieve the payment with
54
 * @param       mixed $value The value for $field
55
 *
56
 * @return      mixed
57
 */
58
function give_get_payment_by( $field = '', $value = '' ) {
59
60 34
	if ( empty( $field ) || empty( $value ) ) {
61
		return false;
62
	}
63
64 34
	switch ( strtolower( $field ) ) {
65
66 34
		case 'id':
67 34
			$payment = get_post( $value );
68
69 34
			if ( get_post_type( $payment ) != 'give_payment' ) {
70
				return false;
71
			}
72
73 34
			break;
74
75
		case 'key':
76
			$payment = give_get_payments( array(
77
				'meta_key'       => '_give_payment_purchase_key',
78
				'meta_value'     => $value,
79
				'posts_per_page' => 1
80
			) );
81
82
			if ( $payment ) {
83
				$payment = $payment[0];
84
			}
85
86
			break;
87
88
		case 'payment_number':
89
			$payment = give_get_payments( array(
90
				'meta_key'       => '_give_payment_number',
91
				'meta_value'     => $value,
92
				'posts_per_page' => 1
93
			) );
94
95
			if ( $payment ) {
96
				$payment = $payment[0];
97
			}
98
99
			break;
100
101
		default:
102
			return false;
103 34
	}
104
105 34
	if ( $payment ) {
106 34
		return $payment;
107
	}
108
109
	return false;
110
}
111
112
/**
113
 * Insert Payment
114
 *
115
 * @since 1.0
116
 *
117
 * @param array $payment_data
118
 *
119
 * @return int|bool Payment ID if payment is inserted, false otherwise
120
 */
121
function give_insert_payment( $payment_data = array() ) {
122 34
	if ( empty( $payment_data ) ) {
123
		return false;
124
	}
125
126
	// Make sure the payment is inserted with the correct timezone
127 34
	date_default_timezone_set( give_get_timezone_id() );
128
129
	// Construct the payment title
130 34
	if ( isset( $payment_data['user_info']['first_name'] ) || isset( $payment_data['user_info']['last_name'] ) ) {
131 34
		$payment_title = $payment_data['user_info']['first_name'] . ' ' . $payment_data['user_info']['last_name'];
132 34
	} else {
133
		$payment_title = $payment_data['user_email'];
134
	}
135
136
	// Find the next payment number, if enabled
137 34
	if ( give_get_option( 'enable_sequential' ) ) {
138
		$number = give_get_next_payment_number();
139
	}
140
141 34
	$args = apply_filters( 'give_insert_payment_args', array(
142 34
		'post_title'    => $payment_title,
143 34
		'post_status'   => isset( $payment_data['status'] ) ? $payment_data['status'] : 'pending',
144 34
		'post_type'     => 'give_payment',
145 34
		'post_parent'   => isset( $payment_data['parent'] ) ? $payment_data['parent'] : null,
146 34
		'post_date'     => isset( $payment_data['post_date'] ) ? $payment_data['post_date'] : null,
147 34
		'post_date_gmt' => isset( $payment_data['post_date'] ) ? get_gmt_from_date( $payment_data['post_date'] ) : null
148 34
	), $payment_data );
149
	
150
	// Create a blank payment
151 34
	$payment = wp_insert_post( $args );
152
153 34
	if ( $payment ) {
154
155
		$payment_meta = array(
156 34
			'currency'   => $payment_data['currency'],
157 34
			'form_title' => $payment_data['give_form_title'],
158 34
			'form_id'    => $payment_data['give_form_id'],
159 34
			'price_id'   => give_get_price_id( $payment_data['give_form_id'], $payment_data['price'] ),
160 34
			'user_info'  => $payment_data['user_info'],
161 34
		);
162
163 34
		$mode    = give_is_test_mode() ? 'test' : 'live';
164 34
		$gateway = ! empty( $payment_data['gateway'] ) ? $payment_data['gateway'] : '';
165 34
		$gateway = empty( $gateway ) && isset( $_POST['give-gateway'] ) ? $_POST['give-gateway'] : $gateway;
166
167 34
		if ( ! $payment_data['price'] ) {
168
			// Ensures the _give_payment_total meta key is created for donations with an amount of 0
169
			$payment_data['price'] = '0.00';
170
		}
171
172
		// Create or update a customer
173 34
		$customer = new Give_Customer( $payment_data['user_email'] );
174
175
		// If we didn't find a customer and the user is logged in, check by user_id #437
176 34
		if ( empty( $customer->id ) && is_user_logged_in() ) {
177 10
			$customer = new Give_Customer( get_current_user_id(), true );
178 10
		}
179
180
		$customer_data = array(
181 34
			'name'    => $payment_data['user_info']['first_name'] . ' ' . $payment_data['user_info']['last_name'],
182 34
			'email'   => $payment_data['user_email'],
183 34
			'user_id' => $payment_data['user_info']['id']
184 34
		);
185
186 34
		if ( empty( $customer->id ) ) {
187 34
			$customer->create( $customer_data );
188 34
		}
189
190 34
		$customer->attach_payment( $payment, false );
191
192
		// Record the payment details
193 34
		give_update_payment_meta( $payment, '_give_payment_meta', apply_filters( 'give_payment_meta', $payment_meta, $payment_data ) );
194 34
		give_update_payment_meta( $payment, '_give_payment_user_id', $payment_data['user_info']['id'] );
195 34
		give_update_payment_meta( $payment, '_give_payment_customer_id', $customer->id );
196 34
		give_update_payment_meta( $payment, '_give_payment_user_email', $payment_data['user_email'] );
197 34
		give_update_payment_meta( $payment, '_give_payment_user_ip', give_get_ip() );
198 34
		give_update_payment_meta( $payment, '_give_payment_purchase_key', $payment_data['purchase_key'] );
199 34
		give_update_payment_meta( $payment, '_give_payment_total', $payment_data['price'] );
200 34
		give_update_payment_meta( $payment, '_give_payment_mode', $mode );
201 34
		give_update_payment_meta( $payment, '_give_payment_gateway', $gateway );
202
203 34
		if ( give_get_option( 'enable_sequential' ) ) {
204
			give_update_payment_meta( $payment, '_give_payment_number', give_format_payment_number( $number ) );
0 ignored issues
show
Bug introduced by
The variable $number does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
205
			update_option( 'give_last_payment_number', $number );
206
		}
207
208
		// Clear the user's purchased cache
209 34
		delete_transient( 'give_user_' . $payment_data['user_info']['id'] . '_purchases' );
210
211 34
		do_action( 'give_insert_payment', $payment, $payment_data );
212
213 34
		return $payment; // Return the ID
214
215
	}
216
217
	// Return false if no payment was inserted
218
	return false;
219
}
220
221
/**
222
 * Updates a payment status.
223
 *
224
 * @since 1.0
225
 *
226
 * @param int $payment_id Payment ID
227
 * @param string $new_status New Payment Status (default: publish)
228
 *
229
 * @return void
230
 */
231
function give_update_payment_status( $payment_id, $new_status = 'publish' ) {
232
233 34
	if ( $new_status == 'completed' || $new_status == 'complete' ) {
234 34
		$new_status = 'publish';
235 34
	}
236
237 34
	if ( empty( $payment_id ) ) {
238
		return;
239
	}
240
241 34
	$payment = get_post( $payment_id );
242
243 34
	if ( is_wp_error( $payment ) || ! is_object( $payment ) ) {
244
		return;
245
	}
246
247 34
	$old_status = $payment->post_status;
248
249 34
	if ( $old_status === $new_status ) {
250
		return; // Don't permit status changes that aren't changes
251
	}
252
253 34
	$do_change = apply_filters( 'give_should_update_payment_status', true, $payment_id, $new_status, $old_status );
254
255 34
	if ( $do_change ) {
256
257 34
		do_action( 'give_before_payment_status_change', $payment_id, $new_status, $old_status );
258
259
		$update_fields = array(
260 34
			'ID'          => $payment_id,
261 34
			'post_status' => $new_status,
262 34
			'edit_date'   => current_time( 'mysql' )
263 34
		);
264
265 34
		wp_update_post( apply_filters( 'give_update_payment_status_fields', $update_fields ) );
266
267 34
		do_action( 'give_update_payment_status', $payment_id, $new_status, $old_status );
268
269 34
	}
270 34
}
271
272
/**
273
 * Deletes a Donation
274
 *
275
 * @since 1.0
276
 * @global    $give_logs
277
 * @uses  Give_Logging::delete_logs()
278
 *
279
 * @param int $payment_id Payment ID (default: 0)
280
 *
281
 * @return void
282
 */
283
function give_delete_purchase( $payment_id = 0 ) {
284
	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...
285
286
	$post = get_post( $payment_id );
287
288
	if ( ! $post ) {
289
		return;
290
	}
291
292
	$form_id = give_get_payment_form_id( $payment_id );
293
294
	give_undo_purchase( $form_id, $payment_id );
295
296
	$amount   = give_get_payment_amount( $payment_id );
297
	$status   = $post->post_status;
298
	$donor_id = give_get_payment_customer_id( $payment_id );
299
300
	if ( $status == 'revoked' || $status == 'publish' ) {
301
		// Only decrease earnings if they haven't already been decreased (or were never increased for this payment)
302
		give_decrease_total_earnings( $amount );
303
		// Clear the This Month earnings (this_monththis_month is NOT a typo)
304
		delete_transient( md5( 'give_earnings_this_monththis_month' ) );
305
306
		if ( $donor_id ) {
307
308
			// Decrement the stats for the donor
309
			Give()->customers->decrement_stats( $donor_id, $amount );
0 ignored issues
show
Bug introduced by
The method decrement_stats() does not seem to exist on object<Give_Customer>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
310
311
		}
312
	}
313
314
	do_action( 'give_payment_delete', $payment_id );
315
316
	if ( $donor_id ) {
317
318
		// Remove the payment ID from the donor
319
		Give()->customers->remove_payment( $donor_id, $payment_id );
320
321
	}
322
323
	// Remove the payment
324
	wp_delete_post( $payment_id, true );
325
326
	// Remove related sale log entries
327
	$give_logs->delete_logs(
328
		null,
329
		'sale',
330
		array(
331
			array(
332
				'key'   => '_give_log_payment_id',
333
				'value' => $payment_id
334
			)
335
		)
336
	);
337
338
	do_action( 'give_payment_deleted', $payment_id );
339
}
340
341
/**
342
 * Undoes a donation, including the decrease of donations and earning stats. Used for when refunding or deleting a donation
343
 *
344
 * @since 1.0
345
 *
346
 * @param int $form_id Form (Post) ID
347
 * @param int $payment_id Payment ID
348
 *
349
 * @return void
350
 */
351
function give_undo_purchase( $form_id, $payment_id ) {
352
353
	if ( give_is_test_mode() ) {
354
		return;
355
	}
356
357
	$amount = give_get_payment_amount( $payment_id );
358
359
	// decrease earnings
360
	give_decrease_earnings( $form_id, $amount );
361
362
	// decrease purchase count
363
	give_decrease_purchase_count( $form_id );
364
365
366
}
367
368
369
/**
370
 * Count Payments
371
 *
372
 * Returns the total number of payments recorded.
373
 *
374
 * @since 1.0
375
 *
376
 * @param array $args
377
 *
378
 * @return array $count Number of payments sorted by payment status
379
 */
380
function give_count_payments( $args = array() ) {
381
382
	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...
383
384
	$defaults = array(
385
		'user'       => null,
386
		's'          => null,
387
		'start-date' => null,
388
		'end-date'   => null,
389
	);
390
391
	$args = wp_parse_args( $args, $defaults );
392
393
	$join  = '';
394
	$where = "WHERE p.post_type = 'give_payment'";
395
396
	// Count payments for a specific user
397
	if ( ! empty( $args['user'] ) ) {
398
399
		if ( is_email( $args['user'] ) ) {
400
			$field = 'email';
401
		} elseif ( is_numeric( $args['user'] ) ) {
402
			$field = 'id';
403
		} else {
404
			$field = '';
405
		}
406
407
		$join = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
408
409
		if ( ! empty( $field ) ) {
410
			$where .= "
411
				AND m.meta_key = '_give_payment_user_{$field}'
412
				AND m.meta_value = '{$args['user']}'";
413
		}
414
415
		// Count payments for a search
416
	} elseif ( ! empty( $args['s'] ) ) {
417
418
		if ( is_email( $args['s'] ) || strlen( $args['s'] ) == 32 ) {
419
420
			if ( is_email( $args['s'] ) ) {
421
				$field = '_give_payment_user_email';
422
			} else {
423
				$field = '_give_payment_purchase_key';
424
			}
425
426
427
			$join = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
428
			$where .= "
429
				AND m.meta_key = '{$field}'
430
				AND m.meta_value = '{$args['s']}'";
431
432
		} elseif ( is_numeric( $args['s'] ) ) {
433
434
			$join = "LEFT JOIN $wpdb->postmeta m ON (p.ID = m.post_id)";
435
			$where .= "
436
				AND m.meta_key = '_give_payment_user_id'
437
				AND m.meta_value = '{$args['s']}'";
438
439
		} else {
440
			$where .= "AND ((p.post_title LIKE '%{$args['s']}%') OR (p.post_content LIKE '%{$args['s']}%'))";
441
		}
442
443
	}
444
445
	// Limit payments count by date
446
	if ( ! empty( $args['start-date'] ) && false !== strpos( $args['start-date'], '/' ) ) {
447
448
		$date_parts = explode( '/', $args['start-date'] );
449
		$month      = ! empty( $date_parts[0] ) && is_numeric( $date_parts[0] ) ? $date_parts[0] : 0;
450
		$day        = ! empty( $date_parts[1] ) && is_numeric( $date_parts[1] ) ? $date_parts[1] : 0;
451
		$year       = ! empty( $date_parts[2] ) && is_numeric( $date_parts[2] ) ? $date_parts[2] : 0;
452
453
		$is_date = checkdate( $month, $day, $year );
454
		if ( false !== $is_date ) {
455
456
			$date = new DateTime( $args['start-date'] );
457
			$where .= $wpdb->prepare( " AND p.post_date >= '%s'", $date->format( 'Y-m-d' ) );
458
459
		}
460
461
		// Fixes an issue with the payments list table counts when no end date is specified (partiy with stats class)
462
		if ( empty( $args['end-date'] ) ) {
463
			$args['end-date'] = $args['start-date'];
464
		}
465
466
	}
467
468
	if ( ! empty ( $args['end-date'] ) && false !== strpos( $args['end-date'], '/' ) ) {
469
470
		$date_parts = explode( '/', $args['end-date'] );
471
472
		$month = ! empty( $date_parts[0] ) ? $date_parts[0] : 0;
473
		$day   = ! empty( $date_parts[1] ) ? $date_parts[1] : 0;
474
		$year  = ! empty( $date_parts[2] ) ? $date_parts[2] : 0;
475
476
		$is_date = checkdate( $month, $day, $year );
477
		if ( false !== $is_date ) {
478
479
			$date = new DateTime( $args['end-date'] );
480
			$where .= $wpdb->prepare( " AND p.post_date <= '%s'", $date->format( 'Y-m-d' ) );
481
482
		}
483
484
	}
485
486
	$where = apply_filters( 'give_count_payments_where', $where );
487
	$join  = apply_filters( 'give_count_payments_join', $join );
488
489
	$query = "SELECT p.post_status,count( * ) AS num_posts
490
		FROM $wpdb->posts p
491
		$join
492
		$where
493
		GROUP BY p.post_status
494
	";
495
496
	$cache_key = md5( implode( '|', $args ) . $where );
497
498
	$count = wp_cache_get( $cache_key, 'counts' );
499
	if ( false !== $count ) {
500
		return $count;
501
	}
502
503
	$count = $wpdb->get_results( $query, ARRAY_A );
504
505
	$stats    = array();
506
	$statuses = get_post_stati();
507
	if ( isset( $statuses['private'] ) && empty( $args['s'] ) ) {
508
		unset( $statuses['private'] );
509
	}
510
511
	foreach ( $statuses as $state ) {
512
		$stats[ $state ] = 0;
513
	}
514
515
	foreach ( (array) $count as $row ) {
516
		if ( 'private' == $row['post_status'] && empty( $args['s'] ) ) {
517
			continue;
518
		}
519
520
		$stats[ $row['post_status'] ] = $row['num_posts'];
521
	}
522
523
	$stats = (object) $stats;
524
	wp_cache_set( $cache_key, $stats, 'counts' );
525
526
	return $stats;
527
}
528
529
530
/**
531
 * Check For Existing Payment
532
 *
533
 * @since 1.0
534
 *
535
 * @param int $payment_id Payment ID
536
 *
537
 * @return bool true if payment exists, false otherwise
538
 */
539
function give_check_for_existing_payment( $payment_id ) {
540
	$payment = get_post( $payment_id );
541
542
	if ( $payment && $payment->post_status == 'publish' ) {
543
		return true; // Payment exists
544
	}
545
546
	return false; // This payment doesn't exist
547
}
548
549
/**
550
 * Get Payment Status
551
 *
552
 * @since 1.0
553
 *
554
 * @param WP_Post $payment
555
 * @param bool $return_label Whether to return the donation status or not
556
 *
557
 * @return bool|mixed if payment status exists, false otherwise
558
 */
559
function give_get_payment_status( $payment, $return_label = false ) {
560
	if ( ! is_object( $payment ) || ! isset( $payment->post_status ) ) {
561
		return false;
562
	}
563
564
	$statuses = give_get_payment_statuses();
565
	if ( ! is_array( $statuses ) || empty( $statuses ) ) {
566
		return false;
567
	}
568
569
	if ( array_key_exists( $payment->post_status, $statuses ) ) {
570
		if ( true === $return_label ) {
571
			return $statuses[ $payment->post_status ];
572
		} else {
573
			return array_search( $payment->post_status, $statuses );
574
		}
575
	}
576
577
	return false;
578
}
579
580
/**
581
 * Retrieves all available statuses for payments.
582
 *
583
 * @since 1.0
584
 * @return array $payment_status All the available payment statuses
585
 */
586
function give_get_payment_statuses() {
587
	$payment_statuses = array(
588 34
		'pending'     => __( 'Pending', 'give' ),
589 34
		'publish'     => __( 'Complete', 'give' ),
590 34
		'refunded'    => __( 'Refunded', 'give' ),
591 34
		'failed'      => __( 'Failed', 'give' ),
592 34
		'cancelled'   => __( 'Cancelled', 'give' ),
593 34
		'abandoned'   => __( 'Abandoned', 'give' ),
594 34
		'preapproval' => __( 'Pre-Approved', 'give' ),
595 34
		'revoked'     => __( 'Revoked', 'give' )
596 34
	);
597
598 34
	return apply_filters( 'give_payment_statuses', $payment_statuses );
599
}
600
601
/**
602
 * Get Payment Status Keys
603
 *
604
 * @description Retrieves keys for all available statuses for payments
605
 *
606
 * @since       1.0
607
 * @return array $payment_status All the available payment statuses
608
 */
609
function give_get_payment_status_keys() {
610
	$statuses = array_keys( give_get_payment_statuses() );
611
	asort( $statuses );
612
613
	return array_values( $statuses );
614
}
615
616
/**
617
 * Get Earnings By Date
618
 *
619
 * @since 1.0
620
 *
621
 * @param int $day Day number
622
 * @param int $month_num Month number
623
 * @param int $year Year
624
 * @param int $hour Hour
625
 *
626
 * @return int $earnings Earnings
627
 */
628
function give_get_earnings_by_date( $day = null, $month_num, $year = null, $hour = null ) {
629
630
	// This is getting deprecated soon. Use Give_Payment_Stats with the get_earnings() method instead
631
632
	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...
633
634
	$args = array(
635
		'post_type'              => 'give_payment',
636
		'nopaging'               => true,
637
		'year'                   => $year,
638
		'monthnum'               => $month_num,
639
		'post_status'            => array( 'publish', 'revoked' ),
640
		'fields'                 => 'ids',
641
		'update_post_term_cache' => false
642
	);
643
	if ( ! empty( $day ) ) {
644
		$args['day'] = $day;
645
	}
646
647
	if ( ! empty( $hour ) ) {
648
		$args['hour'] = $hour;
649
	}
650
651
	$args = apply_filters( 'give_get_earnings_by_date_args', $args );
652
	$key  = 'give_stats_' . substr( md5( serialize( $args ) ), 0, 15 );
653
654
	if ( ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'give-refresh-reports' ) ) {
655
		$earnings = false;
656
	} else {
657
		$earnings = get_transient( $key );
658
	}
659
660
	if ( false === $earnings ) {
661
		$sales    = get_posts( $args );
662
		$earnings = 0;
663
		if ( $sales ) {
664
			$sales = implode( ',', $sales );
665
			$earnings += $wpdb->get_var( "SELECT SUM(meta_value) FROM $wpdb->postmeta WHERE meta_key = '_give_payment_total' AND post_id IN({$sales})" );
666
667
		}
668
		// Cache the results for one hour
669
		set_transient( $key, $earnings, HOUR_IN_SECONDS );
670
	}
671
672
	return round( $earnings, 2 );
673
}
674
675
/**
676
 * Get Donations (sales) By Date
677
 *
678
 * @since  1.0
679
 *
680
 * @param int $day Day number
681
 * @param int $month_num Month number
682
 * @param int $year Year
683
 * @param int $hour Hour
684
 *
685
 * @return int $count Sales
686
 */
687
function give_get_sales_by_date( $day = null, $month_num = null, $year = null, $hour = null ) {
688
689
	// This is getting deprecated soon. Use Give_Payment_Stats with the get_sales() method instead
690
	$args = array(
691
		'post_type'              => 'give_payment',
692
		'nopaging'               => true,
693
		'year'                   => $year,
694
		'fields'                 => 'ids',
695
		'post_status'            => array( 'publish', 'revoked' ),
696
		'update_post_meta_cache' => false,
697
		'update_post_term_cache' => false
698
	);
699
700
	if ( ! empty( $month_num ) ) {
701
		$args['monthnum'] = $month_num;
702
	}
703
704
	if ( ! empty( $day ) ) {
705
		$args['day'] = $day;
706
	}
707
708
	if ( ! empty( $hour ) ) {
709
		$args['hour'] = $hour;
710
	}
711
712
	$args = apply_filters( 'give_get_sales_by_date_args', $args );
713
	$key  = 'give_stats_' . substr( md5( serialize( $args ) ), 0, 15 );
714
715
	if ( ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'give-refresh-reports' ) ) {
716
		$count = false;
717
	} else {
718
		$count = get_transient( $key );
719
	}
720
721
	if ( false === $count ) {
722
		$sales = new WP_Query( $args );
723
		$count = (int) $sales->post_count;
724
		// Cache the results for one hour
725
		set_transient( $key, $count, HOUR_IN_SECONDS );
726
	}
727
728
	return $count;
729
}
730
731
/**
732
 * Checks whether a payment has been marked as complete.
733
 *
734
 * @since 1.0
735
 *
736
 * @param int $payment_id Payment ID to check against
737
 *
738
 * @return bool true if complete, false otherwise
739
 */
740
function give_is_payment_complete( $payment_id ) {
741
	$payment = get_post( $payment_id );
742
	$ret     = false;
743
	if ( $payment && $payment->post_status == 'publish' ) {
744
		$ret = true;
745
	}
746
747
	return apply_filters( 'give_is_payment_complete', $ret, $payment_id, $payment->post_status );
748
}
749
750
/**
751
 * Get Total Sales (Donations)
752
 *
753
 * @since 1.0
754
 * @return int $count Total sales
755
 */
756
function give_get_total_sales() {
757
758
	$payments = give_count_payments();
759
760
	return $payments->revoked + $payments->publish;
761
}
762
763
/**
764
 * Get Total Earnings
765
 *
766
 * @since 1.0
767
 * @return float $total Total earnings
768
 */
769
function give_get_total_earnings() {
770
771 34
	$total = get_option( 'give_earnings_total', 0 );
772
773
	// If no total stored in DB, use old method of calculating total earnings
774 34
	if ( ! $total ) {
775
776 34
		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...
777
778 34
		$total = get_transient( 'give_earnings_total' );
779
780 34
		if ( false === $total ) {
781
782 34
			$total = (float) 0;
783
784 34
			$args = apply_filters( 'give_get_total_earnings_args', array(
785 34
				'offset' => 0,
786 34
				'number' => - 1,
787 34
				'status' => array( 'publish', 'revoked' ),
788
				'fields' => 'ids'
789 34
			) );
790
791
792 34
			$payments = give_get_payments( $args );
793 34
			if ( $payments ) {
794
795
				/*
796
				 * If performing a purchase, we need to skip the very last payment in the database, since it calls
797
				 * give_increase_total_earnings() on completion, which results in duplicated earnings for the very
798
				 * first purchase
799
				 */
800
801 34
				if ( did_action( 'give_update_payment_status' ) ) {
802 34
					array_pop( $payments );
803 34
				}
804
805 34
				if ( ! empty( $payments ) ) {
806
					$payments = implode( ',', $payments );
807
					$total += $wpdb->get_var( "SELECT SUM(meta_value) FROM $wpdb->postmeta WHERE meta_key = '_give_payment_total' AND post_id IN({$payments})" );
808
				}
809
810 34
			}
811
812
			// Cache results for 1 day. This cache is cleared automatically when a payment is made
813 34
			set_transient( 'give_earnings_total', $total, 86400 );
814
815
			// Store the total for the first time
816 34
			update_option( 'give_earnings_total', $total );
817 34
		}
818 34
	}
819
820 34
	if ( $total < 0 ) {
821
		$total = 0; // Don't ever show negative earnings
822
	}
823
824 34
	return apply_filters( 'give_total_earnings', round( $total, give_currency_decimal_filter() ) );
825
}
826
827
/**
828
 * Increase the Total Earnings
829
 *
830
 * @since 1.0
831
 *
832
 * @param $amount int The amount you would like to increase the total earnings by.
833
 *
834
 * @return float $total Total earnings
835
 */
836
function give_increase_total_earnings( $amount = 0 ) {
837 34
	$total = give_get_total_earnings();
838 34
	$total += $amount;
839 34
	update_option( 'give_earnings_total', $total );
840
841 34
	return $total;
842
}
843
844
/**
845
 * Decrease the Total Earnings
846
 *
847
 * @since 1.0
848
 *
849
 * @param $amount int The amount you would like to decrease the total earnings by.
850
 *
851
 * @return float $total Total earnings
852
 */
853
function give_decrease_total_earnings( $amount = 0 ) {
854
	$total = give_get_total_earnings();
855
	$total -= $amount;
856
	if ( $total < 0 ) {
857
		$total = 0;
858
	}
859
	update_option( 'give_earnings_total', $total );
860
861
	return $total;
862
}
863
864
/**
865
 * Get Payment Meta for a specific Payment
866
 *
867
 * @since 1.0
868
 *
869
 * @param int $payment_id Payment ID
870
 * @param string $meta_key The meta key to pull
871
 * @param bool $single Pull single meta entry or as an object
872
 *
873
 * @return mixed $meta Payment Meta
874
 */
875
function give_get_payment_meta( $payment_id = 0, $meta_key = '_give_payment_meta', $single = true ) {
876
877 34
	$meta = get_post_meta( $payment_id, $meta_key, $single );
878
879 34
	if ( $meta_key === '_give_payment_meta' ) {
880
881 34
		if ( empty( $meta['key'] ) ) {
882 34
			$meta['key'] = give_get_payment_key( $payment_id );
883 34
		}
884
885 34
		if ( empty( $meta['email'] ) ) {
886 34
			$meta['email'] = give_get_payment_user_email( $payment_id );
887 34
		}
888
889 34
		if ( empty( $meta['date'] ) ) {
890 34
			$meta['date'] = get_post_field( 'post_date', $payment_id );
891 34
		}
892 34
	}
893
894 34
	$meta = apply_filters( 'give_get_payment_meta_' . $meta_key, $meta, $payment_id );
895
896 34
	return apply_filters( 'give_get_payment_meta', $meta, $payment_id, $meta_key );
897
}
898
899
/**
900
 * Update the meta for a payment
901
 *
902
 * @param  integer $payment_id Payment ID
903
 * @param  string $meta_key Meta key to update
904
 * @param  string $meta_value Value to update to
905
 * @param  string $prev_value Previous value
906
 *
907
 * @return mixed               Meta ID if successful, false if unsuccessful
908
 */
909
function give_update_payment_meta( $payment_id = 0, $meta_key = '', $meta_value = '', $prev_value = '' ) {
910
911 34
	if ( empty( $payment_id ) || empty( $meta_key ) ) {
912
		return;
913
	}
914
915 34
	if ( $meta_key == 'key' || $meta_key == 'date' ) {
916
917
		$current_meta              = give_get_payment_meta( $payment_id );
918
		$current_meta[ $meta_key ] = $meta_value;
919
920
		$meta_key   = '_give_payment_meta';
921
		$meta_value = $current_meta;
922
923 34
	} else if ( $meta_key == 'email' || $meta_key == '_give_payment_user_email' ) {
924
925 34
		$meta_value = apply_filters( 'give_give_update_payment_meta_' . $meta_key, $meta_value, $payment_id );
926 34
		update_post_meta( $payment_id, '_give_payment_user_email', $meta_value );
927
928 34
		$current_meta                       = give_get_payment_meta( $payment_id );
929 34
		$current_meta['user_info']['email'] = $meta_value;
930
931 34
		$meta_key   = '_give_payment_meta';
932 34
		$meta_value = $current_meta;
933
934 34
	}
935
936 34
	$meta_value = apply_filters( 'give_give_update_payment_meta_' . $meta_key, $meta_value, $payment_id );
937
938 34
	return update_post_meta( $payment_id, $meta_key, $meta_value, $prev_value );
939
}
940
941
/**
942
 * Get the user_info Key from Payment Meta
943
 *
944
 * @since 1.0
945
 *
946
 * @param int $payment_id Payment ID
947
 *
948
 * @return array $user_info User Info Meta Values
949
 */
950
function give_get_payment_meta_user_info( $payment_id ) {
951 34
	$payment_meta = give_get_payment_meta( $payment_id );
952 34
	$user_info    = isset( $payment_meta['user_info'] ) ? maybe_unserialize( $payment_meta['user_info'] ) : false;
953
954 34
	return apply_filters( 'give_payment_meta_user_info', $user_info );
955
}
956
957
/**
958
 * Get the donations Key from Payment Meta
959
 *
960
 * @description Retrieves the form_id from a (Previously titled give_get_payment_meta_donations)
961
 * @since       1.0
962
 *
963
 * @param int $payment_id Payment ID
964
 *
965
 * @return int $form_id
966
 */
967
function give_get_payment_form_id( $payment_id ) {
968
	$payment_meta = give_get_payment_meta( $payment_id );
969
970
	$form_id = isset( $payment_meta['form_id'] ) ? $payment_meta['form_id'] : 0;
971
972
	return apply_filters( 'give_get_payment_form_id', $form_id );
973
}
974
975
/**
976
 * Get the user email associated with a payment
977
 *
978
 * @since 1.0
979
 *
980
 * @param int $payment_id Payment ID
981
 *
982
 * @return string $email User Email
983
 */
984
function give_get_payment_user_email( $payment_id ) {
985 34
	$email = give_get_payment_meta( $payment_id, '_give_payment_user_email', true );
986
987 34
	return apply_filters( 'give_payment_user_email', $email );
988
}
989
990
/**
991
 * Is the payment provided associated with a user account
992
 *
993
 * @since  1.3
994
 *
995
 * @param  int $payment_id The payment ID
996
 *
997
 * @return bool            If the payment is associated with a user (false) or not (true)
998
 */
999
function give_is_guest_payment( $payment_id ) {
1000
	$payment_user_id  = give_get_payment_user_id( $payment_id );
1001
	$is_guest_payment = ! empty( $payment_user_id ) && $payment_user_id > 0 ? false : true;
1002
1003
	return (bool) apply_filters( 'give_is_guest_payment', $is_guest_payment, $payment_id );
1004
}
1005
1006
/**
1007
 * Get the user ID associated with a payment
1008
 *
1009
 * @since 1.3
1010
 *
1011
 * @param int $payment_id Payment ID
1012
 *
1013
 * @return string $user_id User ID
1014
 */
1015
function give_get_payment_user_id( $payment_id ) {
1016
1017
	$user_id = - 1;
1018
1019
	// check the customer record first
1020
	$customer_id = give_get_payment_customer_id( $payment_id );
1021
	$customer    = new Give_Customer( $customer_id );
1022
1023
	if ( ! empty( $customer->user_id ) && $customer->user_id > 0 ) {
1024
		$user_id = $customer->user_id;
1025
	}
1026
1027
	// check the payment meta if we're still not finding a user with the customer record
1028
	if ( empty( $user_id ) || $user_id < 1 ) {
1029
		$payment_meta_user_id = give_get_payment_meta( $payment_id, '_give_payment_user_id', true );
1030
1031
		if ( ! empty( $payment_meta_user_id ) ) {
1032
			$user_id = $payment_meta_user_id;
1033
		}
1034
	}
1035
1036
	// Last ditch effort is to connect payment email with a user in the user table
1037
	if ( empty( $user_id ) || $user_id < 1 ) {
1038
		$payment_email = give_get_payment_user_email( $payment_id );
1039
		$user          = get_user_by( 'email', $payment_email );
1040
1041
		if ( false !== $user ) {
1042
			$user_id = $user->ID;
1043
		}
1044
	}
1045
1046
	return apply_filters( 'give_payment_user_id', (int) $user_id );
1047
}
1048
1049
/**
1050
 * Get the donor ID associated with a payment
1051
 *
1052
 * @since 1.0
1053
 *
1054
 * @param int $payment_id Payment ID
1055
 *
1056
 * @return string $donor_id Donor ID
1057
 */
1058
function give_get_payment_customer_id( $payment_id ) {
1059 34
	$customer_id = get_post_meta( $payment_id, '_give_payment_customer_id', true );
1060
1061 34
	return apply_filters( '_give_payment_customer_id', $customer_id );
1062
}
1063
1064
/**
1065
 * Get the IP address used to make a purchase
1066
 *
1067
 * @since 1.0
1068
 *
1069
 * @param int $payment_id Payment ID
1070
 *
1071
 * @return string $ip User IP
1072
 */
1073
function give_get_payment_user_ip( $payment_id ) {
1074
	$ip = give_get_payment_meta( $payment_id, '_give_payment_user_ip', true );
1075
1076
	return apply_filters( 'give_payment_user_ip', $ip );
1077
}
1078
1079
/**
1080
 * Get the date a payment was completed
1081
 *
1082
 * @since 1.0
1083
 *
1084
 * @param int $payment_id Payment ID
1085
 *
1086
 * @return string $date The date the payment was completed
1087
 */
1088
function give_get_payment_completed_date( $payment_id = 0 ) {
1089
1090 34
	$payment = get_post( $payment_id );
1091
1092 34
	if ( 'pending' == $payment->post_status || 'preapproved' == $payment->post_status ) {
1093
		return false; // This payment was never completed
1094
	}
1095
1096 34
	$date = ( $date = give_get_payment_meta( $payment_id, '_give_completed_date', true ) ) ? $date : $payment->modified_date;
1097
1098 34
	return apply_filters( 'give_payment_completed_date', $date, $payment_id );
1099
}
1100
1101
/**
1102
 * Get the gateway associated with a payment
1103
 *
1104
 * @since 1.0
1105
 *
1106
 * @param int $payment_id Payment ID
1107
 *
1108
 * @return string $gateway Gateway
1109
 */
1110
function give_get_payment_gateway( $payment_id ) {
1111 34
	$gateway = give_get_payment_meta( $payment_id, '_give_payment_gateway', true );
1112
1113 34
	return apply_filters( 'give_payment_gateway', $gateway );
1114
}
1115
1116
/**
1117
 * Get the currency code a payment was made in
1118
 *
1119
 * @since 1.0
1120
 *
1121
 * @param int $payment_id Payment ID
1122
 *
1123
 * @return string $currency The currency code
1124
 */
1125
function give_get_payment_currency_code( $payment_id = 0 ) {
1126 34
	$meta     = give_get_payment_meta( $payment_id );
1127 34
	$currency = isset( $meta['currency'] ) ? $meta['currency'] : give_get_currency();
1128
1129 34
	return apply_filters( 'give_payment_currency_code', $currency, $payment_id );
1130
}
1131
1132
/**
1133
 * Get the currency name a payment was made in
1134
 *
1135
 * @since 1.0
1136
 *
1137
 * @param int $payment_id Payment ID
1138
 *
1139
 * @return string $currency The currency name
1140
 */
1141
function give_get_payment_currency( $payment_id = 0 ) {
1142
	$currency = give_get_payment_currency_code( $payment_id );
1143
1144
	return apply_filters( 'give_payment_currency', give_get_currency_name( $currency ), $payment_id );
1145
}
1146
1147
/**
1148
 * Get the purchase key for a purchase
1149
 *
1150
 * @since 1.0
1151
 *
1152
 * @param int $payment_id Payment ID
1153
 *
1154
 * @return string $key Purchase key
1155
 */
1156
function give_get_payment_key( $payment_id = 0 ) {
1157 34
	$key = give_get_payment_meta( $payment_id, '_give_payment_purchase_key', true );
1158
1159 34
	return apply_filters( 'give_payment_key', $key, $payment_id );
1160
}
1161
1162
/**
1163
 * Get the payment order number
1164
 *
1165
 * This will return the payment ID if sequential order numbers are not enabled or the order number does not exist
1166
 *
1167
 * @since 1.0
1168
 *
1169
 * @param int $payment_id Payment ID
1170
 *
1171
 * @return string $number Payment order number
1172
 */
1173
function give_get_payment_number( $payment_id = 0 ) {
1174
1175 34
	$number = $payment_id;
1176
1177 34
	if ( give_get_option( 'enable_sequential' ) ) {
1178
1179
		$number = give_get_payment_meta( $payment_id, '_give_payment_number', true );
1180
1181
		if ( ! $number ) {
1182
1183
			$number = $payment_id;
1184
1185
		}
1186
1187
	}
1188
1189 34
	return apply_filters( 'give_payment_number', $number, $payment_id );
1190
}
1191
1192
/**
1193
 * Formats the payment number with the prefix and postfix
1194
 *
1195
 * @since  1.3
1196
 *
1197
 * @param  int $number The payment number to format
1198
 *
1199
 * @return string      The formatted payment number
1200
 */
1201
function give_format_payment_number( $number ) {
1202
1203
	if ( ! give_get_option( 'enable_sequential' ) ) {
1204
		return $number;
1205
	}
1206
1207
	if ( ! is_numeric( $number ) ) {
1208
		return $number;
1209
	}
1210
1211
	$prefix  = give_get_option( 'sequential_prefix' );
1212
	$number  = absint( $number );
1213
	$postfix = give_get_option( 'sequential_postfix' );
1214
1215
	$formatted_number = $prefix . $number . $postfix;
1216
1217
	return apply_filters( 'give_format_payment_number', $formatted_number, $prefix, $number, $postfix );
1218
}
1219
1220
/**
1221
 * Gets the next available order number
1222
 *
1223
 * This is used when inserting a new payment
1224
 *
1225
 * @since 1.0
1226
 * @return string $number The next available payment number
1227
 */
1228
function give_get_next_payment_number() {
1229
1230
	if ( ! give_get_option( 'enable_sequential' ) ) {
1231
		return false;
1232
	}
1233
1234
	$number           = get_option( 'give_last_payment_number' );
1235
	$start            = give_get_option( 'sequential_start', 1 );
1236
	$increment_number = true;
1237
1238
	if ( false !== $number ) {
1239
1240
		if ( empty( $number ) ) {
1241
1242
			$number           = $start;
1243
			$increment_number = false;
1244
1245
		}
1246
1247
	} else {
1248
1249
		// This case handles the first addition of the new option, as well as if it get's deleted for any reason
1250
		$payments     = new Give_Payments_Query( array(
1251
			'number'  => 1,
1252
			'order'   => 'DESC',
1253
			'orderby' => 'ID',
1254
			'output'  => 'posts',
1255
			'fields'  => 'ids'
1256
		) );
1257
		$last_payment = $payments->get_payments();
1258
1259
		if ( $last_payment ) {
1260
1261
			$number = give_get_payment_number( $last_payment[0] );
1262
1263
		}
1264
1265
		if ( ! empty( $number ) && $number !== $last_payment[0] ) {
1266
1267
			$number = give_remove_payment_prefix_postfix( $number );
1268
1269
		} else {
1270
1271
			$number           = $start;
1272
			$increment_number = false;
1273
		}
1274
1275
	}
1276
1277
	$increment_number = apply_filters( 'give_increment_payment_number', $increment_number, $number );
1278
1279
	if ( $increment_number ) {
1280
		$number ++;
1281
	}
1282
1283
	return apply_filters( 'give_get_next_payment_number', $number );
1284
}
1285
1286
/**
1287
 * Given a given a number, remove the pre/postfix
1288
 *
1289
 * @since  1.3
1290
 *
1291
 * @param  string $number The formatted Current Number to increment
1292
 *
1293
 * @return string          The new Payment number without prefix and postfix
1294
 */
1295
function give_remove_payment_prefix_postfix( $number ) {
1296
1297
	$prefix  = give_get_option( 'sequential_prefix' );
1298
	$postfix = give_get_option( 'sequential_postfix' );
1299
1300
	// Remove prefix
1301
	$number = preg_replace( '/' . $prefix . '/', '', $number, 1 );
1302
1303
	// Remove the postfix
1304
	$length      = strlen( $number );
1305
	$postfix_pos = strrpos( $number, $postfix );
1306
	if ( false !== $postfix_pos ) {
1307
		$number = substr_replace( $number, '', $postfix_pos, $length );
1308
	}
1309
1310
	// Ensure it's a whole number
1311
	$number = intval( $number );
1312
1313
	return apply_filters( 'give_remove_payment_prefix_postfix', $number, $prefix, $postfix );
1314
1315
}
1316
1317
1318
/**
1319
 * Get Payment Amount
1320
 *
1321
 * @description 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.
1322
 *
1323
 * @since       1.0
1324
 *
1325
 * @param int $payment_id Payment ID
1326
 *
1327
 * @return string $amount Fully formatted payment amount
1328
 */
1329
function give_payment_amount( $payment_id = 0 ) {
1330
	$amount = give_get_payment_amount( $payment_id );
1331
1332
	return give_currency_filter( give_format_amount( $amount ), give_get_payment_currency_code( $payment_id ) );
1333
}
1334
1335
/**
1336
 * Get the amount associated with a payment
1337
 *
1338
 * @access public
1339
 * @since  1.0
1340
 *
1341
 * @param int $payment_id Payment ID
1342
 *
1343
 * @return mixed|void
1344
 */
1345
function give_get_payment_amount( $payment_id ) {
1346
1347 34
	$amount = give_get_payment_meta( $payment_id, '_give_payment_total', true );
1348
1349 34
	if ( empty( $amount ) && '0.00' != $amount ) {
1350 1
		$meta = give_get_payment_meta( $payment_id, '_give_payment_meta', true );
1351 1
		$meta = maybe_unserialize( $meta );
1352
1353 1
		if ( isset( $meta['amount'] ) ) {
1354
			$amount = $meta['amount'];
1355
		}
1356 1
	}
1357
1358 34
	return apply_filters( 'give_payment_amount', floatval( $amount ), $payment_id );
1359
}
1360
1361
1362
/**
1363
 * Retrieves the transaction ID for the given payment
1364
 *
1365
 * @since  1.0
1366
 *
1367
 * @param int $payment_id Payment ID
1368
 *
1369
 * @return string The Transaction ID
1370
 */
1371
function give_get_payment_transaction_id( $payment_id = 0 ) {
1372
1373 10
	$transaction_id = false;
1374 10
	$transaction_id = give_get_payment_meta( $payment_id, '_give_payment_transaction_id', true );
1375
1376 10
	if ( empty( $transaction_id ) ) {
1377
1378 10
		$gateway        = give_get_payment_gateway( $payment_id );
1379 10
		$transaction_id = apply_filters( 'give_get_payment_transaction_id-' . $gateway, $payment_id );
1380
1381 10
	}
1382
1383 10
	return apply_filters( 'give_get_payment_transaction_id', $transaction_id, $payment_id );
1384
}
1385
1386
/**
1387
 * Sets a Transaction ID in post meta for the given Payment ID
1388
 *
1389
 * @since  1.0
1390
 *
1391
 * @param int $payment_id Payment ID
1392
 * @param string $transaction_id The transaction ID from the gateway
1393
 *
1394
 * @return bool|mixed
1395
 */
1396
function give_set_payment_transaction_id( $payment_id = 0, $transaction_id = '' ) {
1397
1398
	if ( empty( $payment_id ) || empty( $transaction_id ) ) {
1399
		return false;
1400
	}
1401
1402
	$transaction_id = apply_filters( 'give_set_payment_transaction_id', $transaction_id, $payment_id );
1403
1404
	return give_update_payment_meta( $payment_id, '_give_payment_transaction_id', $transaction_id );
1405
}
1406
1407
/**
1408
 * Retrieve the purchase ID based on the purchase key
1409
 *
1410
 * @since 1.0
1411
 * @global object $wpdb Used to query the database using the WordPress
1412
 *                      Database API
1413
 *
1414
 * @param string $key the purchase key to search for
1415
 *
1416
 * @return int $purchase Purchase ID
1417
 */
1418
function give_get_purchase_id_by_key( $key ) {
1419
	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...
1420
1421
	$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 ) );
1422
1423
	if ( $purchase != null ) {
1424
		return $purchase;
1425
	}
1426
1427
	return 0;
1428
}
1429
1430
1431
/**
1432
 * Retrieve the purchase ID based on the transaction ID
1433
 *
1434
 * @since 1.3
1435
 * @global object $wpdb Used to query the database using the WordPress
1436
 *                      Database API
1437
 *
1438
 * @param string $key the transaction ID to search for
1439
 *
1440
 * @return int $purchase Purchase ID
1441
 */
1442
function give_get_purchase_id_by_transaction_id( $key ) {
1443
	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...
1444
1445
	$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 ) );
1446
1447
	if ( $purchase != null ) {
1448
		return $purchase;
1449
	}
1450
1451
	return 0;
1452
}
1453
1454
/**
1455
 * Retrieve all notes attached to a purchase
1456
 *
1457
 * @since 1.0
1458
 *
1459
 * @param int $payment_id The payment ID to retrieve notes for
1460
 * @param string $search Search for notes that contain a search term
1461
 *
1462
 * @return array $notes Payment Notes
1463
 */
1464
function give_get_payment_notes( $payment_id = 0, $search = '' ) {
1465
1466
	if ( empty( $payment_id ) && empty( $search ) ) {
1467
		return false;
1468
	}
1469
1470
	remove_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1471
	remove_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10, 2 );
1472
1473
	$notes = get_comments( array( 'post_id' => $payment_id, 'order' => 'ASC', 'search' => $search ) );
1474
1475
	add_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1476
	add_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10, 2 );
1477
1478
	return $notes;
1479
}
1480
1481
1482
/**
1483
 * Add a note to a payment
1484
 *
1485
 * @since 1.0
1486
 *
1487
 * @param int $payment_id The payment ID to store a note for
1488
 * @param string $note The note to store
1489
 *
1490
 * @return int The new note ID
1491
 */
1492
function give_insert_payment_note( $payment_id = 0, $note = '' ) {
1493 34
	if ( empty( $payment_id ) ) {
1494
		return false;
1495
	}
1496
1497 34
	do_action( 'give_pre_insert_payment_note', $payment_id, $note );
1498
1499 34
	$note_id = wp_insert_comment( wp_filter_comment( array(
1500 34
		'comment_post_ID'      => $payment_id,
1501 34
		'comment_content'      => $note,
1502 34
		'user_id'              => is_admin() ? get_current_user_id() : 0,
1503 34
		'comment_date'         => current_time( 'mysql' ),
1504 34
		'comment_date_gmt'     => current_time( 'mysql', 1 ),
1505 34
		'comment_approved'     => 1,
1506 34
		'comment_parent'       => 0,
1507 34
		'comment_author'       => '',
1508 34
		'comment_author_IP'    => '',
1509 34
		'comment_author_url'   => '',
1510 34
		'comment_author_email' => '',
1511
		'comment_type'         => 'give_payment_note'
1512
1513 34
	) ) );
1514
1515 34
	do_action( 'give_insert_payment_note', $note_id, $payment_id, $note );
1516
1517 34
	return $note_id;
1518
}
1519
1520
/**
1521
 * Deletes a payment note
1522
 *
1523
 * @since 1.0
1524
 *
1525
 * @param int $comment_id The comment ID to delete
1526
 * @param int $payment_id The payment ID the note is connected to
1527
 *
1528
 * @return bool True on success, false otherwise
1529
 */
1530
function give_delete_payment_note( $comment_id = 0, $payment_id = 0 ) {
1531
	if ( empty( $comment_id ) ) {
1532
		return false;
1533
	}
1534
1535
	do_action( 'give_pre_delete_payment_note', $comment_id, $payment_id );
1536
	$ret = wp_delete_comment( $comment_id, true );
1537
	do_action( 'give_post_delete_payment_note', $comment_id, $payment_id );
1538
1539
	return $ret;
1540
}
1541
1542
/**
1543
 * Gets the payment note HTML
1544
 *
1545
 * @since 1.0
1546
 *
1547
 * @param     object /int $note The comment object or ID
1548
 * @param int $payment_id The payment ID the note is connected to
1549
 *
1550
 * @return string
1551
 */
1552
function give_get_payment_note_html( $note, $payment_id = 0 ) {
1553
1554
	if ( is_numeric( $note ) ) {
1555
		$note = get_comment( $note );
1556
	}
1557
1558
	if ( ! empty( $note->user_id ) ) {
1559
		$user = get_userdata( $note->user_id );
1560
		$user = $user->display_name;
1561
	} else {
1562
		$user = __( 'System', 'give' );
1563
	}
1564
1565
	$date_format = get_option( 'date_format' ) . ', ' . get_option( 'time_format' );
1566
1567
	$delete_note_url = wp_nonce_url( add_query_arg( array(
1568
		'give-action' => 'delete_payment_note',
1569
		'note_id'     => $note->comment_ID,
1570
		'payment_id'  => $payment_id
1571
	) ), 'give_delete_payment_note_' . $note->comment_ID );
1572
1573
	$note_html = '<div class="give-payment-note" id="give-payment-note-' . $note->comment_ID . '">';
1574
	$note_html .= '<p>';
1575
	$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/>';
1576
	$note_html .= $note->comment_content;
1577
	$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 ) . '" title="' . __( 'Delete this payment note', 'give' ) . '">' . __( 'Delete', 'give' ) . '</a>';
1578
	$note_html .= '</p>';
1579
	$note_html .= '</div>';
1580
1581
	return $note_html;
1582
1583
}
1584
1585
/**
1586
 * Exclude notes (comments) on give_payment post type from showing in Recent
1587
 * Comments widgets
1588
 *
1589
 * @since 1.0
1590
 *
1591
 * @param obj $query WordPress Comment Query Object
1592
 *
1593
 * @return void
1594
 */
1595
function give_hide_payment_notes( $query ) {
1596
	global $wp_version;
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...
1597
1598
	if ( version_compare( floatval( $wp_version ), '4.1', '>=' ) ) {
1599
		$types = isset( $query->query_vars['type__not_in'] ) ? $query->query_vars['type__not_in'] : array();
1600
		if ( ! is_array( $types ) ) {
1601
			$types = array( $types );
1602
		}
1603
		$types[]                           = 'give_payment_note';
1604
		$query->query_vars['type__not_in'] = $types;
1605
	}
1606
}
1607
1608
add_action( 'pre_get_comments', 'give_hide_payment_notes', 10 );
1609
1610
/**
1611
 * Exclude notes (comments) on give_payment post type from showing in Recent Comments widgets
1612
 *
1613
 * @since 1.0
1614
 *
1615
 * @param array $clauses Comment clauses for comment query
1616
 * @param obj $wp_comment_query WordPress Comment Query Object
1617
 *
1618
 * @return array $clauses Updated comment clauses
1619
 */
1620
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...
1621
	global $wpdb, $wp_version;
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...
1622
1623
	if ( version_compare( floatval( $wp_version ), '4.1', '<' ) ) {
1624
		$clauses['where'] .= ' AND comment_type != "give_payment_note"';
1625
	}
1626
1627
	return $clauses;
1628
}
1629
1630
add_filter( 'comments_clauses', 'give_hide_payment_notes_pre_41', 10, 2 );
1631
1632
1633
/**
1634
 * Exclude notes (comments) on give_payment post type from showing in comment feeds
1635
 *
1636
 * @since 1.0
1637
 *
1638
 * @param array $where
1639
 * @param obj $wp_comment_query WordPress Comment Query Object
1640
 *
1641
 * @return array $where
1642
 */
1643
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...
1644
	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...
1645
1646
	$where .= $wpdb->prepare( " AND comment_type != %s", 'give_payment_note' );
1647
1648
	return $where;
1649
}
1650
1651
add_filter( 'comment_feed_where', 'give_hide_payment_notes_from_feeds', 10, 2 );
1652
1653
1654
/**
1655
 * Remove Give Comments from the wp_count_comments function
1656
 *
1657
 * @access public
1658
 * @since  1.0
1659
 *
1660
 * @param array $stats (empty from core filter)
1661
 * @param int $post_id Post ID
1662
 *
1663
 * @return array Array of comment counts
1664
 */
1665
function give_remove_payment_notes_in_comment_counts( $stats, $post_id ) {
1666
	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...
1667
1668
	if ( 'index.php' != $pagenow ) {
1669
		return $stats;
1670
	}
1671
1672
	$post_id = (int) $post_id;
1673
1674
	if ( apply_filters( 'give_count_payment_notes_in_comments', false ) ) {
1675
		return $stats;
1676
	}
1677
1678
	$stats = wp_cache_get( "comments-{$post_id}", 'counts' );
1679
1680
	if ( false !== $stats ) {
1681
		return $stats;
1682
	}
1683
1684
	$where = 'WHERE comment_type != "give_payment_note"';
1685
1686
	if ( $post_id > 0 ) {
1687
		$where .= $wpdb->prepare( " AND comment_post_ID = %d", $post_id );
1688
	}
1689
1690
	$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A );
1691
1692
	$total    = 0;
1693
	$approved = array(
1694
		'0'            => 'moderated',
1695
		'1'            => 'approved',
1696
		'spam'         => 'spam',
1697
		'trash'        => 'trash',
1698
		'post-trashed' => 'post-trashed'
1699
	);
1700
	foreach ( (array) $count as $row ) {
1701
		// Don't count post-trashed toward totals
1702
		if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
1703
			$total += $row['num_comments'];
1704
		}
1705
		if ( isset( $approved[ $row['comment_approved'] ] ) ) {
1706
			$stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
1707
		}
1708
	}
1709
1710
	$stats['total_comments'] = $total;
1711
	foreach ( $approved as $key ) {
1712
		if ( empty( $stats[ $key ] ) ) {
1713
			$stats[ $key ] = 0;
1714
		}
1715
	}
1716
1717
	$stats = (object) $stats;
1718
	wp_cache_set( "comments-{$post_id}", $stats, 'counts' );
1719
1720
	return $stats;
1721
}
1722
1723
add_filter( 'wp_count_comments', 'give_remove_payment_notes_in_comment_counts', 10, 2 );
1724
1725
1726
/**
1727
 * Filter where older than one week
1728
 *
1729
 * @access public
1730
 * @since  1.0
1731
 *
1732
 * @param string $where Where clause
1733
 *
1734
 * @return string $where Modified where clause
1735
 */
1736
function give_filter_where_older_than_week( $where = '' ) {
1737
	// Payments older than one week
1738
	$start = date( 'Y-m-d', strtotime( '-7 days' ) );
1739
	$where .= " AND post_date <= '{$start}'";
1740
1741
	return $where;
1742
}
1743
1744
1745
/**
1746
 * Get Price ID
1747
 *
1748
 * @description Retrieves the Price ID given a proper form ID and price (donation) total
1749
 *
1750
 * @param $form_id
1751
 * @param $price
1752
 *
1753
 * @return string $price_id
1754
 */
1755
function give_get_price_id( $form_id, $price ) {
1756
1757 34
	$price_id = 0;
1758
1759 34
	if ( give_has_variable_prices( $form_id ) ) {
1760
1761 34
		$levels = maybe_unserialize( get_post_meta( $form_id, '_give_donation_levels', true ) );
1762
1763 34
		foreach ( $levels as $level ) {
1764
1765 34
			$level_amount = (float) give_sanitize_amount( $level['_give_amount'] );
1766
1767
			//check that this indeed the recurring price
1768 34
			if ( $level_amount == $price ) {
1769
1770 34
				$price_id = $level['_give_id']['level_id'];
1771
1772 34
			}
1773
1774 34
		}
1775
1776 34
	}
1777
1778 34
	return $price_id;
1779
1780
}
1781
1782
/**
1783
 * Retrieves arbitrary fees for the donation (Currently not in use!!)
1784
 * @TODO  - Incorporate a fee-based functionality similar to below
1785
 * @since 1.0
1786
 *
1787
 * @param int $payment_id Payment ID
1788
 * @param string $type Fee type
1789
 *
1790
 * @return mixed array if payment fees found, false otherwise
1791
 */
1792
function give_get_payment_fees( $payment_id = 0, $type = 'all' ) {
1793
	$payment_meta = give_get_payment_meta( $payment_id );
1794
	$fees         = array();
1795
	$payment_fees = isset( $payment_meta['fees'] ) ? $payment_meta['fees'] : false;
1796
	if ( ! empty( $payment_fees ) && is_array( $payment_fees ) ) {
1797
		foreach ( $payment_fees as $fee_id => $fee ) {
1798
			if ( 'all' != $type && ! empty( $fee['type'] ) && $type != $fee['type'] ) {
1799
				unset( $payment_fees[ $fee_id ] );
1800
			} else {
1801
				$fees[] = array(
1802
					'id'     => $fee_id,
1803
					'amount' => $fee['amount'],
1804
					'label'  => $fee['label']
1805
				);
1806
			}
1807
		}
1808
	}
1809
1810
	return apply_filters( 'give_get_payment_fees', $fees, $payment_id );
1811
}