Give_Payments_Query   F
last analyzed

Complexity

Total Complexity 110

Size/Duplication

Total Lines 912
Duplicated Lines 9.65 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
dl 88
loc 912
rs 1.688
c 0
b 0
f 0
wmc 110
lcom 1
cbo 7

24 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 38 1
A __set() 7 7 2
A __unset() 0 3 1
A init() 0 2 1
A set_filters() 0 33 2
A unset_filters() 0 12 1
C get_payments() 25 70 10
B get_payment_by_group() 0 51 8
B date_filter_pre() 0 28 9
A status() 0 8 2
A page() 0 8 2
A per_page() 0 14 3
A month() 0 8 2
A orderby() 0 21 4
B custom_orderby() 0 19 7
A user() 0 25 5
A donor() 0 12 3
D search() 0 112 17
A mode() 0 14 3
A children() 0 6 2
A give_forms() 24 24 3
A gateway_filter() 23 23 3
F get_sql() 9 105 17
A update_meta_cache() 0 8 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Give_Payments_Query often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Give_Payments_Query, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Payments Query
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Stats
7
 * @copyright   Copyright (c) 2016, GiveWP
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
62
	 * the query is run to convert them to the proper syntax.
63
	 *
64
	 * @since  1.0
65
	 * @access public
66
	 *
67
	 * @param  $args array The array of arguments that can be passed in and used for setting up this payment query.
68
	 */
69
	public function __construct( $args = array() ) {
70
		$defaults = array(
71
			'output'          => 'payments',
72
			'post_type'       => array( 'give_payment' ),
73
			'start_date'      => false,
74
			'end_date'        => false,
75
			'number'          => 20,
76
			'page'            => null,
77
			'orderby'         => 'ID',
78
			'order'           => 'DESC',
79
			'user'            => null, // deprecated, use donor
80
			'donor'           => null,
81
			'status'          => give_get_payment_status_keys(),
82
			'meta_key'        => null,
83
			'year'            => null,
84
			'month'           => null,
85
			'day'             => null,
86
			's'               => null,
87
			'search_in_notes' => false,
88
			'children'        => false,
89
			'fields'          => null,
90
			'gateway'         => null,
91
			'give_forms'      => null,
92
			'offset'          => null,
93
94
			// Currently these params only works with get_payment_by_group
95
			'group_by'        => '',
96
			'count'           => false,
97
		);
98
99
		// We do not want WordPress to handle meta cache because WordPress stores in under `post_meta` key and cache object while we want it under `donation_meta`.
100
		// Similar for term cache
101
		$args['update_post_meta_cache'] = false;
102
103
		$this->args = $this->_args = wp_parse_args( $args, $defaults );
104
105
		$this->init();
106
	}
107
108
	/**
109
	 * Set a query variable.
110
	 *
111
	 * @since  1.0
112
	 * @access public
113
	 *
114
	 * @param $query_var
115
	 * @param $value
116
	 */
117 View Code Duplication
	public function __set( $query_var, $value ) {
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...
118
		if ( in_array( $query_var, array( 'meta_query', 'tax_query' ) ) ) {
119
			$this->args[ $query_var ][] = $value;
120
		} else {
121
			$this->args[ $query_var ] = $value;
122
		}
123
	}
124
125
	/**
126
	 * Unset a query variable.
127
	 *
128
	 * @since  1.0
129
	 * @access public
130
	 *
131
	 * @param $query_var
132
	 */
133
	public function __unset( $query_var ) {
134
		unset( $this->args[ $query_var ] );
135
	}
136
137
	/**
138
	 * Modify the query/query arguments before we retrieve payments.
139
	 *
140
	 * @since  1.0
141
	 * @access public
142
	 *
143
	 * @return void
144
	 */
145
	public function init() {
146
	}
147
148
149
	/**
150
	 * Set query filter.
151
	 *
152
	 * @since  1.8.9
153
	 * @access private
154
	 */
155
	private function set_filters() {
156
		// Reset param to apply filters.
157
		// While set filters $args will get override and multiple get_payments call will not work.
158
		$this->args = $this->_args;
159
160
		// Whitelist order.
161
		$this->args['order'] = in_array( strtoupper( $this->args['order'] ), array( 'ASC', 'DESC' ) ) ? $this->args['order'] : 'DESC' ;
162
163
		$this->date_filter_pre();
164
		$this->orderby();
165
		$this->status();
166
		$this->month();
167
		$this->per_page();
168
		$this->page();
169
		$this->user();
170
		$this->donor();
171
		$this->search();
172
		$this->mode();
173
		$this->children();
174
		$this->give_forms();
175
		$this->gateway_filter();
176
177
		add_filter( 'posts_orderby', array( $this, 'custom_orderby' ), 10, 2 );
178
179
		/**
180
		 * Fires after setup filters.
181
		 *
182
		 * @since 1.0
183
		 *
184
		 * @param Give_Payments_Query $this Payments query object.
185
		 */
186
		do_action( 'give_pre_get_payments', $this );
187
	}
188
189
	/**
190
	 * Unset query filter.
191
	 *
192
	 * @since  1.8.9
193
	 * @access private
194
	 */
195
	private function unset_filters() {
196
		remove_filter( 'posts_orderby', array( $this, 'custom_orderby' ) );
197
198
		/**
199
		 * Fires after retrieving payments.
200
		 *
201
		 * @since 1.0
202
		 *
203
		 * @param Give_Payments_Query $this Payments query object.
204
		 */
205
		do_action( 'give_post_get_payments', $this );
206
	}
207
208
209
	/**
210
	 * Retrieve payments.
211
	 *
212
	 * The query can be modified in two ways; either the action before the
213
	 * query is run, or the filter on the arguments (existing mainly for backwards
214
	 * compatibility).
215
	 *
216
	 * @since  1.0
217
	 * @access public
218
	 *
219
	 * @return array
220
	 */
221
	public function get_payments() {
222
		global $post;
223
224
		$results        = array();
225
		$this->payments = array();
226
		$cache_key      = Give_Cache::get_key( 'give_payment_query', $this->args, false );
227
		$this->payments = Give_Cache::get_db_query( $cache_key );
0 ignored issues
show
Documentation Bug introduced by
It seems like \Give_Cache::get_db_query($cache_key) of type * is incompatible with the declared type array of property $payments.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
228
229
		// Return cached result.
230
		if ( ! is_null( $this->payments ) ) {
231
			return $this->payments;
232
		}
233
234
235
		// Modify the query/query arguments before we retrieve payments.
236
		$this->set_filters();
237
238
		/* @var WP_Query $query */
239
		$query = new WP_Query( $this->args );
240
241
		$custom_output = array(
242
			'payments',
243
			'give_payments',
244
		);
245
246
		if ( $query->have_posts() ) {
247
248
			// Update meta cache only if query is not for all donations.
249
			// @see https://github.com/impress-org/give/issues/4104
250
			if (
251
				( isset( $this->args['nopaging'] ) && true !== (bool) $this->args['nopaging'] )
252
				|| ( isset( $this->args['posts_per_page'] ) && 0 < $this->args['posts_per_page'] )
253
			) {
254
				self::update_meta_cache( wp_list_pluck( $query->posts, 'ID' ) );
255
			}
256
257 View Code Duplication
			if ( ! in_array( $this->args['output'], $custom_output ) ) {
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...
258
				$results = $query->posts;
259
260
			} else{
261
				$previous_post = $post;
262
263
				while ( $query->have_posts() ) {
264
					$query->the_post();
265
266
					$payment_id = get_post()->ID;
267
					$payment    = new Give_Payment( $payment_id );
268
269
					$this->payments[] = apply_filters( 'give_payment', $payment, $payment_id, $this );
270
				}
271
272
				wp_reset_postdata();
273
274
				// Prevent nest loop from producing unexpected results.
275
				if ( $previous_post instanceof WP_Post ) {
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
276
					$post = $previous_post;
277
					setup_postdata( $post );
278
				}
279
280
				$results = $this->payments;
281
			}
282
		}
283
284
		Give_Cache::set_db_query( $cache_key, $results );
285
286
		// Remove query filters after we retrieve payments.
287
		$this->unset_filters();
288
289
		return $results;
290
	}
291
292
	/**
293
	 * Get payments by group
294
	 *
295
	 * @since  1.8.17
296
	 * @access public
297
	 *
298
	 * @return array
299
	 */
300
	public function get_payment_by_group() {
301
		global $wpdb;
302
303
		$allowed_groups = array( 'post_status' );
304
		$result         = array();
305
306
307
		if ( in_array( $this->args['group_by'], $allowed_groups ) ) {
308
			// Set only count in result.
309
			if ( $this->args['count'] ) {
310
311
				$this->set_filters();
312
313
				$new_results = $wpdb->get_results( $this->get_sql(), ARRAY_N );
314
315
				$this->unset_filters();
316
317
				foreach ( $new_results as $results ) {
318
					$result[ $results[0] ] = $results[1];
319
				}
320
321
				switch ( $this->args['group_by'] ) {
322
					case 'post_status':
323
324
						/* @var Give_Payment $donation */
325
						foreach ( give_get_payment_status_keys() as $status ) {
326
							if ( ! isset( $result[ $status ] ) ) {
327
								$result[ $status ] = 0;
328
							}
329
						}
330
331
						break;
332
				}
333
			} else {
334
				$donations = $this->get_payments();
335
336
				/* @var $donation Give_Payment */
337
				foreach ( $donations as $donation ) {
338
					$result[ $donation->{$this->args['group_by']} ][] = $donation;
339
				}
340
			}
341
		}
342
343
344
		/**
345
		 * Filter the result
346
		 *
347
		 * @since 1.8.17
348
		 */
349
		return apply_filters( 'give_get_payment_by_group', $result, $this );
350
	}
351
352
	/**
353
	 * If querying a specific date, add the proper filters.
354
	 *
355
	 * @since  1.0
356
	 * @access public
357
	 *
358
	 * @return void
359
	 */
360
	public function date_filter_pre() {
361
		if ( ! ( $this->args['start_date'] || $this->args['end_date'] ) ) {
362
			return;
363
		}
364
365
		$this->setup_dates( $this->args['start_date'], $this->args['end_date'] );
366
367
		$is_start_date = property_exists( __CLASS__, 'start_date' );
368
		$is_end_date   = property_exists( __CLASS__, 'end_date' );
369
370
		if ( $is_start_date || $is_end_date ) {
371
			$date_query = array();
372
373
			if ( $is_start_date && ! is_wp_error( $this->start_date ) ) {
374
				$date_query['after'] = date( 'Y-m-d H:i:s', $this->start_date );
375
			}
376
377
			if ( $is_end_date && ! is_wp_error( $this->end_date ) ) {
378
				$date_query['before'] = date( 'Y-m-d H:i:s', $this->end_date );
379
			}
380
381
			// Include Start Date and End Date while querying.
382
			$date_query['inclusive'] = true;
383
384
			$this->__set( 'date_query', $date_query );
385
386
		}
387
	}
388
389
	/**
390
	 * Post Status
391
	 *
392
	 * @since  1.0
393
	 * @access public
394
	 *
395
	 * @return void
396
	 */
397
	public function status() {
398
		if ( ! isset( $this->args['status'] ) ) {
399
			return;
400
		}
401
402
		$this->__set( 'post_status', $this->args['status'] );
403
		$this->__unset( 'status' );
404
	}
405
406
	/**
407
	 * Current Page
408
	 *
409
	 * @since  1.0
410
	 * @access public
411
	 *
412
	 * @return void
413
	 */
414
	public function page() {
415
		if ( ! isset( $this->args['page'] ) ) {
416
			return;
417
		}
418
419
		$this->__set( 'paged', $this->args['page'] );
420
		$this->__unset( 'page' );
421
	}
422
423
	/**
424
	 * Posts Per Page
425
	 *
426
	 * @since  1.0
427
	 * @access public
428
	 *
429
	 * @return void
430
	 */
431
	public function per_page() {
432
433
		if ( ! isset( $this->args['number'] ) ) {
434
			return;
435
		}
436
437
		if ( $this->args['number'] == - 1 ) {
438
			$this->__set( 'nopaging', true );
439
		} else {
440
			$this->__set( 'posts_per_page', $this->args['number'] );
441
		}
442
443
		$this->__unset( 'number' );
444
	}
445
446
	/**
447
	 * Current Month
448
	 *
449
	 * @since  1.0
450
	 * @access public
451
	 *
452
	 * @return void
453
	 */
454
	public function month() {
455
		if ( ! isset( $this->args['month'] ) ) {
456
			return;
457
		}
458
459
		$this->__set( 'monthnum', $this->args['month'] );
460
		$this->__unset( 'month' );
461
	}
462
463
	/**
464
	 * Order by
465
	 *
466
	 * @since  1.0
467
	 * @access public
468
	 *
469
	 * @return void
470
	 */
471
	public function orderby() {
472
		switch ( $this->args['orderby'] ) {
473
			case 'amount':
474
				$this->__set( 'orderby', 'meta_value_num' );
475
				$this->__set( 'meta_key', '_give_payment_total' );
476
				break;
477
478
			case 'status':
479
				$this->__set( 'orderby', 'post_status' );
480
				break;
481
482
			case 'donation_form':
483
				$this->__set( 'orderby', 'meta_value' );
484
				$this->__set( 'meta_key', '_give_payment_form_title' );
485
				break;
486
487
			default:
488
				$this->__set( 'orderby', $this->args['orderby'] );
489
				break;
490
		}
491
	}
492
493
	/**
494
	 * Custom orderby.
495
	 * Note: currently custom sorting is only used for donation listing page.
496
	 *
497
	 * @since  1.8
498
	 * @access public
499
	 *
500
	 * @param string   $order
501
	 * @param WP_Query $query
502
	 *
503
	 * @return mixed
504
	 */
505
	public function custom_orderby( $order, $query ) {
506
507
		if ( ! empty( $query->query['post_type'] ) ) {
508
			$post_types = is_array( $query->query['post_type'] ) ? $query->query['post_type'] : array( $query->query['post_type'] );
509
510
			if ( ! in_array( 'give_payment', $post_types ) || ! isset( $query->query['orderby'] ) || is_array( $query->query['orderby'] ) ) {
511
				return $order;
512
			}
513
514
			global $wpdb;
515
			switch ( $query->query['orderby'] ) {
516
				case 'post_status':
517
					$order = $wpdb->posts . '.post_status ' . strtoupper( $query->query['order'] );
518
					break;
519
			}
520
		}
521
522
		return $order;
523
	}
524
525
	/**
526
	 * Specific User
527
	 *
528
	 * @since  1.0
529
	 * @access public
530
	 *
531
	 * @return void
532
	 */
533
	public function user() {
534
		if ( is_null( $this->args['user'] ) ) {
535
			return;
536
		}
537
538
539
		$args = array();
540
541
		if ( is_numeric( $this->args['user'] ) ) {
542
			// Backward compatibility: user donor param to get payment attached to donor instead of user
543
			$donor_id = Give()->donors->get_column_by( 'id', is_numeric( $this->args['user'] ) ? 'user_id' : 'email', $this->args['user'] );
544
545
			$args = array(
546
				'key'   => '_give_payment_donor_id',
547
				'value' => absint( $donor_id ),
548
			);
549
		} elseif ( is_email( $this->args['user'] ) ) {
550
			$args = array(
551
				'key'   => '_give_payment_donor_email',
552
				'value' => $this->args['user'],
553
			);
554
		}
555
556
		$this->__set( 'meta_query', $args );
557
	}
558
559
	/**
560
	 * Specific donor id
561
	 *
562
	 * @access  public
563
	 * @since   1.8.9
564
	 * @return  void
565
	 */
566
	public function donor() {
567
		if ( is_null( $this->args['donor'] ) || ! is_numeric( $this->args['donor'] ) ) {
568
			return;
569
		}
570
571
		$donor_meta_type = Give()->donor_meta->meta_type;
572
573
		$this->__set( 'meta_query', array(
574
			'key'   => "_give_payment_{$donor_meta_type}_id",
575
			'value' => (int) $this->args['donor'],
576
		) );
577
	}
578
579
	/**
580
	 * Search
581
	 *
582
	 * @since  1.0
583
	 * @access public
584
	 *
585
	 * @return void
586
	 */
587
	public function search() {
588
589
		if ( ! isset( $this->args['s'] ) ) {
590
			return;
591
		}
592
593
		$search = trim( $this->args['s'] );
594
595
		if ( empty( $search ) ) {
596
			return;
597
		}
598
599
		$is_email = is_email( $search ) || strpos( $search, '@' ) !== false;
600
		$is_user  = strpos( $search, strtolower( 'user:' ) ) !== false;
601
602
		if ( ! empty( $this->args['search_in_notes'] ) ) {
603
604
			$notes = give_get_payment_notes( 0, $search );
605
606
			if ( ! empty( $notes ) ) {
607
608
				$payment_ids = wp_list_pluck( (array) $notes, 'comment_post_ID' );
609
610
				$this->__set( 'post__in', $payment_ids );
611
			}
612
613
			$this->__unset( 's' );
614
615
		} elseif ( $is_email || strlen( $search ) == 32 ) {
616
617
			$key         = $is_email ? '_give_payment_donor_email' : '_give_payment_purchase_key';
618
			$search_meta = array(
619
				'key'     => $key,
620
				'value'   => $search,
621
				'compare' => 'LIKE',
622
			);
623
624
			$this->__set( 'meta_query', $search_meta );
625
			$this->__unset( 's' );
626
627
		} elseif ( $is_user ) {
628
629
			$search_meta = array(
630
				'key'   => '_give_payment_donor_id',
631
				'value' => trim( str_replace( 'user:', '', strtolower( $search ) ) ),
632
			);
633
634
			$this->__set( 'meta_query', $search_meta );
635
636
			$this->__unset( 's' );
637
638
		} elseif ( is_numeric( $search ) ) {
639
640
			$post = get_post( $search );
641
642
			if ( is_object( $post ) && $post->post_type == 'give_payment' ) {
643
644
				$arr   = array();
645
				$arr[] = $search;
646
				$this->__set( 'post__in', $arr );
647
				$this->__unset( 's' );
648
			}
649
		} elseif ( '#' == substr( $search, 0, 1 ) ) {
650
651
			$search = str_replace( '#:', '', $search );
652
			$search = str_replace( '#', '', $search );
653
			$this->__set( 'give_forms', $search );
654
			$this->__unset( 's' );
655
656
		} else if ( ! empty( $search ) ) {
657
			$search_parts = preg_split( '/\s+/', $search );
658
659
			if ( is_array( $search_parts ) && 2 === count( $search_parts ) ) {
660
				$search_meta = array(
661
					'relation' => 'AND',
662
					array(
663
						'key'     => '_give_donor_billing_first_name',
664
						'value'   => $search_parts[0],
665
						'compare' => '=',
666
					),
667
					array(
668
						'key'     => '_give_donor_billing_last_name',
669
						'value'   => $search_parts[1],
670
						'compare' => '=',
671
					),
672
				);
673
			} else {
674
				$search_meta = array(
675
					'relation' => 'OR',
676
					array(
677
						'key'     => '_give_donor_billing_first_name',
678
						'value'   => $search,
679
						'compare' => 'LIKE',
680
					),
681
					array(
682
						'key'     => '_give_donor_billing_last_name',
683
						'value'   => $search,
684
						'compare' => 'LIKE',
685
					),
686
				);
687
			}
688
689
			$this->__set( 'meta_query', $search_meta );
690
691
			$this->__unset( 's' );
692
693
		} else {
694
			$this->__set( 's', $search );
695
696
		}
697
698
	}
699
700
	/**
701
	 * Payment Mode
702
	 *
703
	 * @since  1.0
704
	 * @access public
705
	 *
706
	 * @return void
707
	 */
708
	public function mode() {
709
		if ( empty( $this->args['mode'] ) || $this->args['mode'] == 'all' ) {
710
			$this->__unset( 'mode' );
711
712
			return;
713
		}
714
715
		$this->__set(
716
			'meta_query', array(
717
				'key'   => '_give_payment_mode',
718
				'value' => $this->args['mode'],
719
			)
720
		);
721
	}
722
723
	/**
724
	 * Children
725
	 *
726
	 * @since  1.0
727
	 * @access public
728
	 *
729
	 * @return void
730
	 */
731
	public function children() {
732
		if ( empty( $this->args['children'] ) ) {
733
			$this->__set( 'post_parent', 0 );
734
		}
735
		$this->__unset( 'children' );
736
	}
737
738
	/**
739
	 * Specific Give Form
740
	 *
741
	 * @since  1.0
742
	 * @access public
743
	 *
744
	 * @return void
745
	 */
746 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...
747
748
		if ( empty( $this->args['give_forms'] ) ) {
749
			return;
750
		}
751
752
		$compare = '=';
753
754
		if ( is_array( $this->args['give_forms'] ) ) {
755
			$compare = 'IN';
756
		}
757
758
		$this->__set(
759
			'meta_query',
760
			array(
761
				'key'     => '_give_payment_form_id',
762
				'value'   => $this->args['give_forms'],
763
				'compare' => $compare,
764
			)
765
		);
766
767
		$this->__unset( 'give_forms' );
768
769
	}
770
771
	/**
772
	 * Specific Gateway
773
	 *
774
	 * @since  1.8.17
775
	 * @access public
776
	 *
777
	 * @return void
778
	 */
779 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...
780
781
		if ( empty( $this->args['gateway'] ) ) {
782
			return;
783
		}
784
785
		$compare = '=';
786
787
		if ( is_array( $this->args['gateway'] ) ) {
788
			$compare = 'IN';
789
		}
790
791
		$this->__set(
792
			'meta_query', array(
793
				'key'     => '_give_payment_gateway',
794
				'value'   => $this->args['gateway'],
795
				'compare' => $compare,
796
			)
797
		);
798
799
		$this->__unset( 'gateway' );
800
801
	}
802
803
804
	/**
805
	 * Get sql query
806
	 *
807
	 * Note: Internal purpose only. We are developing on this fn.
808
	 *
809
	 * @since  1.8.18
810
	 * @access public
811
	 * @global $wpdb
812
	 *
813
	 * @return string
814
	 */
815
	private function get_sql() {
816
		global $wpdb;
817
818
		$allowed_keys = array(
819
			'post_name',
820
			'post_author',
821
			'post_date',
822
			'post_title',
823
			'post_status',
824
			'post_modified',
825
			'post_parent',
826
			'post_type',
827
			'menu_order',
828
			'comment_count',
829
		);
830
831
		$this->args['orderby'] = 'post_parent__in';
832
833
		// Whitelist orderby.
834
		if( ! in_array( $this->args['orderby'], $allowed_keys ) ) {
835
			$this->args['orderby'] = 'ID';
836
		}
837
838
		$where = "WHERE {$wpdb->posts}.post_type = 'give_payment'";
839
		$where .= " AND {$wpdb->posts}.post_status IN ('" . implode( "','", $this->args['post_status'] ) . "')";
840
841
		if ( is_numeric( $this->args['post_parent'] ) ) {
842
			$where .= " AND {$wpdb->posts}.post_parent={$this->args['post_parent']}";
843
		}
844
845
		// Set orderby.
846
		$orderby  = "ORDER BY {$wpdb->posts}.{$this->args['orderby']}";
847
		$group_by = '';
848
849
		// Set group by.
850 View Code Duplication
		if ( ! empty( $this->args['group_by'] ) ) {
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...
851
			$group_by = "GROUP BY {$wpdb->posts}.{$this->args['group_by']}";
852
		}
853
854
		// Set offset.
855
		if (
856
			empty( $this->args['nopaging'] ) &&
857
			empty( $this->args['offset'] ) &&
858
			( ! empty( $this->args['page'] ) && 0 < $this->args['page'] )
859
		) {
860
			$this->args['offset'] = $this->args['posts_per_page'] * ( $this->args['page'] - 1 );
861
		}
862
863
		// Set fields.
864
		$fields = "{$wpdb->posts}.*";
865
		if ( ! empty( $this->args['fields'] ) && 'all' !== $this->args['fields'] ) {
866
			if ( is_string( $this->args['fields'] ) ) {
867
				$fields = "{$wpdb->posts}.{$this->args['fields']}";
868 View Code Duplication
			} elseif ( is_array( $this->args['fields'] ) ) {
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...
869
				$fields = "{$wpdb->posts}." . implode( " , {$wpdb->posts}.", $this->args['fields'] );
870
			}
871
		}
872
873
		// Set count.
874
		if ( ! empty( $this->args['count'] ) ) {
875
			$fields = "COUNT({$wpdb->posts}.ID)";
876
877 View Code Duplication
			if ( ! empty( $this->args['group_by'] ) ) {
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...
878
				$fields = "{$wpdb->posts}.{$this->args['group_by']}, {$fields}";
879
			}
880
		}
881
882
		// Date query.
883
		if ( ! empty( $this->args['date_query'] ) ) {
884
			$date_query_obj = new WP_Date_Query( $this->args['date_query'] );
885
			$where          .= str_replace(
886
				array(
887
					"\n",
888
					'(   (',
889
					'))',
890
				),
891
				array(
892
					'',
893
					'( (',
894
					') )',
895
				),
896
				$date_query_obj->get_sql()
897
			);
898
		}
899
900
		// Meta query.
901
		if ( ! empty( $this->args['meta_query'] ) ) {
902
			$meta_query_obj = new WP_Meta_Query( $this->args['meta_query'] );
903
			$where          = implode( ' ', $meta_query_obj->get_sql( 'post', $wpdb->posts, 'ID' ) ) . " {$where}";
904
			$where          = Give()->payment_meta->__rename_meta_table_name( $where, 'posts_where' );
905
		}
906
907
		// Set sql query.
908
		$sql = $wpdb->prepare(
909
			"SELECT {$fields} FROM {$wpdb->posts} LIMIT %d,%d;",
910
			absint( $this->args['offset'] ),
911
			( empty( $this->args['nopaging'] ) ? absint( $this->args['posts_per_page'] ) : 99999999999 )
912
		);
913
914
		// $where, $orderby and order already prepared query they can generate notice if you re prepare them in above.
915
		// WordPress consider LIKE condition as placeholder if start with s,f, or d.
916
		$sql = str_replace( 'LIMIT', "{$where} {$group_by} {$orderby} {$this->args['order']} LIMIT", $sql );
917
918
		return $sql;
919
	}
920
921
	/**
922
	 * Update donations meta cache
923
	 *
924
	 * @since  2.5.0
925
	 * @access private
926
	 *
927
	 * @param $donation_ids
928
	 */
929
	public static function update_meta_cache( $donation_ids ) {
930
		// Exit.
931
		if ( empty( $donation_ids ) ) {
932
			return;
933
		}
934
935
		update_meta_cache( Give()->payment_meta->get_meta_type(), $donation_ids );
936
	}
937
}
938