Test Failed
Push — release/1.8.17 ( baf467...e6f68c )
by Ravinder
05:06
created

Give_Payments_Query::custom_orderby()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 6
nop 2
dl 0
loc 16
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * Payments Query
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Stats
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
 * Give_Payments_Query Class
19
 *
20
 * This class is for retrieving payments data.
21
 *
22
 * Payments can be retrieved for date ranges and pre-defined periods.
23
 *
24
 * @since 1.0
25
 */
26
class Give_Payments_Query extends Give_Stats {
27
28
	/**
29
	 * Preserve args
30
	 *
31
	 * @since  1.8.17
32
	 * @access public
33
	 *
34
	 * @var    array
35
	 */
36
	public $_args = array();
37
38
	/**
39
	 * The args to pass to the give_get_payments() query
40
	 *
41
	 * @since  1.0
42
	 * @access public
43
	 *
44
	 * @var    array
45
	 */
46
	public $args = array();
47
48
	/**
49
	 * The payments found based on the criteria set
50
	 *
51
	 * @since  1.0
52
	 * @access public
53
	 *
54
	 * @var    array
55
	 */
56
	public $payments = array();
57
58
	/**
59
	 * Default query arguments.
60
	 *
61
	 * Not all of these are valid arguments that can be passed to WP_Query. The ones that are not, are modified before the query is run to convert them to the proper syntax.
62
	 *
63
	 * @since  1.0
64
	 * @access public
65
	 *
66
	 * @param  $args array The array of arguments that can be passed in and used for setting up this payment query.
67
	 */
68
	public function __construct( $args = array() ) {
69
		$defaults = array(
70
			'output'          => 'payments',
71
			'post_type'       => array( 'give_payment' ),
72
			'start_date'      => false,
73
			'end_date'        => false,
74
			'number'          => 20,
75
			'page'            => null,
76
			'orderby'         => 'ID',
77
			'order'           => 'DESC',
78
			'user'            => null,
79
			'donor'           => null,
80
			'status'          => give_get_payment_status_keys(),
81
			'meta_key'        => null,
0 ignored issues
show
introduced by
Detected usage of meta_key, possible slow query.
Loading history...
82
			'year'            => null,
83
			'month'           => null,
84
			'day'             => null,
85
			's'               => null,
86
			'search_in_notes' => false,
87
			'children'        => false,
88
			'fields'          => null,
89
			'gateway'         => null,
90
			'give_forms'      => null,
91
92
			// Currently these params only works with get_payment_by_group
93
			'group_by'        => '',
94
			'count'           => false,
95
		);
96
97
		$this->args = $this->_args = wp_parse_args( $args, $defaults );
98
99
		$this->init();
100
	}
101
102
	/**
103
	 * Set a query variable.
104
	 *
105
	 * @since  1.0
106
	 * @access public
107
	 *
108
	 * @param $query_var
109
	 * @param $value
110
	 */
111
	public function __set( $query_var, $value ) {
112
		if ( in_array( $query_var, array( 'meta_query', 'tax_query' ) ) ) {
113
			$this->args[ $query_var ][] = $value;
114
		} else {
115
			$this->args[ $query_var ] = $value;
116
		}
117
	}
118
119
	/**
120
	 * Unset a query variable.
121
	 *
122
	 * @since  1.0
123
	 * @access public
124
	 *
125
	 * @param $query_var
126
	 */
127
	public function __unset( $query_var ) {
128
		unset( $this->args[ $query_var ] );
129
	}
130
131
	/**
132
	 * Modify the query/query arguments before we retrieve payments.
133
	 *
134
	 * @since  1.0
135
	 * @access public
136
	 *
137
	 * @return void
138
	 */
139
	public function init() {
140
	}
141
142
143
	/**
144
	 * Set query filter.
145
	 *
146
	 * @since  1.8.9
147
	 * @access private
148
	 */
149
	private function set_filters() {
150
		// Reset param to apply filters.
151
		// While set filters $args will get override and multiple get_payments call will not work.
152
		$this->args = $this->_args;
153
154
		$this->date_filter_pre();
155
		$this->orderby();
156
		$this->status();
157
		$this->month();
158
		$this->per_page();
159
		$this->page();
160
		$this->user();
161
		$this->donor();
162
		$this->search();
163
		$this->mode();
164
		$this->children();
165
		$this->give_forms();
166
		$this->gateway_filter();
167
168
		add_filter( 'posts_orderby', array( $this, 'custom_orderby' ), 10, 2 );
169
	}
170
171
	/**
172
	 * Unset query filter.
173
	 *
174
	 * @since  1.8.9
175
	 * @access private
176
	 */
177
	private function unset_filters() {
178
		$this->date_filter_post();
179
		remove_filter( 'posts_orderby', array( $this, 'custom_orderby' ) );
180
	}
181
182
183
	/**
184
	 * Retrieve payments.
185
	 *
186
	 * The query can be modified in two ways; either the action before the
187
	 * query is run, or the filter on the arguments (existing mainly for backwards
188
	 * compatibility).
189
	 *
190
	 * @since  1.0
191
	 * @access public
192
	 *
193
	 * @return array
194
	 */
195
	public function get_payments() {
196
		// Modify the query/query arguments before we retrieve payments.
197
		$this->set_filters();
198
199
		/**
200
		 * Fires before retrieving payments.
201
		 *
202
		 * @since 1.0
203
		 *
204
		 * @param Give_Payments_Query $this Payments query object.
205
		 */
206
		do_action( 'give_pre_get_payments', $this );
207
208
		$query          = new WP_Query( $this->args );
209
		$this->payments = array();
210
211
		$custom_output = array(
212
			'payments',
213
			'give_payments',
214
		);
215
216
		if ( ! in_array( $this->args['output'], $custom_output ) ) {
217
			return $query->posts;
218
		}
219
220
		if ( $query->have_posts() ) {
221
			while ( $query->have_posts() ) {
222
				$query->the_post();
223
224
				$payment_id = get_post()->ID;
225
				$payment    = new Give_Payment( $payment_id );
226
227
				$this->payments[] = apply_filters( 'give_payment', $payment, $payment_id, $this );
228
			}
229
230
			wp_reset_postdata();
231
		}
232
233
		// Remove query filters after we retrieve payments.
234
		$this->unset_filters();
235
236
		/**
237
		 * Fires after retrieving payments.
238
		 *
239
		 * @since 1.0
240
		 *
241
		 * @param Give_Payments_Query $this Payments query object.
242
		 */
243
		do_action( 'give_post_get_payments', $this );
244
245
		return $this->payments;
246
	}
247
248
249
	/**
250
	 * Get payments by group
251
	 *
252
	 * @since  1.8.17
253
	 * @access public
254
	 *
255
	 * @return array
256
	 */
257
	public function get_payment_by_group() {
258
		global $wpdb;
259
260
		$allowed_groups = array( 'post_status' );
261
		$result         = array();
262
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
263
264
		if ( in_array( $this->args['group_by'], $allowed_groups ) ) {
265
			// Set only count in result.
266
			if ( $this->args['count'] ) {
267
				$statuses     = get_post_stati();
268
				$status_query = '';
269
270
				$counter = 0;
271
				foreach ( $statuses as $status ) {
272
					$prefix       = $counter ? " OR " : '';
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal OR does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
273
					$status_query .= "{$prefix}{$wpdb->posts}.post_status=\"{$status}\"";
274
					$counter ++;
275
				}
276
277
				$new_results = $wpdb->get_results(
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...
278
					"
279
					SELECT {$wpdb->posts}.post_status, COUNT({$wpdb->posts}.ID)
280
					FROM {$wpdb->posts}
281
					WHERE 1=1 
282
					AND {$wpdb->posts}.post_parent = 0 
283
					AND {$wpdb->posts}.post_type = 'give_payment'
284
					AND (($status_query))
285
					GROUP BY {$wpdb->posts}.{$this->args['group_by']}
286
					ORDER BY {$wpdb->posts}.ID
287
					DESC
288
					"
289
					, ARRAY_N );
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 16 spaces, but found 20.
Loading history...
290
291
				foreach ( $new_results as $results ) {
292
					$result[ $results[0] ] = $results[1];
293
				}
294
295
				switch ( $this->args['group_by'] ) {
296
					case 'post_status':
297
298
						if ( isset( $statuses['private'] ) && empty( $args['s'] ) ) {
299
							unset( $statuses['private'] );
300
						}
301
302
						/* @var Give_Payment $donation */
303
						foreach ( $statuses as $status => $status_label ) {
304
							if ( ! isset( $result[ $status ] ) ) {
305
								$result[ $status ] = 0;
306
							}
307
						}
308
309
						break;
310
				}
311
			} else {
312
				$donations = $this->get_payments();
313
314
				/* @var $donation Give_Payment */
315
				foreach ( $donations as $donation ) {
316
					$result[ $donation->{$this->args['group_by']} ][] = $donation;
317
				}
318
			}
319
		}
320
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
321
322
		/**
323
		 * Filter the result
324
		 *
325
		 * @since 1.8.17
326
		 */
327
		return apply_filters( 'give_get_payment_by_group', $result, $this );
328
	}
329
330
	/**
331
	 * If querying a specific date, add the proper filters.
332
	 *
333
	 * @since  1.0
334
	 * @access public
335
	 *
336
	 * @return void
337
	 */
338
	public function date_filter_pre() {
339
		if ( ! ( $this->args['start_date'] || $this->args['end_date'] ) ) {
340
			return;
341
		}
342
343
		$this->setup_dates( $this->args['start_date'], $this->args['end_date'] );
344
345
		add_filter( 'posts_where', array( $this, 'payments_where' ) );
346
	}
347
348
	/**
349
	 * If querying a specific date, remove filters after the query has been run
350
	 * to avoid affecting future queries.
351
	 *
352
	 * @since  1.0
353
	 * @access public
354
	 *
355
	 * @return void
356
	 */
357
	public function date_filter_post() {
358
		if ( ! ( $this->args['start_date'] || $this->args['end_date'] ) ) {
359
			return;
360
		}
361
362
		remove_filter( 'posts_where', array( $this, 'payments_where' ) );
363
	}
364
365
	/**
366
	 * Post Status
367
	 *
368
	 * @since  1.0
369
	 * @access public
370
	 *
371
	 * @return void
372
	 */
373
	public function status() {
374
		if ( ! isset( $this->args['status'] ) ) {
375
			return;
376
		}
377
378
		$this->__set( 'post_status', $this->args['status'] );
379
		$this->__unset( 'status' );
380
	}
381
382
	/**
383
	 * Current Page
384
	 *
385
	 * @since  1.0
386
	 * @access public
387
	 *
388
	 * @return void
389
	 */
390
	public function page() {
391
		if ( ! isset( $this->args['page'] ) ) {
392
			return;
393
		}
394
395
		$this->__set( 'paged', $this->args['page'] );
396
		$this->__unset( 'page' );
397
	}
398
399
	/**
400
	 * Posts Per Page
401
	 *
402
	 * @since  1.0
403
	 * @access public
404
	 *
405
	 * @return void
406
	 */
407
	public function per_page() {
408
409
		if ( ! isset( $this->args['number'] ) ) {
410
			return;
411
		}
412
413
		if ( $this->args['number'] == - 1 ) {
414
			$this->__set( 'nopaging', true );
415
		} else {
416
			$this->__set( 'posts_per_page', $this->args['number'] );
417
		}
418
419
		$this->__unset( 'number' );
420
	}
421
422
	/**
423
	 * Current Month
424
	 *
425
	 * @since  1.0
426
	 * @access public
427
	 *
428
	 * @return void
429
	 */
430
	public function month() {
431
		if ( ! isset( $this->args['month'] ) ) {
432
			return;
433
		}
434
435
		$this->__set( 'monthnum', $this->args['month'] );
436
		$this->__unset( 'month' );
437
	}
438
439
	/**
440
	 * Order by
441
	 *
442
	 * @since  1.0
443
	 * @access public
444
	 *
445
	 * @return void
446
	 */
447
	public function orderby() {
448
		switch ( $this->args['orderby'] ) {
449
			case 'amount':
450
				$this->__set( 'orderby', 'meta_value_num' );
451
				$this->__set( 'meta_key', '_give_payment_total' );
452
				break;
453
454
			case 'status':
455
				$this->__set( 'orderby', 'post_status' );
456
				break;
457
458
			case 'donation_form':
459
				$this->__set( 'orderby', 'meta_value' );
460
				$this->__set( 'meta_key', '_give_payment_form_title' );
461
				break;
462
463
			default:
464
				$this->__set( 'orderby', $this->args['orderby'] );
465
				break;
466
		}
467
	}
468
469
	/**
470
	 * Custom orderby.
471
	 * Note: currently custom sorting is only used for donation listing page.
472
	 *
473
	 * @since  1.8
474
	 * @access public
475
	 *
476
	 * @param string   $order
477
	 * @param WP_Query $query
478
	 *
479
	 * @return mixed
480
	 */
481
	public function custom_orderby( $order, $query ) {
482
		global $wpdb;
483
484
		$post_types = is_array( $query->query['post_type'] ) ? $query->query['post_type'] : array( $query->query['post_type'] );
485
		if ( ! in_array( 'give_payment', $post_types ) || is_array( $query->query['orderby'] ) ) {
486
			return $order;
487
		}
488
489
		switch ( $query->query['orderby'] ) {
490
			case 'post_status':
491
				$order = $wpdb->posts . '.post_status ' . strtoupper( $query->query['order'] );
492
				break;
493
		}
494
495
		return $order;
496
	}
497
498
	/**
499
	 * Specific User
500
	 *
501
	 * @since  1.0
502
	 * @access public
503
	 *
504
	 * @return void
505
	 */
506
	public function user() {
507
		if ( is_null( $this->args['user'] ) ) {
508
			return;
509
		}
510
511
		if ( is_numeric( $this->args['user'] ) ) {
512
			$user_key = '_give_payment_user_id';
513
		} else {
514
			$user_key = '_give_payment_user_email';
515
		}
516
517
		$this->__set(
518
			'meta_query', array(
519
				'key'   => $user_key,
520
				'value' => $this->args['user'],
521
			)
522
		);
523
	}
524
525
	/**
526
	 * Specific donor id
527
	 *
528
	 * @access  public
529
	 * @since   1.8.9
530
	 * @return  void
531
	 */
532
	public function donor() {
533
		if ( is_null( $this->args['donor'] ) || ! is_numeric( $this->args['donor'] ) ) {
534
			return;
535
		}
536
537
		$this->__set(
538
			'meta_query', array(
539
				'key'   => '_give_payment_customer_id',
540
				'value' => (int) $this->args['donor'],
541
			)
542
		);
543
	}
544
545
	/**
546
	 * Search
547
	 *
548
	 * @since  1.0
549
	 * @access public
550
	 *
551
	 * @return void
552
	 */
553
	public function search() {
554
555
		if ( ! isset( $this->args['s'] ) ) {
556
			return;
557
		}
558
559
		$search = trim( $this->args['s'] );
560
561
		if ( empty( $search ) ) {
562
			return;
563
		}
564
565
		$is_email = is_email( $search ) || strpos( $search, '@' ) !== false;
566
		$is_user  = strpos( $search, strtolower( 'user:' ) ) !== false;
567
568
		if ( ! empty( $this->args['search_in_notes'] ) ) {
569
570
			$notes = give_get_payment_notes( 0, $search );
571
572
			if ( ! empty( $notes ) ) {
573
574
				$payment_ids = wp_list_pluck( (array) $notes, 'comment_post_ID' );
575
576
				$this->__set( 'post__in', $payment_ids );
577
			}
578
579
			$this->__unset( 's' );
580
581
		} elseif ( $is_email || strlen( $search ) == 32 ) {
582
583
			$key         = $is_email ? '_give_payment_user_email' : '_give_payment_purchase_key';
584
			$search_meta = array(
585
				'key'     => $key,
586
				'value'   => $search,
587
				'compare' => 'LIKE',
588
			);
589
590
			$this->__set( 'meta_query', $search_meta );
591
			$this->__unset( 's' );
592
593
		} elseif ( $is_user ) {
594
595
			$search_meta = array(
596
				'key'   => '_give_payment_user_id',
597
				'value' => trim( str_replace( 'user:', '', strtolower( $search ) ) ),
598
			);
599
600
			$this->__set( 'meta_query', $search_meta );
601
602
			if ( give_get_option( 'enable_sequential' ) ) {
603
604
				$search_meta = array(
605
					'key'     => '_give_payment_number',
606
					'value'   => $search,
607
					'compare' => 'LIKE',
608
				);
609
610
				$this->__set( 'meta_query', $search_meta );
611
612
				$this->args['meta_query']['relation'] = 'OR';
613
614
			}
615
616
			$this->__unset( 's' );
617
618
		} elseif (
619
			give_get_option( 'enable_sequential' ) &&
620
			(
621
				false !== strpos( $search, give_get_option( 'sequential_prefix' ) ) ||
622
				false !== strpos( $search, give_get_option( 'sequential_postfix' ) )
623
			)
624
		) {
625
626
			$search_meta = array(
627
				'key'     => '_give_payment_number',
628
				'value'   => $search,
629
				'compare' => 'LIKE',
630
			);
631
632
			$this->__set( 'meta_query', $search_meta );
633
			$this->__unset( 's' );
634
635
		} elseif ( is_numeric( $search ) ) {
636
637
			$post = get_post( $search );
638
639
			if ( is_object( $post ) && $post->post_type == 'give_payment' ) {
0 ignored issues
show
introduced by
Found "== '". Use Yoda Condition checks, you must
Loading history...
640
641
				$arr   = array();
642
				$arr[] = $search;
643
				$this->__set( 'post__in', $arr );
644
				$this->__unset( 's' );
645
			}
646
		} elseif ( '#' == substr( $search, 0, 1 ) ) {
647
648
			$search = str_replace( '#:', '', $search );
649
			$search = str_replace( '#', '', $search );
650
			$this->__set( 'give_forms', $search );
651
			$this->__unset( 's' );
652
653
		} else {
654
			$this->__set( 's', $search );
655
656
		}
657
658
	}
659
660
	/**
661
	 * Payment Mode
662
	 *
663
	 * @since  1.0
664
	 * @access public
665
	 *
666
	 * @return void
667
	 */
668
	public function mode() {
669
		if ( empty( $this->args['mode'] ) || $this->args['mode'] == 'all' ) {
0 ignored issues
show
introduced by
Found "== '". Use Yoda Condition checks, you must
Loading history...
670
			$this->__unset( 'mode' );
671
672
			return;
673
		}
674
675
		$this->__set(
676
			'meta_query', array(
677
				'key'   => '_give_payment_mode',
678
				'value' => $this->args['mode'],
679
			)
680
		);
681
	}
682
683
	/**
684
	 * Children
685
	 *
686
	 * @since  1.0
687
	 * @access public
688
	 *
689
	 * @return void
690
	 */
691
	public function children() {
692
		if ( empty( $this->args['children'] ) ) {
693
			$this->__set( 'post_parent', 0 );
694
		}
695
		$this->__unset( 'children' );
696
	}
697
698
	/**
699
	 * Specific Give Form
700
	 *
701
	 * @since  1.0
702
	 * @access public
703
	 *
704
	 * @return void
705
	 */
706 View Code Duplication
	public function give_forms() {
0 ignored issues
show
Duplication introduced by
This method 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...
707
708
		if ( empty( $this->args['give_forms'] ) ) {
709
			return;
710
		}
711
712
		$compare = '=';
713
714
		if ( is_array( $this->args['give_forms'] ) ) {
715
			$compare = 'IN';
716
		}
717
718
		$this->__set(
719
			'meta_query', array(
720
				array(
721
					'key'     => '_give_payment_form_id',
722
					'value'   => $this->args['give_forms'],
723
					'compare' => $compare,
724
				),
725
			)
726
		);
727
728
		$this->__unset( 'give_forms' );
729
730
	}
731
732
	/**
733
	 * Specific Gateway
734
	 *
735
	 * @since  1.8.17
736
	 * @access public
737
	 *
738
	 * @return void
739
	 */
740 View Code Duplication
	public function gateway_filter() {
0 ignored issues
show
Duplication introduced by
This method 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...
741
742
		if ( empty( $this->args['gateway'] ) ) {
743
			return;
744
		}
745
746
		$compare = '=';
747
748
		if ( is_array( $this->args['gateway'] ) ) {
749
			$compare = 'IN';
750
		}
751
752
		$this->__set(
753
			'meta_query', array(
754
				array(
755
					'key'     => '_give_payment_gateway',
756
					'value'   => $this->args['gateway'],
757
					'compare' => $compare,
758
				),
759
			)
760
		);
761
762
		$this->__unset( 'gateway' );
763
764
	}
765
766
}
767