Issues (4296)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/class-give-donate-form.php (40 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Donate Form
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Give_Donate_Form
7
 * @copyright   Copyright (c) 2015, 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_Donate_Form Class.
19
 *
20
 * This class handles donation forms.
21
 *
22
 * @since 1.0
23
 *
24
 * @property $price
25
 * @property $minimum_price
26
 * @property $maximum_price
27
 * @property $prices
28
 * @property $goal
29
 * @property $sales
30
 * @property $earnings
31
 * @property $post_type
32
 */
33
class Give_Donate_Form {
34
35
	/**
36
	 * The donation ID.
37
	 *
38
	 * @since  1.0
39
	 * @access public
40
	 *
41
	 * @var    int
42
	 */
43
	public $ID = 0;
44
45
	/**
46
	 * The donation price.
47
	 *
48
	 * @since  1.0
49
	 * @access private
50
	 *
51
	 * @var    float
52
	 */
53
	private $price;
54
55
	/**
56
	 * The minimum donation price.
57
	 *
58
	 * @since  1.3.6
59
	 * @access private
60
	 *
61
	 * @var    float
62
	 */
63
	private $minimum_price;
64
65
	/**
66
	 * The maximum donation price.
67
	 *
68
	 * @since  2.0
69
	 * @access private
70
	 *
71
	 * @var    float
72
	 */
73
	private $maximum_price;
74
75
	/**
76
	 * The donation prices, if Price Levels are enabled.
77
	 *
78
	 * @since  1.0
79
	 * @access private
80
	 *
81
	 * @var    array
82
	 */
83
	private $prices;
84
85
	/**
86
	 * The donation goal.
87
	 *
88
	 * @since  1.0
89
	 * @access private
90
	 *
91
	 * @var    float
92
	 */
93
	private $goal;
94
95
	/**
96
	 * The form's sale count.
97
	 *
98
	 * @since  1.0
99
	 * @access private
100
	 *
101
	 * @var    int
102
	 */
103 57
	private $sales;
104
105
	/**
106 57
	 * The form's total earnings
107
	 *
108 57
	 * @since  1.0
109
	 * @access private
110
	 *
111
	 * @var    float
112
	 */
113
	private $earnings;
114
115
	/**
116
	 * Declare the default properties in WP_Post as we can't extend it
117
	 * Anything we've declared above has been removed.
118
	 */
119
120 57
	/**
121
	 * The post author
122 57
	 *
123 2
	 * @since  1.0
124
	 * @access public
125
	 *
126 57
	 * @var    int
127
	 */
128
	public $post_author = 0;
129
130 57
	/**
131
	 * The post date
132
	 *
133
	 * @since  1.0
134 57
	 * @access public
135
	 *
136
	 * @var    string
137
	 */
138 57
	public $post_date = '0000-00-00 00:00:00';
139 57
140 57
	/**
141
	 * The post GTM date
142 57
	 *
143
	 * @since  1.0
144 57
	 * @access public
145
	 *
146 57
	 * @var    string
147
	 */
148
	public $post_date_gmt = '0000-00-00 00:00:00';
149
150
	/**
151
	 * The post content
152
	 *
153
	 * @since  1.0
154
	 * @access public
155
	 *
156
	 * @var    string
157
	 */
158
	public $post_content = '';
159
160 44
	/**
161
	 * The post title
162 44
	 *
163
	 * @since  1.0
164 44
	 * @access public
165
	 *
166
	 * @var    string
167
	 */
168
	public $post_title = '';
169
170
	/**
171
	 * The post excerpt
172
	 *
173
	 * @since  1.0
174
	 * @access public
175
	 *
176
	 * @var    string
177
	 */
178
	public $post_excerpt = '';
179
180
	/**
181
	 * The post status
182
	 *
183
	 * @since  1.0
184
	 * @access public
185
	 *
186
	 * @var    string
187
	 */
188
	public $post_status = 'publish';
189
190
	/**
191
	 * The comment status
192
	 *
193
	 * @since  1.0
194
	 * @access public
195
	 *
196
	 * @var    string
197
	 */
198
	public $comment_status = 'open';
199
200
	/**
201
	 * The ping status
202
	 *
203
	 * @since  1.0
204
	 * @access public
205
	 *
206
	 * @var    string
207
	 */
208
	public $ping_status = 'open';
209
210
	/**
211
	 * The post password
212
	 *
213
	 * @since  1.0
214
	 * @access public
215
	 *
216
	 * @var    string
217
	 */
218
	public $post_password = '';
219
220
	/**
221
	 * The post name
222
	 *
223
	 * @since  1.0
224
	 * @access public
225
	 *
226
	 * @var    string
227
	 */
228 1
	public $post_name = '';
229
230 1
	/**
231
	 * Ping
232
	 *
233
	 * @since  1.0
234
	 * @access public
235
	 *
236
	 * @var    string
237
	 */
238
	public $to_ping = '';
239
240
	/**
241
	 * Pinged
242
	 *
243
	 * @since  1.0
244
	 * @access public
245
	 *
246
	 * @var    string
247
	 */
248
	public $pinged = '';
249
250 15
	/**
251
	 * The post modified date
252 15
	 *
253
	 * @since  1.0
254 15
	 * @access public
255
	 *
256 15
	 * @var    string
257
	 */
258 4
	public $post_modified = '0000-00-00 00:00:00';
259
260 4
	/**
261
	 * The post modified GTM date
262 11
	 *
263
	 * @since  1.0
264
	 * @access public
265
	 *
266 15
	 * @var    string
267
	 */
268
	public $post_modified_gmt = '0000-00-00 00:00:00';
269
270
	/**
271
	 * The post filtered content
272
	 *
273
	 * @since  1.0
274
	 * @access public
275
	 *
276 15
	 * @var    string
277
	 */
278
	public $post_content_filtered = '';
279
280
	/**
281
	 * The post parent
282
	 *
283
	 * @since  1.0
284
	 * @access public
285 2
	 *
286
	 * @var    int
287 2
	 */
288
	public $post_parent = 0;
289 2
290 2
	/**
291
	 * The post GUID
292 2
	 *
293
	 * @since  1.0
294 1
	 * @access public
295
	 *
296 1
	 * @var    string
297
	 */
298 1
	public $guid = '';
299
300
	/**
301
	 * The menu order
302 2
	 *
303
	 * @since  1.0
304 2
	 * @access public
305
	 *
306
	 * @var    int
307
	 */
308
	public $menu_order = 0;
309
310
	/**
311
	 * The mime type0
312
	 *
313 36
	 * @since  1.0
314
	 * @access public
315 36
	 *
316
	 * @var    string
317 36
	 */
318
	public $post_mime_type = '';
319 36
320
	/**
321
	 * The comment count
322
	 *
323
	 * @since  1.0
324
	 * @access public
325
	 *
326
	 * @var    int
327
	 */
328
	public $comment_count = 0;
329 36
330
	/**
331
	 * Filtered
332
	 *
333
	 * @since  1.0
334
	 * @access public
335
	 *
336
	 * @var    string
337
	 */
338
	public $filter;
339 2
340
	/**
341 2
	 * Class Constructor
342
	 *
343 2
	 * Set up the Give Donate Form Class.
344
	 *
345 2
	 * @since  1.0
346
	 * @access public
347 1
	 *
348
	 * @param  int|bool $_id   Post id. Default is false.
349 1
	 * @param  array    $_args Arguments passed.
350
	 */
351 2
	public function __construct( $_id = false, $_args = array() ) {
0 ignored issues
show
The parameter $_args 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...
352
353
		$donation_form = WP_Post::get_instance( $_id );
354
355 2
		return $this->setup_donation_form( $donation_form );
0 ignored issues
show
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
356
	}
357 2
358
	/**
359
	 * Given the donation form data, let's set the variables
360
	 *
361
	 * @since  1.5
362
	 * @access private
363
	 *
364
	 * @param  WP_Post $donation_form WP_Post Object for the donation form.
365
	 *
366
	 * @return bool                   If the setup was successful or not.
367
	 */
368
	private function setup_donation_form( $donation_form ) {
369
370
		if ( ! is_object( $donation_form ) ) {
371
			return false;
372
		}
373
374
		if ( ! is_a( $donation_form, 'WP_Post' ) ) {
375
			return false;
376
		}
377
378
		if ( 'give_forms' !== $donation_form->post_type ) {
379
			return false;
380
		}
381
382
		foreach ( $donation_form as $key => $value ) {
383
384
			switch ( $key ) {
385
386
				default:
0 ignored issues
show
default: $this->{$key} = $value; break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
387
					$this->$key = $value;
388
					break;
389
390
			}
0 ignored issues
show
Blank line found after control structure
Loading history...
391
392
		}
393
394
		return true;
395
396 53
	}
397
398 53
	/**
399 53
	 * Magic __get function to dispatch a call to retrieve a private property
400
	 *
401 53
	 * @since  1.0
402 36
	 * @access public
403 36
	 *
404
	 * @param  string $key
405
	 *
406
	 * @return mixed
407
	 */
408 View Code Duplication
	public function __get( $key ) {
0 ignored issues
show
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...
409
410
		if ( method_exists( $this, 'get_' . $key ) ) {
411 53
412
			return call_user_func( array( $this, 'get_' . $key ) );
413
414
		} else {
415
416
			/* translators: %s: property key */
417
			return new WP_Error( 'give-form-invalid-property', sprintf( esc_html__( 'Can\'t get property %s.', 'give' ), $key ) );
418
419
		}
420
421
	}
422
423
	/**
424
	 * Creates a donation form
425
	 *
426
	 * @since  1.5
427
	 * @access public
428
	 *
429
	 * @param  array $data Array of attributes for a donation form.
430
	 *
431
	 * @return bool|int    False if data isn't passed and class not instantiated for creation, or New Form ID.
432
	 */
433
	public function create( $data = array() ) {
434
435
		if ( $this->id != 0 ) {
0 ignored issues
show
Found "!= 0". Use Yoda Condition checks, you must
Loading history...
436
			return false;
437
		}
438
439
		$defaults = array(
440
			'post_type'   => 'give_forms',
441
			'post_status' => 'draft',
442
			'post_title'  => __( 'New Donation Form', 'give' ),
443 42
		);
444
445 42
		$args = wp_parse_args( $data, $defaults );
446
447 42
		/**
448 23
		 * Fired before a donation form is created
449 23
		 *
450
		 * @param array $args The post object arguments used for creation.
451 42
		 */
452
		do_action( 'give_form_pre_create', $args );
453 42
454
		$id = wp_insert_post( $args, true );
455
456
		$donation_form = WP_Post::get_instance( $id );
457
458 42
		/**
459
		 * Fired after a donation form is created
460 42
		 *
461
		 * @param int   $id   The post ID of the created item.
462
		 * @param array $args The post object arguments used for creation.
463
		 */
464
		do_action( 'give_form_post_create', $id, $args );
465
466
		return $this->setup_donation_form( $donation_form );
467
468
	}
469
470
	/**
471
	 * Retrieve the ID
472
	 *
473 42
	 * @since  1.0
474
	 * @access public
475 42
	 *
476 42
	 * @return int    Donation form ID.
477 42
	 */
478
	public function get_ID() {
0 ignored issues
show
The function name get_ID is in camel caps, but expected get_i_d instead as per the coding standard.
Loading history...
479 42
		return $this->ID;
480
	}
481 42
482
	/**
483 42
	 * Retrieve the donation form name
484
	 *
485
	 * @since  1.5
486
	 * @access public
487 1
	 *
488
	 * @return string Donation form name.
489
	 */
490
	public function get_name() {
491
		return get_the_title( $this->ID );
492
	}
493
494
	/**
495
	 * Retrieve the price
496
	 *
497
	 * @since  1.0
498
	 * @access public
499 19
	 *
500
	 * @return float  Price.
501 19
	 */
502 View Code Duplication
	public function get_price() {
0 ignored issues
show
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...
503
504 19
		if ( ! isset( $this->price ) ) {
505
506 19
			$this->price = give_maybe_sanitize_amount(
0 ignored issues
show
Documentation Bug introduced by
It seems like give_maybe_sanitize_amou...give_set_price', true)) can also be of type integer or string. However, the property $price is declared as type double. Maybe add an additional type check?

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

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

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

class Id
{
    public $id;

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

}

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

$account_id = false;

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

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
507 19
				give_get_meta(
508
					$this->ID,
509 19
					'_give_set_price',
510
					true
511 5
				)
512
			);
513 5
514
			if ( ! $this->price ) {
515
				$this->price = 0;
0 ignored issues
show
Documentation Bug introduced by
The property $price was declared of type double, but 0 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
516
			}
0 ignored issues
show
Blank line found after control structure
Loading history...
517 15
518
		}
519 16
520
		/**
521
		 * Override the donation form set price.
522
		 *
523
		 * @since 1.0
524
		 *
525
		 * @param string     $price The donation form price.
526
		 * @param string|int $id    The form ID.
527
		 */
528
		return apply_filters( 'give_get_set_price', $this->price, $this->ID );
529 43
	}
530
531 43
	/**
532
	 * Retrieve the minimum price.
533 43
	 *
534 23
	 * @since  1.3.6
535 23
	 * @access public
536
	 *
537 43
	 * @return float  Minimum price.
538
	 */
539 43
	public function get_minimum_price() {
540
541
		if ( ! isset( $this->minimum_price ) ) {
542
543
			$this->minimum_price = give_get_meta( $this->ID, '_give_custom_amount_range_minimum', true );
544 43
545
			// Give backward < 2.1
546 43
			if ( empty( $this->minimum_price ) ) {
547
				$this->minimum_price = give_get_meta( $this->ID, '_give_custom_amount_minimum', true );
548
			}
549
550
			if ( ! $this->is_custom_price_mode() ) {
551
				$this->minimum_price = give_get_lowest_price_option( $this->ID );
552
			}
0 ignored issues
show
Blank line found after control structure
Loading history...
553
554
		}
555
556 42
		return apply_filters( 'give_get_set_minimum_price', $this->minimum_price, $this->ID );
557
	}
558 42
559 42
	/**
560
	 * Retrieve the maximum price.
561 42
	 *
562
	 * @since  2.1
563 42
	 * @access public
564
	 *
565 42
	 * @return float  Maximum price.
566
	 */
567 View Code Duplication
	public function get_maximum_price() {
0 ignored issues
show
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...
568
569 1
		if ( ! isset( $this->maximum_price ) ) {
570
			$this->maximum_price = give_get_meta( $this->ID, '_give_custom_amount_range_maximum', true, 999999.99 );
0 ignored issues
show
999999.99 is of type double, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
571
572
			if ( ! $this->is_custom_price_mode() ) {
573
				$this->maximum_price = give_get_highest_price_option( $this->ID );
574
			}
575
		}
576
577
		return apply_filters( 'give_get_set_maximum_price', $this->maximum_price, $this->ID );
578
	}
579 19
580
	/**
581 19
	 * Retrieve the variable prices
582
	 *
583 19
	 * @since  1.0
584
	 * @access public
585 19
	 *
586
	 * @return array  Variable prices.
587
	 */
588 19
	public function get_prices() {
589
590 5
		if ( ! isset( $this->prices ) ) {
591
592 5
			$this->prices = give_get_meta( $this->ID, '_give_donation_levels', true );
0 ignored issues
show
Documentation Bug introduced by
It seems like give_get_meta($this->ID,...donation_levels', true) of type * is incompatible with the declared type array of property $prices.

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...
593
594
		}
595
596 15
		/**
597
		 * Override multi-level prices
598 16
		 *
599
		 * @since 1.0
600
		 *
601
		 * @param array      $prices The array of mulit-level prices.
602
		 * @param int|string $ID     The ID of the form.
603
		 */
604
		return apply_filters( 'give_get_donation_levels', $this->prices, $this->ID );
605
606
	}
607
608
	/**
609
	 * Get donation form level info
610
	 *
611
	 * @since  2.0.6
612
	 * @access public
613
	 *
614
	 * @param $price_id
615
	 *
616
	 * @return array|null
617
	 */
618
	public function get_level_info( $price_id ) {
619
		$level_info = array();
620
621
		// Bailout.
622
		if ( 'multi' !== $this->get_type() ) {
623
			return null;
624
		} elseif ( ! ( $levels = $this->get_prices() ) ) {
625
			return $level_info;
626
		}
627
628
		foreach ( $levels as $level ) {
629
			if ( $price_id === $level['_give_id']['level_id'] ) {
630
				$level_info = $level;
631
				break;
632
			}
633
		}
634
635
		return $level_info;
636
	}
637
638 1
639
	/**
640 1
	 * Retrieve the goal
641 1
	 *
642 1
	 * @since  1.0
643 1
	 * @access public
644
	 *
645
	 * @return float  Goal.
646
	 */
647
	public function get_goal() {
648
649
		if ( ! isset( $this->goal ) ) {
650
651
			$goal_format = give_get_form_goal_format( $this->ID );
652
653
			if ( 'donation' === $goal_format ) {
654
				$this->goal = give_get_meta( $this->ID, '_give_number_of_donation_goal', true );
655
			} elseif ( 'donors' === $goal_format ) {
656
				$this->goal = give_get_meta( $this->ID, '_give_number_of_donor_goal', true );
657
			} else {
658 42
				$this->goal = give_get_meta( $this->ID, '_give_set_goal', true );
659
			}
660 42
661
			if ( ! $this->goal ) {
662 42
				$this->goal = 0;
0 ignored issues
show
Documentation Bug introduced by
The property $goal was declared of type double, but 0 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
663 1
			}
0 ignored issues
show
Blank line found after control structure
Loading history...
664
665
		}
666
667 42
		return apply_filters( 'give_get_set_goal', $this->goal, $this->ID );
668
669 42
	}
670 42
671 42
	/**
672
	 * Determine if single price mode is enabled or disabled
673
	 *
674
	 * @since  1.0
675 42
	 * @access public
676
	 *
677 42
	 * @return bool
678
	 */
679 42 View Code Duplication
	public function is_single_price_mode() {
0 ignored issues
show
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...
680
681 42
		$option = give_get_meta( $this->ID, '_give_price_option', true );
682
		$ret    = 0;
683
684
		if ( empty( $option ) || $option === 'set' ) {
0 ignored issues
show
Found "=== '". Use Yoda Condition checks, you must
Loading history...
685 16
			$ret = 1;
686
		}
687
688
		/**
689
		 * Override the price mode for a donation when checking if is in single price mode.
690
		 *
691
		 * @since 1.0
692
		 *
693
		 * @param bool       $ret Is donation form in single price mode?
694
		 * @param int|string $ID  The ID of the donation form.
695
		 */
696
		return (bool) apply_filters( 'give_single_price_option_mode', $ret, $this->ID );
697
698
	}
699
700
	/**
701
	 * Determine if custom price mode is enabled or disabled
702
	 *
703
	 * @since  1.6
704
	 * @access public
705
	 *
706
	 * @return bool
707
	 */
708
	public function is_custom_price_mode() {
709
710
		$option = give_get_meta( $this->ID, '_give_custom_amount', true );
711
		$ret    = 0;
712
713
		if ( give_is_setting_enabled( $option ) ) {
714
			$ret = 1;
715
		}
716
717
		/**
718
		 * Override the price mode for a donation when checking if is in custom price mode.
719
		 *
720
		 * @since 1.6
721
		 *
722
		 * @param bool       $ret Is donation form in custom price mode?
723
		 * @param int|string $ID  The ID of the donation form.
724
		 */
725
		return (bool) apply_filters( 'give_custom_price_option_mode', $ret, $this->ID );
726
727
	}
728
729
	/**
730
	 * Determine if custom price mode is enabled or disabled
731
	 *
732
	 * @since  1.8.18
733
	 * @access public
734
	 *
735
	 * @param string|float $amount Donation Amount.
736
	 *
737
	 * @return bool
738
	 */
739
	public function is_custom_price( $amount ) {
740
		$result = false;
741
		$amount = give_maybe_sanitize_amount( $amount );
742
743
		if ( $this->is_custom_price_mode() ) {
744
745
			if ( 'set' === $this->get_type() ) {
746
				if ( $amount !== $this->get_price() ) {
747
					$result = true;
748
				}
0 ignored issues
show
Blank line found after control structure
Loading history...
749
750
			} elseif ( 'multi' === $this->get_type() ) {
751
				$level_amounts = array_map( 'give_maybe_sanitize_amount', wp_list_pluck( $this->get_prices(), '_give_amount' ) );
752
				$result        = ! in_array( $amount, $level_amounts );
753
			}
754
		}
755
756
		/**
757
		 * Filter to reset whether it is custom price or not.
758
		 *
759
		 * @param bool         $result True/False.
760
		 * @param string|float $amount Donation Amount.
761
		 * @param int          $this   ->ID Form ID.
762
		 *
763
		 * @since 1.8.18
764
		 */
765
		return (bool) apply_filters( 'give_is_custom_price', $result, $amount, $this->ID );
766
	}
767
768
	/**
769
	 * Has Variable Prices
770
	 *
771
	 * Determine if the donation form has variable prices enabled
772
	 *
773
	 * @since  1.0
774
	 * @access public
775
	 *
776
	 * @return bool
777
	 */
778 View Code Duplication
	public function has_variable_prices() {
0 ignored issues
show
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...
779
780
		$option = give_get_meta( $this->ID, '_give_price_option', true );
781
		$ret    = 0;
782
783
		if ( $option === 'multi' ) {
0 ignored issues
show
Found "=== '". Use Yoda Condition checks, you must
Loading history...
784
			$ret = 1;
785
		}
786
787
		/**
788
		 * Filter: Override whether the donation form has variables prices.
789
		 *
790
		 * @param bool       $ret Does donation form have variable prices?
791
		 * @param int|string $ID  The ID of the donation form.
792
		 */
793
		return (bool) apply_filters( 'give_has_variable_prices', $ret, $this->ID );
794
795
	}
796
797
	/**
798
	 * Retrieve the donation form type, set or multi-level
799
	 *
800
	 * @since  1.5
801
	 * @access public
802
	 *
803
	 * @return string Type of donation form, either 'set' or 'multi'.
804
	 */
805 View Code Duplication
	public function get_type() {
0 ignored issues
show
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...
806
807
		if ( ! isset( $this->type ) ) {
808
809
			$this->type = give_get_meta( $this->ID, '_give_price_option', true );
810
811
			if ( empty( $this->type ) ) {
812
				$this->type = 'set';
813
			}
0 ignored issues
show
Blank line found after control structure
Loading history...
814
815
		}
816
817
		return apply_filters( 'give_get_form_type', $this->type, $this->ID );
818
819
	}
820
821
	/**
822
	 * Get form tag classes.
823
	 *
824
	 * Provides the classes for the donation <form> html tag and filters for customization.
825
	 *
826
	 * @since  1.6
827
	 * @access public
828
	 *
829
	 * @param  $args
830
	 *
831
	 * @return string
832
	 */
833
	public function get_form_classes( $args ) {
834
835
		$float_labels_option = give_is_float_labels_enabled( $args )
836
			? 'float-labels-enabled'
837
			: '';
838
839
		$form_classes_array = apply_filters( 'give_form_classes', array(
840
			'give-form',
841
			'give-form-' . $this->ID,
842
			'give-form-type-' . $this->get_type(),
843
			$float_labels_option,
844
		), $this->ID, $args );
845
846
		// Remove empty class names.
847
		$form_classes_array = array_filter( $form_classes_array );
848
849
		return implode( ' ', $form_classes_array );
850
851
	}
852
853
	/**
854
	 * Get form wrap Classes.
855
	 *
856
	 * Provides the classes for the donation form div wrapper and filters for customization.
857
	 *
858
	 * @access public
859
	 *
860
	 * @param  $args
861
	 *
862
	 * @return string
863
	 */
864
	public function get_form_wrap_classes( $args ) {
865
		$custom_class = array(
866
			'give-form-wrap',
867
		);
868
869
		if ( $this->is_close_donation_form() ) {
870
			$custom_class[] = 'give-form-closed';
871
		} else {
872
			$display_option = ( isset( $args['display_style'] ) && ! empty( $args['display_style'] ) )
873
				? $args['display_style']
874
				: give_get_meta( $this->ID, '_give_payment_display', true );
875
876
			$custom_class[] = "give-display-{$display_option}";
877
878
			// If admin want to show only button for form then user inbuilt modal functionality.
879
			if ( 'button' === $display_option ) {
880
				$custom_class[] = 'give-display-button-only';
881
			}
882
		}
883
0 ignored issues
show
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
884
885
		/**
886
		 * Filter the donation form classes.
887
		 *
888
		 * @since 1.0
889
		 */
890
		$form_wrap_classes_array = (array) apply_filters( 'give_form_wrap_classes', $custom_class, $this->ID, $args );
891
0 ignored issues
show
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
892
893
		return implode( ' ', $form_wrap_classes_array );
894
895
	}
896
897
	/**
898
	 * Get if form type set or not.
899
	 *
900
	 * @since  1.6
901
	 * @access public
902
	 *
903
	 * @return bool
904
	 */
905
	public function is_set_type_donation_form() {
906
		$form_type = $this->get_type();
907
908
		return ( 'set' === $form_type ? true : false );
909
	}
910
911
	/**
912
	 * Get if form type multi or not.
913
	 *
914
	 * @since  1.6
915
	 * @access public
916
	 *
917
	 * @return bool True if form type is 'multi' and false otherwise.
918
	 */
919
	public function is_multi_type_donation_form() {
920
		$form_type = $this->get_type();
921
922
		return ( 'multi' === $form_type ? true : false );
923
924
	}
925
926
	/**
927
	 * Retrieve the sale count for the donation form
928
	 *
929
	 * @since  1.0
930
	 * @access public
931
	 *
932
	 * @return int    Donation form sale count.
933
	 */
934 View Code Duplication
	public function get_sales() {
0 ignored issues
show
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...
935
936
		if ( ! isset( $this->sales ) ) {
937
938
			if ( '' == give_get_meta( $this->ID, '_give_form_sales', true ) ) {
939
				add_post_meta( $this->ID, '_give_form_sales', 0 );
940
			} // End if
941
942
			$this->sales = give_get_meta( $this->ID, '_give_form_sales', true );
943
944
			if ( $this->sales < 0 ) {
945
				// Never let sales be less than zero.
946
				$this->sales = 0;
947
			}
0 ignored issues
show
Blank line found after control structure
Loading history...
948
949
		}
950
951
		return $this->sales;
952
953
	}
954
955
	/**
956
	 * Increment the sale count by one
957
	 *
958
	 * @since  1.0
959
	 * @access public
960
	 *
961
	 * @param  int $quantity The quantity to increase the donations by. Default is 1.
962
	 *
963
	 * @return int|false     New number of total sales.
964
	 */
965
	public function increase_sales( $quantity = 1 ) {
966
967
		$sales       = give_get_form_sales_stats( $this->ID );
968
		$quantity    = absint( $quantity );
969
		$total_sales = $sales + $quantity;
970
971
		if ( $this->update_meta( '_give_form_sales', $total_sales ) ) {
972
973
			$this->sales = $total_sales;
974
975
			return $this->sales;
976
977
		}
978
979
		return false;
980
	}
981
982
	/**
983
	 * Decrement the sale count by one
984
	 *
985
	 * @since  1.0
986
	 * @access public
987
	 *
988
	 * @param  int $quantity The quantity to decrease by. Default is 1.
989
	 *
990
	 * @return int|false     New number of total sales.
991
	 */
992
	public function decrease_sales( $quantity = 1 ) {
993
994
		$sales = give_get_form_sales_stats( $this->ID );
995
996
		// Only decrease if not already zero
997
		if ( $sales > 0 ) {
998
999
			$quantity    = absint( $quantity );
1000
			$total_sales = $sales - $quantity;
1001
1002
			if ( $this->update_meta( '_give_form_sales', $total_sales ) ) {
1003
1004
				$this->sales = $sales;
0 ignored issues
show
Documentation Bug introduced by
It seems like $sales can also be of type double. However, the property $sales is declared as type integer. Maybe add an additional type check?

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

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

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

class Id
{
    public $id;

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

}

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

$account_id = false;

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

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1005
1006
				return $sales;
1007
1008
			}
0 ignored issues
show
Blank line found after control structure
Loading history...
1009
1010
		}
1011
1012
		return false;
1013
1014
	}
1015
1016
	/**
1017
	 * Retrieve the total earnings for the form
1018
	 *
1019
	 * @since  1.0
1020
	 * @access public
1021
	 *
1022
	 * @return float  Donation form total earnings.
1023
	 */
1024 View Code Duplication
	public function get_earnings() {
0 ignored issues
show
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...
1025
1026
		if ( ! isset( $this->earnings ) ) {
1027
1028
			if ( '' == give_get_meta( $this->ID, '_give_form_earnings', true ) ) {
1029
				add_post_meta( $this->ID, '_give_form_earnings', 0 );
1030
			}
1031
1032
			$this->earnings = give_get_meta( $this->ID, '_give_form_earnings', true );
1033
1034
			if ( $this->earnings < 0 ) {
1035
				// Never let earnings be less than zero
1036
				$this->earnings = 0;
0 ignored issues
show
Documentation Bug introduced by
The property $earnings was declared of type double, but 0 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1037
			}
0 ignored issues
show
Blank line found after control structure
Loading history...
1038
1039
		}
1040
1041
		return $this->earnings;
1042
1043
	}
1044
1045
	/**
1046
	 * Increase the earnings by the given amount
1047
	 *
1048
	 * @since  1.0
1049
	 * @since  2.1 Pass the donation ID.
1050
	 *
1051
	 * @access public
1052
	 *
1053
	 * @param  int $amount     Amount of donation. Default is 0.
1054
	 * @param int  $payment_id Donation ID.
1055
	 *
1056
	 * @return float|false
1057
	 */
1058 View Code Duplication
	public function increase_earnings( $amount = 0, $payment_id = 0 ) {
0 ignored issues
show
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...
1059
1060
		$earnings   = give_get_form_earnings_stats( $this->ID );
1061
1062
		/**
1063
		 * Modify the earning amount when increasing.
1064
		 *
1065
		 * @since 2.1
1066
		 *
1067
		 * @param float $amount     Earning amount.
1068
		 * @param int   $form_id    Donation form ID.
1069
		 * @param int   $payment_id Donation ID.
1070
		 */
1071
		$amount = apply_filters( 'give_increase_form_earnings_amount', $amount, $this->ID, $payment_id );
1072
1073
		$new_amount = $earnings + (float) $amount;
1074
1075
		if ( $this->update_meta( '_give_form_earnings', $new_amount ) ) {
1076
1077
			$this->earnings = $new_amount;
1078
1079
			return $this->earnings;
1080
1081
		}
1082
1083
		return false;
1084
1085
	}
1086
1087
	/**
1088
	 * Decrease the earnings by the given amount
1089
	 *
1090
	 * @since  1.0
1091
	 * @access public
1092
	 *
1093
	 * @param  int $amount     Amount of donation.
1094
	 * @param int  $payment_id Donation ID.
1095
	 *
1096
	 * @return float|false
1097
	 */
1098 View Code Duplication
	public function decrease_earnings( $amount, $payment_id = 0 ) {
0 ignored issues
show
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...
1099
1100
		$earnings = give_get_form_earnings_stats( $this->ID );
1101
1102
		if ( $earnings > 0 ) {
1103
1104
			/**
1105
			 * Modify the earning value when decreasing it.
1106
			 *
1107
			 * @since 2.1
1108
			 *
1109
			 * @param float $amount     Earning amount.
1110
			 * @param int   $form_id    Donation Form ID.
1111
			 * @param int   $payment_id Donation ID.
1112
			 */
1113
			$amount = apply_filters( 'give_decrease_form_earnings_amount', $amount, $this->ID, $payment_id );
1114
1115
			// Only decrease if greater than zero
1116
			$new_amount = $earnings - (float) $amount;
1117
1118
			if ( $this->update_meta( '_give_form_earnings', $new_amount ) ) {
1119
				$this->earnings = $new_amount;
1120
1121
				return $this->earnings;
1122
			}
0 ignored issues
show
Blank line found after control structure
Loading history...
1123
1124
		}
1125
1126
		return false;
1127
1128
	}
1129
1130
	/**
1131
	 * Determine if donation form closed or not
1132
	 *
1133
	 * Form will be close if:
1134
	 *  a. form has fixed goal
1135
	 *  b. close form when goal achieved cmb2 setting is set to 'Yes'
1136
	 *  c. goal has been achieved
1137
	 *
1138
	 * @since  1.4.5
1139
	 * @access public
1140
	 *
1141
	 * @return bool
1142
	 */
1143
	public function is_close_donation_form() {
1144
		$is_closed = ( 'closed' === give_get_meta( $this->ID, '_give_form_status', true, 'open' ) );
0 ignored issues
show
'open' is of type string, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1145
1146
		// If manual upgrade not completed, proceed with backward compatible code.
1147
		if ( ! give_has_upgrade_completed( 'v210_verify_form_status_upgrades' ) ) {
1148
1149
			// Check for backward compatibility.
1150
			$is_closed = $this->bc_210_is_close_donation_form();
1151
		}
1152
1153
		/**
1154
		 * Filter the close form result.
1155
		 *
1156
		 * @since 1.8
1157
		 */
1158
		return apply_filters(
1159
			'give_is_close_donation_form',
1160
			$is_closed,
1161
			$this
1162
		);
1163
1164
	}
1165
1166
	/**
1167
	 * Updates a single meta entry for the donation form
1168
	 *
1169
	 * @since  1.5
1170
	 * @access private
1171
	 *
1172
	 * @param  string              $meta_key   The meta_key to update.
1173
	 * @param  string|array|object $meta_value The value to put into the meta.
1174
	 *
1175
	 * @return bool                            The result of the update query.
1176
	 */
1177
	private function update_meta( $meta_key = '', $meta_value = '' ) {
1178
1179
		/* @var WPDB $wpdb */
1180
		global $wpdb;
1181
1182
		// Bailout.
1183
		if ( empty( $meta_key ) ) {
1184
			return false;
1185
		}
1186
1187
		if ( give_update_meta( $this->ID, $meta_key, $meta_value ) ) {
1188
			return true;
1189
		}
1190
1191
		return false;
1192
	}
1193
1194
	/**
1195
	 * Backward Compatible function for is_close_donation_form()
1196
	 *
1197
	 * @since 2.1.0
1198
	 *
1199
	 * @return bool
1200
	 */
1201
	private function bc_210_is_close_donation_form() {
1202
1203
		$close_form      = false;
1204
		$is_goal_enabled = give_is_setting_enabled( give_get_meta( $this->ID, '_give_goal_option', true, 'disabled' ) );
0 ignored issues
show
'disabled' is of type string, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1205
1206
		// Proceed, if the form goal is enabled.
1207
		if ( $is_goal_enabled ) {
1208
1209
			$close_form_when_goal_achieved = give_is_setting_enabled( give_get_meta( $this->ID, '_give_close_form_when_goal_achieved', true, 'disabled' ) );
0 ignored issues
show
'disabled' is of type string, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1210
1211
			// Proceed, if close form when goal achieved option is enabled.
1212
			if ( $close_form_when_goal_achieved ) {
1213
1214
				$form        = new Give_Donate_Form( $this->ID );
1215
				$goal_format = give_get_form_goal_format( $this->ID );
1216
1217
				// Verify whether the form is closed or not after processing data based on goal format.
1218
				switch ( $goal_format ) {
1219
					case 'donation':
1220
						$closed = $form->get_goal() <= $form->get_sales();
1221
						break;
1222
					case 'donors':
1223
						$closed = $form->get_goal() <= give_get_form_donor_count( $this->ID );
1224
						break;
1225
					default :
1226
						$closed = $form->get_goal() <= $form->get_earnings();
1227
						break;
1228
				}
1229
1230
				if ( $closed ) {
1231
					$close_form = true;
1232
				}
0 ignored issues
show
Blank line found after control structure
Loading history...
1233
1234
			}
1235
		}
1236
1237
		return $close_form;
1238
	}
1239
1240
}
1241