Issues (1282)

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 (21 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, 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_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
	private $sales;
104
105
	/**
106
	 * The form's total earnings
107
	 *
108
	 * @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
	/**
121
	 * The post author
122
	 *
123
	 * @since  1.0
124
	 * @access public
125
	 *
126
	 * @var    int
127
	 */
128
	public $post_author = 0;
129
130
	/**
131
	 * The post date
132
	 *
133
	 * @since  1.0
134
	 * @access public
135
	 *
136
	 * @var    string
137
	 */
138
	public $post_date = '0000-00-00 00:00:00';
139
140
	/**
141
	 * The post GTM date
142
	 *
143
	 * @since  1.0
144
	 * @access public
145
	 *
146
	 * @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
	/**
161
	 * The post title
162
	 *
163
	 * @since  1.0
164
	 * @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
	public $post_name = '';
229
230
	/**
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
	/**
251
	 * The post modified date
252
	 *
253
	 * @since  1.0
254
	 * @access public
255
	 *
256
	 * @var    string
257
	 */
258
	public $post_modified = '0000-00-00 00:00:00';
259
260
	/**
261
	 * The post modified GTM date
262
	 *
263
	 * @since  1.0
264
	 * @access public
265
	 *
266
	 * @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
	 * @var    string
277
	 */
278
	public $post_content_filtered = '';
279
280
	/**
281
	 * The post parent
282
	 *
283
	 * @since  1.0
284
	 * @access public
285
	 *
286
	 * @var    int
287
	 */
288
	public $post_parent = 0;
289
290
	/**
291
	 * The post GUID
292
	 *
293
	 * @since  1.0
294
	 * @access public
295
	 *
296
	 * @var    string
297
	 */
298
	public $guid = '';
299
300
	/**
301
	 * The menu order
302
	 *
303
	 * @since  1.0
304
	 * @access public
305
	 *
306
	 * @var    int
307
	 */
308
	public $menu_order = 0;
309
310
	/**
311
	 * The mime type0
312
	 *
313
	 * @since  1.0
314
	 * @access public
315
	 *
316
	 * @var    string
317
	 */
318
	public $post_mime_type = '';
319
320
	/**
321
	 * The comment count
322
	 *
323
	 * @since  1.0
324
	 * @access public
325
	 *
326
	 * @var    int
327
	 */
328
	public $comment_count = 0;
329
330
	/**
331
	 * Filtered
332
	 *
333
	 * @since  1.0
334
	 * @access public
335
	 *
336
	 * @var    string
337
	 */
338
	public $filter;
339
340
	/**
341
	 * Class Constructor
342
	 *
343
	 * Set up the Give Donate Form Class.
344
	 *
345
	 * @since  1.0
346
	 * @access public
347
	 *
348
	 * @param  int|bool $_id   Post id. Default is false.
349
	 * @param  array    $_args Arguments passed.
350
	 */
351
	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
		$donation_form = WP_Post::get_instance( $_id );
353
354
		$this->setup_donation_form( $donation_form );
355
	}
356
357
	/**
358
	 * Given the donation form data, let's set the variables
359
	 *
360
	 * @since  1.5
361
	 * @access private
362
	 *
363
	 * @param  WP_Post $donation_form WP_Post Object for the donation form.
364
	 *
365
	 * @return bool                   If the setup was successful or not.
366
	 */
367
	private function setup_donation_form( $donation_form ) {
368
369
		// Bailout.
370
		if (
371
			! ( $donation_form instanceof WP_Post )
0 ignored issues
show
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...
372
			|| 'give_forms' !== $donation_form->post_type
373
		) {
374
			return false;
375
		}
376
377
378
		Give_Forms_Query::update_meta_cache( array( $donation_form->ID ) );
379
380
		foreach ( $donation_form as $key => $value ) {
381
			$this->$key = $value;
382
		}
383
384
		return true;
385
386
	}
387
388
	/**
389
	 * Magic __get function to dispatch a call to retrieve a private property
390
	 *
391
	 * @since  1.0
392
	 * @access public
393
	 *
394
	 * @param  string $key
395
	 *
396
	 * @return mixed
397
	 */
398
	public function __get( $key ) {
399
400
		if ( method_exists( $this, "get_{$key}" ) ) {
401
			return $this->{"get_{$key}"}();
402
		}
403
404
		/* translators: %s: property key */
405
		return new WP_Error( 'give-form-invalid-property', sprintf( esc_html__( 'Can\'t get property %s.', 'give' ), $key ) );
406
407
	}
408
409
	/**
410
	 * Creates a donation form
411
	 *
412
	 * @since  1.5
413
	 * @access public
414
	 *
415
	 * @param  array $data Array of attributes for a donation form.
416
	 *
417
	 * @return bool|int    False if data isn't passed and class not instantiated for creation, or New Form ID.
418
	 */
419
	public function create( $data = array() ) {
420
421
		if ( $this->id != 0 ) {
422
			return false;
423
		}
424
425
		$defaults = array(
426
			'post_type'   => 'give_forms',
427
			'post_status' => 'draft',
428
			'post_title'  => __( 'New Donation Form', 'give' ),
429
		);
430
431
		$args = wp_parse_args( $data, $defaults );
432
433
		/**
434
		 * Fired before a donation form is created
435
		 *
436
		 * @param array $args The post object arguments used for creation.
437
		 */
438
		do_action( 'give_form_pre_create', $args );
439
440
		$id = wp_insert_post( $args, true );
441
442
		$donation_form = WP_Post::get_instance( $id );
443
444
		/**
445
		 * Fired after a donation form is created
446
		 *
447
		 * @param int   $id   The post ID of the created item.
448
		 * @param array $args The post object arguments used for creation.
449
		 */
450
		do_action( 'give_form_post_create', $id, $args );
451
452
		return $this->setup_donation_form( $donation_form );
453
454
	}
455
456
	/**
457
	 * Retrieve the ID
458
	 *
459
	 * @since  1.0
460
	 * @access public
461
	 *
462
	 * @return int    Donation form ID.
463
	 */
464
	public function get_ID() {
465
		return $this->ID;
466
	}
467
468
	/**
469
	 * Retrieve the donation form name
470
	 *
471
	 * @since  1.5
472
	 * @access public
473
	 *
474
	 * @return string Donation form name.
475
	 */
476
	public function get_name() {
477
		return get_the_title( $this->ID );
478
	}
479
480
	/**
481
	 * Retrieve the price
482
	 *
483
	 * @since  1.0
484
	 * @access public
485
	 *
486
	 * @return float  Price.
487
	 */
488 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...
489
490
		if ( ! isset( $this->price ) ) {
491
492
			$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...
493
				give_get_meta(
494
					$this->ID,
495
					'_give_set_price',
496
					true
497
				)
498
			);
499
500
			if ( ! $this->price ) {
501
				$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...
502
			}
503
504
		}
505
506
		/**
507
		 * Override the donation form set price.
508
		 *
509
		 * @since 1.0
510
		 *
511
		 * @param string     $price The donation form price.
512
		 * @param string|int $id    The form ID.
513
		 */
514
		return apply_filters( 'give_get_set_price', $this->price, $this->ID );
515
	}
516
517
	/**
518
	 * Retrieve the minimum price.
519
	 *
520
	 * @since  1.3.6
521
	 * @access public
522
	 *
523
	 * @return float  Minimum price.
524
	 */
525
	public function get_minimum_price() {
526
527
		if ( ! isset( $this->minimum_price ) ) {
528
529
			$this->minimum_price = give_get_meta( $this->ID, '_give_custom_amount_range_minimum', true );
530
531
			// Give backward < 2.1
532
			if ( empty( $this->minimum_price ) ) {
533
				$this->minimum_price = give_get_meta( $this->ID, '_give_custom_amount_minimum', true );
534
			}
535
536
			if ( ! $this->is_custom_price_mode() ) {
537
				$this->minimum_price = give_get_lowest_price_option( $this->ID );
538
			}
539
540
		}
541
542
		return apply_filters( 'give_get_set_minimum_price', $this->minimum_price, $this->ID );
543
	}
544
545
	/**
546
	 * Retrieve the maximum price.
547
	 *
548
	 * @since  2.1
549
	 * @access public
550
	 *
551
	 * @return float  Maximum price.
552
	 */
553 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...
554
555
		if ( ! isset( $this->maximum_price ) ) {
556
			$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...
557
558
			if ( ! $this->is_custom_price_mode() ) {
559
				$this->maximum_price = give_get_highest_price_option( $this->ID );
560
			}
561
		}
562
563
		return apply_filters( 'give_get_set_maximum_price', $this->maximum_price, $this->ID );
564
	}
565
566
	/**
567
	 * Retrieve the variable prices
568
	 *
569
	 * @since  1.0
570
	 * @access public
571
	 *
572
	 * @return array  Variable prices.
573
	 */
574
	public function get_prices() {
575
576
		if ( ! isset( $this->prices ) ) {
577
578
			$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...
579
580
		}
581
582
		/**
583
		 * Override multi-level prices
584
		 *
585
		 * @since 1.0
586
		 *
587
		 * @param array      $prices The array of mulit-level prices.
588
		 * @param int|string $ID     The ID of the form.
589
		 */
590
		return apply_filters( 'give_get_donation_levels', $this->prices, $this->ID );
591
592
	}
593
594
	/**
595
	 * Get donation form level info
596
	 *
597
	 * @since  2.0.6
598
	 * @access public
599
	 *
600
	 * @param $price_id
601
	 *
602
	 * @return array|null
603
	 */
604
	public function get_level_info( $price_id ) {
605
		$level_info = array();
606
607
		// Bailout.
608
		if ( 'multi' !== $this->get_type() ) {
609
			return null;
610
		} elseif ( ! ( $levels = $this->get_prices() ) ) {
611
			return $level_info;
612
		}
613
614
		foreach ( $levels as $level ) {
615
			if ( $price_id === $level['_give_id']['level_id'] ) {
616
				$level_info = $level;
617
				break;
618
			}
619
		}
620
621
		return $level_info;
622
	}
623
624
625
	/**
626
	 * Retrieve the goal
627
	 *
628
	 * @since  1.0
629
	 * @access public
630
	 *
631
	 * @return float  Goal.
632
	 */
633
	public function get_goal() {
634
635
		if ( ! isset( $this->goal ) ) {
636
637
			$goal_format = give_get_form_goal_format( $this->ID );
638
639
			if( ! $this->has_goal() ) {
640
				$this->goal = '';
0 ignored issues
show
Documentation Bug introduced by
The property $goal was declared of type double, but '' is of type string. 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...
641
642
			} elseif ( 'donation' === $goal_format ) {
643
				$this->goal = give_get_meta( $this->ID, '_give_number_of_donation_goal', true );
644
645
			} elseif ( 'donors' === $goal_format ) {
646
				$this->goal = give_get_meta( $this->ID, '_give_number_of_donor_goal', true );
647
648
			} elseif( in_array( $goal_format, array( 'amount', 'percentage' ) ) ) {
649
				$this->goal = give_get_meta( $this->ID, '_give_set_goal', true );
650
			}
651
		}
652
653
		return apply_filters( 'give_get_set_goal', $this->goal, $this->ID );
654
655
	}
656
657
	/**
658
	 * Determine if single price mode is enabled or disabled
659
	 *
660
	 * @since  1.0
661
	 * @access public
662
	 *
663
	 * @return bool
664
	 */
665 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...
666
667
		$option = give_get_meta( $this->ID, '_give_price_option', true );
668
		$ret    = 0;
669
670
		if ( empty( $option ) || $option === 'set' ) {
671
			$ret = 1;
672
		}
673
674
		/**
675
		 * Override the price mode for a donation when checking if is in single price mode.
676
		 *
677
		 * @since 1.0
678
		 *
679
		 * @param bool       $ret Is donation form in single price mode?
680
		 * @param int|string $ID  The ID of the donation form.
681
		 */
682
		return (bool) apply_filters( 'give_single_price_option_mode', $ret, $this->ID );
683
684
	}
685
686
	/**
687
	 * Determine if custom price mode is enabled or disabled
688
	 *
689
	 * @since  1.6
690
	 * @access public
691
	 *
692
	 * @return bool
693
	 */
694
	public function is_custom_price_mode() {
695
696
		$option = give_get_meta( $this->ID, '_give_custom_amount', true );
697
		$ret    = 0;
698
699
		if ( give_is_setting_enabled( $option ) ) {
700
			$ret = 1;
701
		}
702
703
		/**
704
		 * Override the price mode for a donation when checking if is in custom price mode.
705
		 *
706
		 * @since 1.6
707
		 *
708
		 * @param bool       $ret Is donation form in custom price mode?
709
		 * @param int|string $ID  The ID of the donation form.
710
		 */
711
		return (bool) apply_filters( 'give_custom_price_option_mode', $ret, $this->ID );
712
713
	}
714
715
	/**
716
	 * Determine if custom price mode is enabled or disabled
717
	 *
718
	 * @since  1.8.18
719
	 * @access public
720
	 *
721
	 * @param string|float $amount Donation Amount.
722
	 *
723
	 * @return bool
724
	 */
725
	public function is_custom_price( $amount ) {
726
		$result = false;
727
		$amount = give_maybe_sanitize_amount( $amount );
728
729
		if ( $this->is_custom_price_mode() ) {
730
731
			if ( 'set' === $this->get_type() ) {
732
				if ( $amount !== $this->get_price() ) {
733
					$result = true;
734
				}
735
736
			} elseif ( 'multi' === $this->get_type() ) {
737
				$level_amounts = array_map( 'give_maybe_sanitize_amount', wp_list_pluck( $this->get_prices(), '_give_amount' ) );
738
				$result        = ! in_array( $amount, $level_amounts );
739
			}
740
		}
741
742
		/**
743
		 * Filter to reset whether it is custom price or not.
744
		 *
745
		 * @param bool         $result True/False.
746
		 * @param string|float $amount Donation Amount.
747
		 * @param int          $this   ->ID Form ID.
748
		 *
749
		 * @since 1.8.18
750
		 */
751
		return (bool) apply_filters( 'give_is_custom_price', $result, $amount, $this->ID );
752
	}
753
754
	/**
755
	 * Has Variable Prices
756
	 *
757
	 * Determine if the donation form has variable prices enabled
758
	 *
759
	 * @since  1.0
760
	 * @access public
761
	 *
762
	 * @return bool
763
	 */
764 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...
765
766
		$option = give_get_meta( $this->ID, '_give_price_option', true );
767
		$ret    = 0;
768
769
		if ( $option === 'multi' ) {
770
			$ret = 1;
771
		}
772
773
		/**
774
		 * Filter: Override whether the donation form has variables prices.
775
		 *
776
		 * @param bool       $ret Does donation form have variable prices?
777
		 * @param int|string $ID  The ID of the donation form.
778
		 */
779
		return (bool) apply_filters( 'give_has_variable_prices', $ret, $this->ID );
780
781
	}
782
783
	/**
784
	 * Retrieve the donation form type, set or multi-level
785
	 *
786
	 * @since  1.5
787
	 * @access public
788
	 *
789
	 * @return string Type of donation form, either 'set' or 'multi'.
790
	 */
791 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...
792
793
		if ( ! isset( $this->type ) ) {
794
795
			$this->type = give_get_meta( $this->ID, '_give_price_option', true );
796
797
			if ( empty( $this->type ) ) {
798
				$this->type = 'set';
799
			}
800
801
		}
802
803
		return apply_filters( 'give_get_form_type', $this->type, $this->ID );
804
805
	}
806
807
	/**
808
	 * Get form tag classes.
809
	 *
810
	 * Provides the classes for the donation <form> html tag and filters for customization.
811
	 *
812
	 * @since  1.6
813
	 * @access public
814
	 *
815
	 * @param  $args
816
	 *
817
	 * @return string
818
	 */
819
	public function get_form_classes( $args ) {
820
821
		$float_labels_option = give_is_float_labels_enabled( $args )
822
			? 'float-labels-enabled'
823
			: '';
824
825
		$form_classes_array = apply_filters( 'give_form_classes', array(
826
			'give-form',
827
			'give-form-' . $this->ID,
828
			'give-form-type-' . $this->get_type(),
829
			$float_labels_option,
830
		), $this->ID, $args );
831
832
		// Remove empty class names.
833
		$form_classes_array = array_filter( $form_classes_array );
834
835
		return implode( ' ', $form_classes_array );
836
837
	}
838
839
	/**
840
	 * Get form wrap Classes.
841
	 *
842
	 * Provides the classes for the donation form div wrapper and filters for customization.
843
	 *
844
	 * @access public
845
	 *
846
	 * @param  $args
847
	 *
848
	 * @return string
849
	 */
850
	public function get_form_wrap_classes( $args ) {
851
		$custom_class = array(
852
			'give-form-wrap',
853
		);
854
855
		if ( $this->is_close_donation_form() ) {
856
			$custom_class[] = 'give-form-closed';
857
		} else {
858
			$display_option = ( isset( $args['display_style'] ) && ! empty( $args['display_style'] ) )
859
				? $args['display_style']
860
				: give_get_meta( $this->ID, '_give_payment_display', true );
861
862
			$custom_class[] = "give-display-{$display_option}";
863
864
			// If admin want to show only button for form then user inbuilt modal functionality.
865
			if ( 'button' === $display_option ) {
866
				$custom_class[] = 'give-display-button-only';
867
			}
868
		}
869
870
871
		/**
872
		 * Filter the donation form classes.
873
		 *
874
		 * @since 1.0
875
		 */
876
		$form_wrap_classes_array = (array) apply_filters( 'give_form_wrap_classes', $custom_class, $this->ID, $args );
877
878
879
		return implode( ' ', $form_wrap_classes_array );
880
881
	}
882
883
	/**
884
	 * Get if form type set or not.
885
	 *
886
	 * @since  1.6
887
	 * @access public
888
	 *
889
	 * @return bool
890
	 */
891
	public function is_set_type_donation_form() {
892
		$form_type = $this->get_type();
893
894
		return ( 'set' === $form_type ? true : false );
895
	}
896
897
	/**
898
	 * Get if form type multi or not.
899
	 *
900
	 * @since  1.6
901
	 * @access public
902
	 *
903
	 * @return bool True if form type is 'multi' and false otherwise.
904
	 */
905
	public function is_multi_type_donation_form() {
906
		$form_type = $this->get_type();
907
908
		return ( 'multi' === $form_type ? true : false );
909
910
	}
911
912
	/**
913
	 * Retrieve the sale count for the donation form
914
	 *
915
	 * @since  1.0
916
	 * @access public
917
	 *
918
	 * @return int    Donation form sale count.
919
	 */
920 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...
921
922
		if ( ! isset( $this->sales ) ) {
923
924
			if ( '' == give_get_meta( $this->ID, '_give_form_sales', true ) ) {
925
				add_post_meta( $this->ID, '_give_form_sales', 0 );
926
			} // End if
927
928
			$this->sales = give_get_meta( $this->ID, '_give_form_sales', true );
929
930
			if ( $this->sales < 0 ) {
931
				// Never let sales be less than zero.
932
				$this->sales = 0;
933
			}
934
935
		}
936
937
		return $this->sales;
938
939
	}
940
941
	/**
942
	 * Increment the sale count by one
943
	 *
944
	 * @since  1.0
945
	 * @access public
946
	 *
947
	 * @param  int $quantity The quantity to increase the donations by. Default is 1.
948
	 *
949
	 * @return int|false     New number of total sales.
950
	 */
951
	public function increase_sales( $quantity = 1 ) {
952
953
		$sales       = give_get_form_sales_stats( $this->ID );
954
		$quantity    = absint( $quantity );
955
		$total_sales = $sales + $quantity;
956
957
		if ( $this->update_meta( '_give_form_sales', $total_sales ) ) {
958
959
			$this->sales = $total_sales;
960
961
			return $this->sales;
962
963
		}
964
965
		return false;
966
	}
967
968
	/**
969
	 * Decrement the sale count by one
970
	 *
971
	 * @since  1.0
972
	 * @access public
973
	 *
974
	 * @param  int $quantity The quantity to decrease by. Default is 1.
975
	 *
976
	 * @return int|false     New number of total sales.
977
	 */
978
	public function decrease_sales( $quantity = 1 ) {
979
980
		$sales = give_get_form_sales_stats( $this->ID );
981
982
		// Only decrease if not already zero
983
		if ( $sales > 0 ) {
984
985
			$quantity    = absint( $quantity );
986
			$total_sales = $sales - $quantity;
987
988
			if ( $this->update_meta( '_give_form_sales', $total_sales ) ) {
989
990
				$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...
991
992
				return $sales;
993
994
			}
995
996
		}
997
998
		return false;
999
1000
	}
1001
1002
	/**
1003
	 * Retrieve the total earnings for the form
1004
	 *
1005
	 * @since  1.0
1006
	 * @access public
1007
	 *
1008
	 * @return float  Donation form total earnings.
1009
	 */
1010 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...
1011
1012
		if ( ! isset( $this->earnings ) ) {
1013
1014
			if ( '' == give_get_meta( $this->ID, '_give_form_earnings', true ) ) {
1015
				add_post_meta( $this->ID, '_give_form_earnings', 0 );
1016
			}
1017
1018
			$this->earnings = give_get_meta( $this->ID, '_give_form_earnings', true );
1019
1020
			if ( $this->earnings < 0 ) {
1021
				// Never let earnings be less than zero
1022
				$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...
1023
			}
1024
1025
		}
1026
1027
		return $this->earnings;
1028
1029
	}
1030
1031
	/**
1032
	 * Increase the earnings by the given amount
1033
	 *
1034
	 * @since  1.0
1035
	 * @since  2.1 Pass the donation ID.
1036
	 *
1037
	 * @access public
1038
	 *
1039
	 * @param  int $amount     Amount of donation. Default is 0.
1040
	 * @param int  $payment_id Donation ID.
1041
	 *
1042
	 * @return float|false
1043
	 */
1044 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...
1045
1046
		$earnings   = give_get_form_earnings_stats( $this->ID );
1047
1048
		/**
1049
		 * Modify the earning amount when increasing.
1050
		 *
1051
		 * @since 2.1
1052
		 *
1053
		 * @param float $amount     Earning amount.
1054
		 * @param int   $form_id    Donation form ID.
1055
		 * @param int   $payment_id Donation ID.
1056
		 */
1057
		$amount = apply_filters( 'give_increase_form_earnings_amount', $amount, $this->ID, $payment_id );
1058
1059
		$new_amount = $earnings + (float) $amount;
1060
1061
		if ( $this->update_meta( '_give_form_earnings', $new_amount ) ) {
1062
1063
			$this->earnings = $new_amount;
1064
1065
			return $this->earnings;
1066
1067
		}
1068
1069
		return false;
1070
1071
	}
1072
1073
	/**
1074
	 * Decrease the earnings by the given amount
1075
	 *
1076
	 * @since  1.0
1077
	 * @access public
1078
	 *
1079
	 * @param  int $amount     Amount of donation.
1080
	 * @param int  $payment_id Donation ID.
1081
	 *
1082
	 * @return float|false
1083
	 */
1084 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...
1085
1086
		$earnings = give_get_form_earnings_stats( $this->ID );
1087
1088
		if ( $earnings > 0 ) {
1089
1090
			/**
1091
			 * Modify the earning value when decreasing it.
1092
			 *
1093
			 * @since 2.1
1094
			 *
1095
			 * @param float $amount     Earning amount.
1096
			 * @param int   $form_id    Donation Form ID.
1097
			 * @param int   $payment_id Donation ID.
1098
			 */
1099
			$amount = apply_filters( 'give_decrease_form_earnings_amount', $amount, $this->ID, $payment_id );
1100
1101
			// Only decrease if greater than zero
1102
			$new_amount = $earnings - (float) $amount;
1103
1104
			if ( $this->update_meta( '_give_form_earnings', $new_amount ) ) {
1105
				$this->earnings = $new_amount;
1106
1107
				return $this->earnings;
1108
			}
1109
1110
		}
1111
1112
		return false;
1113
1114
	}
1115
1116
	/**
1117
	 * Determine if donation form closed or not
1118
	 *
1119
	 * Form will be close if:
1120
	 *  a. form has fixed goal
1121
	 *  b. close form when goal achieved cmb2 setting is set to 'Yes'
1122
	 *  c. goal has been achieved
1123
	 *
1124
	 * @since  1.4.5
1125
	 * @access public
1126
	 *
1127
	 * @return bool
1128
	 */
1129
	public function is_close_donation_form() {
1130
		$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...
1131
1132
		// If manual upgrade not completed, proceed with backward compatible code.
1133
		if ( ! give_has_upgrade_completed( 'v210_verify_form_status_upgrades' ) ) {
1134
1135
			// Check for backward compatibility.
1136
			$is_closed = $this->bc_210_is_close_donation_form();
1137
		}
1138
1139
		/**
1140
		 * Filter the close form result.
1141
		 *
1142
		 * @since 1.8
1143
		 */
1144
		return apply_filters(
1145
			'give_is_close_donation_form',
1146
			$is_closed,
1147
			$this
1148
		);
1149
1150
	}
1151
1152
1153
	/**
1154
	 * Check whether donation form has goal or not
1155
	 *
1156
	 * @since  2.4.2
1157
	 * @access public
1158
	 *
1159
	 * @return bool
1160
	 */
1161
	public function has_goal() {
1162
		return give_is_setting_enabled(
1163
			Give()->form_meta->get_meta(
1164
				$this->ID,
1165
				'_give_goal_option',
1166
				true
1167
			)
1168
		);
1169
	}
1170
1171
	/**
1172
	 * Updates a single meta entry for the donation form
1173
	 *
1174
	 * @since  1.5
1175
	 * @access private
1176
	 *
1177
	 * @param  string              $meta_key   The meta_key to update.
1178
	 * @param  string|array|object $meta_value The value to put into the meta.
1179
	 *
1180
	 * @return bool                            The result of the update query.
1181
	 */
1182
	private function update_meta( $meta_key = '', $meta_value = '' ) {
1183
1184
		/* @var WPDB $wpdb */
1185
		global $wpdb;
1186
1187
		// Bailout.
1188
		if ( empty( $meta_key ) ) {
1189
			return false;
1190
		}
1191
1192
		if ( give_update_meta( $this->ID, $meta_key, $meta_value ) ) {
1193
			return true;
1194
		}
1195
1196
		return false;
1197
	}
1198
1199
	/**
1200
	 * Backward Compatible function for is_close_donation_form()
1201
	 *
1202
	 * @since 2.1.0
1203
	 *
1204
	 * @return bool
1205
	 */
1206
	private function bc_210_is_close_donation_form() {
1207
1208
		$close_form      = false;
1209
		$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...
1210
1211
		// Proceed, if the form goal is enabled.
1212
		if ( $is_goal_enabled ) {
1213
1214
			$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...
1215
1216
			// Proceed, if close form when goal achieved option is enabled.
1217
			if ( $close_form_when_goal_achieved ) {
1218
1219
				$form        = new Give_Donate_Form( $this->ID );
1220
				$goal_format = give_get_form_goal_format( $this->ID );
1221
1222
				// Verify whether the form is closed or not after processing data based on goal format.
1223
				switch ( $goal_format ) {
1224
					case 'donation':
1225
						$closed = $form->get_goal() <= $form->get_sales();
1226
						break;
1227
					case 'donors':
1228
						$closed = $form->get_goal() <= give_get_form_donor_count( $this->ID );
1229
						break;
1230
					default :
1231
						$closed = $form->get_goal() <= $form->get_earnings();
1232
						break;
1233
				}
1234
1235
				if ( $closed ) {
1236
					$close_form = true;
1237
				}
1238
1239
			}
1240
		}
1241
1242
		return $close_form;
1243
	}
1244
1245
}
1246