Completed
Push — master ( e61df4...0e8d0d )
by Devin
46:45 queued 26:49
created

functions.php ➔ give_send_back_to_checkout()   C

Complexity

Conditions 7
Paths 32

Size

Total Lines 51
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
cc 7
eloc 26
nc 32
nop 1
dl 0
loc 51
ccs 0
cts 16
cp 0
crap 56
rs 6.9743
c 0
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 22 and the first side effect is on line 14.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Give Form Functions
4
 *
5
 * @package     WordImpress
6
 * @subpackage  Includes/Forms
7
 * @copyright   Copyright (c) 2016, WordImpress
8
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
9
 * @since       1.1
10
 */
11
12
// Exit if accessed directly
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Filter: Do not show the Give shortcut button on Give Forms CPT
19
 *
20
 * @return bool
21
 */
22
function give_shortcode_button_condition() {
23
24
	global $typenow;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
25
26
	if ( $typenow != 'give_forms' ) {
27
		return true;
28
	}
29
30
	return false;
31
}
32
33
add_filter( 'give_shortcode_button_condition', 'give_shortcode_button_condition' );
34
35
36
/**
37
 * Get the form ID from the form $args
38
 *
39
 * @param array $args
40
 *
41
 * @return int|false
42
 */
43
function get_form_id_from_args( $args ) {
44
45
	if ( isset( $args['form_id'] ) && $args['form_id'] != 0 ) {
46
47
		return intval( $args['form_id'] );
48
	}
49
50
	return false;
51
}
52
53
/**
54
 * Checks whether floating labels is enabled for the form ID in $args
55
 *
56
 * @since 1.1
57
 *
58
 * @param array $args
59
 *
60
 * @return bool
61
 */
62
function give_is_float_labels_enabled( $args ) {
63
64 1
	$float_labels = '';
65
66 1
	if ( ! empty( $args['float_labels'] ) ) {
67
		$float_labels = $args['float_labels'];
68
	}
69
70 1
	if ( empty( $float_labels ) ) {
71 1
		$float_labels = get_post_meta( $args['form_id'], '_give_form_floating_labels', true );
72 1
	}
73
74 1
	if ( empty( $float_labels ) ) {
75 1
		$float_labels = give_get_option( 'enable_floatlabels' ) ? 'enabled' : 'disabled';
76 1
	}
77
78 1
	return ( $float_labels == 'enabled' ) ? true : false;
79
}
80
81
/**
82
 * Determines if a user can checkout or not
83
 *
84
 * Allows themes and plugins to set donation checkout conditions
85
 *
86
 * @since 1.0
87
 * @global array $give_options Array of all the Give Options
88
 * @return bool Can user checkout?
89
 */
90
function give_can_checkout() {
91 1
92
	$can_checkout = true;
93 1
94
	return (bool) apply_filters( 'give_can_checkout', $can_checkout );
95
}
96
97
/**
98
 * Retrieve the Success page URI
99
 *
100
 * @access      public
101
 * @since       1.0
102
 * @global array $give_options Array of all the Give Options
103
 * @return      string
104
 */
105
function give_get_success_page_uri() {
106
	global $give_options;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
107
108
	$success_page = isset( $give_options['success_page'] ) ? get_permalink( absint( $give_options['success_page'] ) ) : get_bloginfo( 'url' );
109
110
	return apply_filters( 'give_get_success_page_uri', $success_page );
111
}
112
113
/**
114
 * Determines if we're currently on the Success page.
115
 *
116
 * @since 1.0
117
 * @global array $give_options Array of all the Give Options
118
 * @return bool True if on the Success page, false otherwise.
119
 */
120
function give_is_success_page() {
121
	global $give_options;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
122
	$is_success_page = isset( $give_options['success_page'] ) ? is_page( $give_options['success_page'] ) : false;
123
124
	return apply_filters( 'give_is_success_page', $is_success_page );
125
}
126
127
/**
128
 * Send To Success Page
129
 *
130
 * Sends the user to the success page.
131
 *
132
 * @param string $query_string
133
 *
134
 * @access      public
135
 * @since       1.0
136
 * @return      void
137
 */
138
function give_send_to_success_page( $query_string = null ) {
139
140
	$redirect = give_get_success_page_uri();
141
142
	if ( $query_string ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $query_string of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
143
		$redirect .= $query_string;
144
	}
145
146
	$gateway = isset( $_REQUEST['give-gateway'] ) ? $_REQUEST['give-gateway'] : '';
147
148
	wp_redirect( apply_filters( 'give_success_page_redirect', $redirect, $gateway, $query_string ) );
149
	give_die();
150
}
151
152
153
/**
154
 * Send back to checkout.
155
 *
156
 * Used to redirect a user back to the purchase
157
 * page if there are errors present.
158
 *
159
 * @param array $args
160
 *
161
 * @access public
162
 * @since  1.0
163
 * @return Void
164
 */
165
function give_send_back_to_checkout( $args = array() ) {
166
167
	$url = isset( $_POST['give-current-url'] ) ? sanitize_text_field( $_POST['give-current-url'] ) : '';
168
169
	if ( empty( $url ) ) {
170
		wp_safe_redirect( home_url() );
171
		give_die();
172
	}
173
174
	if ( isset( $_POST['give-form-id'] ) ) {
175
		$form_id = sanitize_text_field( $_POST['give-form-id'] );
176
	} else {
177
		$form_id = 0;
178
	}
179
180
	$defaults = array(
181
		'form-id' => (int) $form_id
182
	);
183
184
	// Check for backward compatibility.
185
	if ( is_string( $args ) ) {
186
		$args = str_replace( '?', '', $args );
187
	}
188
189
	$args = wp_parse_args( $args, $defaults );
190
191
	// Merge URL query with $args to maintain third-party URL parameters after redirect.
192
	$url_data = wp_parse_url( $url );
193
194
	//Check if an array to prevent notices before parsing.
195
	if ( isset( $url_data['query'] ) && ! empty( $url_data['query'] ) ) {
196
		parse_str( $url_data['query'], $query );
197
198
		//Precaution: don't allow any CC info.
199
		unset($query['card_number']);
200
		unset($query['card_cvc']);
201
202
	} else {
203
		//No $url_data so pass empty array.
204
		$query = array();
205
	}
206
207
	$new_query        = array_merge( $args, $query );
208
	$new_query_string = http_build_query( $new_query );
209
210
	// Assemble URL parts.
211
	$redirect = home_url( '/' . $url_data['path'] . '?' . $new_query_string . '#give-form-' . $form_id . '-wrap' );
212
213
	wp_safe_redirect( apply_filters( 'give_send_back_to_checkout', $redirect, $args ) );
214
	give_die();
215
}
216
217
/**
218
 * Get Success Page URL
219
 *
220
 * Gets the success page URL.
221
 *
222
 * @param string $query_string
223
 *
224
 * @access      public
225
 * @since       1.0
226
 * @return      string
227
 */
228
function give_get_success_page_url( $query_string = null ) {
229
230
	$success_page = give_get_option( 'success_page', 0 );
231
	$success_page = get_permalink( $success_page );
232
233
	if ( $query_string ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $query_string of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
234
		$success_page .= $query_string;
235
	}
236
237
	return apply_filters( 'give_success_page_url', $success_page );
238
239
}
240
241
/**
242
 * Get the URL of the Transaction Failed page
243
 *
244
 * @since 1.0
245
 * @global     $give_options Array of all the Give Options
246
 *
247
 * @param bool $extras       Extras to append to the URL
248
 *
249
 * @return mixed|void Full URL to the Transaction Failed page, if present, home page if it doesn't exist
250
 */
251
function give_get_failed_transaction_uri( $extras = false ) {
252
	global $give_options;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
253
254
	$uri = ! empty( $give_options['failure_page'] ) ? trailingslashit( get_permalink( $give_options['failure_page'] ) ) : home_url();
255
	if ( $extras ) {
256
		$uri .= $extras;
257
	}
258
259
	return apply_filters( 'give_get_failed_transaction_uri', $uri );
260
}
261
262
/**
263
 * Determines if we're currently on the Failed Transaction page.
264
 *
265
 * @since 1.0
266
 * @return bool True if on the Failed Transaction page, false otherwise.
267
 */
268
function give_is_failed_transaction_page() {
269
	global $give_options;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
270
	$ret = isset( $give_options['failure_page'] ) ? is_page( $give_options['failure_page'] ) : false;
271
272
	return apply_filters( 'give_is_failure_page', $ret );
273
}
274
275
/**
276
 * Mark payments as Failed when returning to the Failed Transaction page
277
 *
278
 * @access      public
279
 * @since       1.0
280
 * @return      void
281
 */
282
function give_listen_for_failed_payments() {
283
284
	$failed_page = give_get_option( 'failure_page', 0 );
285
286
	if ( ! empty( $failed_page ) && is_page( $failed_page ) && ! empty( $_GET['payment-id'] ) ) {
287
288
		$payment_id = absint( $_GET['payment-id'] );
289
		give_update_payment_status( $payment_id, 'failed' );
290
291
	}
292
293
}
294
295
add_action( 'template_redirect', 'give_listen_for_failed_payments' );
296
297
298 42
/**
299
 * Check if a field is required
300
 *
301 42
 * @param string $field
302 42
 * @param int    $form_id
303 42
 *
304 42
 * @access      public
305 42
 * @since       1.0
306
 * @return      bool
307
 */
308 42
function give_field_is_required( $field = '', $form_id ) {
309
310 42
	$required_fields = give_purchase_form_required_fields( $form_id );
311
312 42
	return array_key_exists( $field, $required_fields );
313 42
}
314
315
/**
316
 * Record Sale In Log
317
 *
318
 * Stores log information for a form sale.
319
 *
320
 * @since 1.0
321
 * @global            $give_logs
322
 *
323
 * @param int         $give_form_id Give Form ID
324
 * @param int         $payment_id   Payment ID
325
 * @param bool|int    $price_id     Price ID, if any
326
 * @param string|null $sale_date    The date of the sale
327 42
 *
328 42
 * @return void
329
 */
330 42
function give_record_sale_in_log( $give_form_id = 0, $payment_id, $price_id = false, $sale_date = null ) {
331
	global $give_logs;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
332
333
	$log_data = array(
334
		'post_parent'   => $give_form_id,
335
		'log_type'      => 'sale',
336
		'post_date'     => isset( $sale_date ) ? $sale_date : null,
337
		'post_date_gmt' => isset( $sale_date ) ? $sale_date : null
338
	);
339
340
	$log_meta = array(
341
		'payment_id' => $payment_id,
342
		'price_id'   => (int) $price_id
343
	);
344 18
345 18
	$give_logs->insert_log( $log_data, $log_meta );
346
}
347 18
348
349
/**
350
 * Increases the donation total count of a donation form.
351
 *
352
 * @since 1.0
353
 *
354
 * @param int $form_id  Give Form ID
355
 * @param int $quantity Quantity to increase purchase count by
356
 *
357
 * @return bool|int
358
 */
359
function give_increase_purchase_count( $form_id = 0, $quantity = 1 ) {
360
	$quantity = (int) $quantity;
361 42
	$form     = new Give_Donate_Form( $form_id );
362
363 42
	return $form->increase_sales( $quantity );
364
}
365
366
/**
367
 * Decreases the sale count of a form. Primarily for when a donation is refunded.
368
 *
369
 * @since 1.0
370
 *
371
 * @param int $form_id  Give Form ID
372
 * @param int $quantity Quantity to increase purchase count by
373
 *
374
 * @return bool|int
375
 */
376
function give_decrease_purchase_count( $form_id = 0, $quantity = 1 ) {
377 18
	$quantity = (int) $quantity;
378
	$form     = new Give_Donate_Form( $form_id );
379 18
380
	return $form->decrease_sales( $quantity );
381
}
382
383
/**
384
 * Increases the total earnings of a form.
385
 *
386
 * @since 1.0
387
 *
388
 * @param int $give_form_id Give Form ID
389
 * @param int $amount       Earnings
390
 *
391
 * @return bool|int
392
 */
393 42
function give_increase_earnings( $give_form_id = 0, $amount ) {
394
	$form = new Give_Donate_Form( $give_form_id );
395 42
396
	return $form->increase_earnings( $amount );
397
}
398
399
/**
400
 * Decreases the total earnings of a form. Primarily for when a purchase is refunded.
401
 *
402
 * @since 1.0
403
 *
404
 * @param int $form_id Give Form ID
405
 * @param int $amount  Earnings
406
 *
407
 * @return bool|int
408
 */
409 42
function give_decrease_earnings( $form_id = 0, $amount ) {
410
	$form = new Give_Donate_Form( $form_id );
411 42
412
	return $form->decrease_earnings( $amount );
413
}
414
415
416
/**
417
 * Returns the total earnings for a form.
418
 *
419
 * @since 1.0
420
 *
421
 * @param int $form_id Give Form ID
422
 *
423
 * @return int $earnings Earnings for a certain form
424
 */
425 11
function give_get_form_earnings_stats( $form_id = 0 ) {
426 11
	$give_form = new Give_Donate_Form( $form_id );
427
428 11
	return $give_form->earnings;
0 ignored issues
show
Documentation introduced by
The property $earnings is declared private in Give_Donate_Form. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
429
}
430 11
431
432 11
/**
433
 * Return the sales number for a form.
434
 *
435
 * @since 1.0
436 11
 *
437
 * @param int $give_form_id Give Form ID
438
 *
439
 * @return int $sales Amount of sales for a certain form
440
 */
441
function give_get_form_sales_stats( $give_form_id = 0 ) {
442
	$give_form = new Give_Donate_Form( $give_form_id );
443
444
	return $give_form->sales;
0 ignored issues
show
Documentation introduced by
The property $sales is declared private in Give_Donate_Form. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
445
}
446
447
448
/**
449
 * Retrieves the average monthly sales for a specific donation form
450 11
 *
451 11
 * @since 1.0
452
 *
453 11
 * @param int $form_id Form ID
454
 *
455 11
 * @return float $sales Average monthly sales
456
 */
457 11
function give_get_average_monthly_form_sales( $form_id = 0 ) {
458
	$sales        = give_get_form_sales_stats( $form_id );
459
	$release_date = get_post_field( 'post_date', $form_id );
460
461 11
	$diff = abs( current_time( 'timestamp' ) - strtotime( $release_date ) );
462
463
	$months = floor( $diff / ( 30 * 60 * 60 * 24 ) ); // Number of months since publication
464
465
	if ( $months > 0 ) {
466
		$sales = ( $sales / $months );
467
	}
468
469
	return $sales;
470
}
471
472
473
/**
474
 * Retrieves the average monthly earnings for a specific form
475
 *
476
 * @since 1.0
477
 *
478
 * @param int $form_id Form ID
479
 *
480 34
 * @return float $earnings Average monthly earnings
481 34
 */
482
function give_get_average_monthly_form_earnings( $form_id = 0 ) {
483 34
	$earnings     = give_get_form_earnings_stats( $form_id );
484
	$release_date = get_post_field( 'post_date', $form_id );
485 34
486
	$diff = abs( current_time( 'timestamp' ) - strtotime( $release_date ) );
487 34
488 34
	$months = floor( $diff / ( 30 * 60 * 60 * 24 ) ); // Number of months since publication
489 34
490
	if ( $months > 0 ) {
491 34
		$earnings = ( $earnings / $months );
492
	}
493 34
494
	return $earnings < 0 ? 0 : $earnings;
495
}
496 34
497
498
/**
499
 * Get Price Option Name (Text)
500
 *
501
 * Retrieves the name of a variable price option
502
 *
503
 * @since       1.0
504
 *
505
 * @param int $form_id    ID of the download
506
 * @param int $price_id   ID of the price option
507
 * @param int $payment_id payment ID for use in filters ( optional )
508
 *
509
 * @return string $price_name Name of the price option
510
 */
511
function give_get_price_option_name( $form_id = 0, $price_id = 0, $payment_id = 0 ) {
512
513
	$prices     = give_get_variable_prices( $form_id );
514
	$price_name = '';
515
516
	foreach ( $prices as $price ) {
0 ignored issues
show
Bug introduced by
The expression $prices of type false|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
517
518
		if ( intval( $price['_give_id']['level_id'] ) == intval( $price_id ) ) {
519
520
			$price_text     = isset( $price['_give_text'] ) ? $price['_give_text'] : '';
521
			$price_fallback = give_currency_filter( give_format_amount( $price['_give_amount'] ) );
522
			$price_name     = ! empty( $price_text ) ? $price_text : $price_fallback;
523
524
		}
525
526
	}
527
528
529
	return apply_filters( 'give_get_price_option_name', $price_name, $form_id, $payment_id, $price_id );
530
}
531
532
533
/**
534
 * Retrieves a price from from low to high of a variable priced form
535
 *
536
 * @since 1.0
537
 *
538
 * @param int $form_id ID of the form
539
 *
540
 * @return string $range A fully formatted price range
541
 */
542
function give_price_range( $form_id = 0 ) {
543
	$low   = give_get_lowest_price_option( $form_id );
544
	$high  = give_get_highest_price_option( $form_id );
545
	$range = '<span class="give_price_range_low">' . give_currency_filter( give_format_amount( $low ) ) . '</span>';
546
	$range .= '<span class="give_price_range_sep">&nbsp;&ndash;&nbsp;</span>';
547
	$range .= '<span class="give_price_range_high">' . give_currency_filter( give_format_amount( $high ) ) . '</span>';
548
549
	return apply_filters( 'give_price_range', $range, $form_id, $low, $high );
550
}
551
552
553
/**
554
 * Get Lowest Price ID
555
 *
556
 * Retrieves the ID for the cheapest price option of a variable donation form
557
 *
558
 * @since 1.5
559
 *
560
 * @param int $form_id ID of the donation
561
 *
562
 * @return int ID of the lowest price
563
 */
564
function give_get_lowest_price_id( $form_id = 0 ) {
565
566
	if ( empty( $form_id ) ) {
567
		$form_id = get_the_ID();
568
	}
569
570
	if ( ! give_has_variable_prices( $form_id ) ) {
571
		return give_get_form_price( $form_id );
572
	}
573
574
	$prices = give_get_variable_prices( $form_id );
575
576
	$low    = 0.00;
577
	$min_id = 1;
578
579
	if ( ! empty( $prices ) ) {
580
581
		foreach ( $prices as $key => $price ) {
582
583
			if ( empty( $price['_give_amount'] ) ) {
584
				continue;
585
			}
586
587
			if ( ! isset( $min ) ) {
588
				$min = $price['_give_amount'];
589
			} else {
590
				$min = min( $min, $price['_give_amount'] );
591
			}
592
593
			if ( $price['_give_amount'] == $min ) {
594
				$min_id = $price['_give_id']['level_id'];
595
			}
596
		}
597
	}
598
599
	return (int) $min_id;
600
}
601
602
/**
603
 * Retrieves cheapest price option of a variable priced form
604
 *
605
 * @since 1.0
606
 *
607
 * @param int $form_id ID of the form
608
 *
609
 * @return float Amount of the lowest price
610
 */
611
function give_get_lowest_price_option( $form_id = 0 ) {
612
	if ( empty( $form_id ) ) {
613
		$form_id = get_the_ID();
614
	}
615
616
	if ( ! give_has_variable_prices( $form_id ) ) {
617
		return give_get_form_price( $form_id );
618
	}
619
620
	$prices = give_get_variable_prices( $form_id );
621
622
	$low = 0.00;
623
624
	if ( ! empty( $prices ) ) {
625
626
		foreach ( $prices as $key => $price ) {
627
628
			if ( empty( $price['_give_amount'] ) ) {
629
				continue;
630
			}
631
632
			if ( ! isset( $min ) ) {
633
				$min = $price['_give_amount'];
634
			} else {
635
				$min = min( $min, give_sanitize_amount( $price['_give_amount'] ) );
636
			}
637
638
			if ( $price['_give_amount'] == $min ) {
639
				$min_id = $key;
640
			}
641
		}
642
643
		$low = $prices[ $min_id ]['_give_amount'];
0 ignored issues
show
Bug introduced by
The variable $min_id does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
644
645
	}
646
647
	return give_sanitize_amount( $low );
648
}
649
650
/**
651
 * Retrieves most expensive price option of a variable priced form
652
 *
653
 * @since 1.0
654
 *
655
 * @param int $form_id ID of the form
656
 *
657
 * @return float Amount of the highest price
658
 */
659
function give_get_highest_price_option( $form_id = 0 ) {
660
661
	if ( empty( $form_id ) ) {
662
		$form_id = get_the_ID();
663
	}
664
665
	if ( ! give_has_variable_prices( $form_id ) ) {
666
		return give_get_form_price( $form_id );
667
	}
668
669
	$prices = give_get_variable_prices( $form_id );
670
671
	$high = 0.00;
672
673
	if ( ! empty( $prices ) ) {
674 12
675
		$max = 0;
676
677
		foreach ( $prices as $key => $price ) {
678 12
			if ( empty( $price['_give_amount'] ) ) {
679
				continue;
680 12
			}
681
			$give_amount = give_sanitize_amount( $price['_give_amount'] );
682
683
			$max = max( $max, $give_amount );
684
685
			if ( $give_amount == $max ) {
686
				$max_id = $key;
687
			}
688
		}
689
690
		$high = $prices[ $max_id ]['_give_amount'];
0 ignored issues
show
Bug introduced by
The variable $max_id does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
691
	}
692
693
	return give_sanitize_amount( $high );
694 1
}
695
696
/**
697
 * Returns the price of a form, but only for non-variable priced forms.
698 1
 *
699
 * @since 1.0
700 1
 *
701
 * @param int $form_id ID number of the form to retrieve a price for
702
 *
703
 * @return mixed string|int Price of the form
704
 */
705
function give_get_form_price( $form_id = 0 ) {
706
707
	if ( empty( $form_id ) ) {
708
		return false;
709
	}
710
711
	$form = new Give_Donate_Form( $form_id );
712
713
	return $form->__get( 'price' );
714
}
715
716
/**
717
 * Returns the minimum price amount of a form, only enforced for the custom amount input.
718
 *
719
 * @since 1.3.6
720
 *
721
 * @param int $form_id ID number of the form to retrieve the minimum price for
722
 *
723
 * @return mixed string|int Minimum price of the form
724
 */
725
function give_get_form_minimum_price( $form_id = 0 ) {
726
727
	if ( empty( $form_id ) ) {
728
		return false;
729
	}
730
731
	$form = new Give_Donate_Form( $form_id );
732
733
	return $form->__get( 'minimum_price' );
734
735
}
736
737
/**
738
 * Displays a formatted price for a donation form
739
 *
740
 * @since 1.0
741
 *
742
 * @param int      $form_id  ID of the form price to show
743
 * @param bool     $echo     Whether to echo or return the results
744
 * @param bool|int $price_id Optional price id for variable pricing
745
 *
746
 * @return int $formatted_price
747
 */
748
function give_price( $form_id = 0, $echo = true, $price_id = false ) {
749
750
	if ( empty( $form_id ) ) {
751
		$form_id = get_the_ID();
752
	}
753
754
	if ( give_has_variable_prices( $form_id ) ) {
755
756
		$prices = give_get_variable_prices( $form_id );
757
758
		if ( false !== $price_id ) {
759
760
			//loop through multi-prices to see which is default
761
			foreach ( $prices as $price ) {
0 ignored issues
show
Bug introduced by
The expression $prices of type false|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
762
				//this is the default price
763
				if ( isset( $price['_give_default'] ) && $price['_give_default'] === 'default' ) {
764
					$price = (float) $price['_give_amount'];
765
				};
766
			}
767
768
		} else {
769
770
			$price = give_get_lowest_price_option( $form_id );
771
		}
772
773
		$price = give_sanitize_amount( $price );
0 ignored issues
show
Bug introduced by
The variable $price does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
774
775 11
	} else {
776
777 11
		$price = give_get_form_price( $form_id );
778
779 11
	}
780 11
781 11
	$price           = apply_filters( 'give_form_price', give_sanitize_amount( $price ), $form_id );
782 11
	$formatted_price = '<span class="give_price" id="give_price_' . $form_id . '">' . $price . '</span>';
783 11
	$formatted_price = apply_filters( 'give_form_price_after_html', $formatted_price, $form_id, $price );
784
785 11
	if ( $echo ) {
786
		echo $formatted_price;
787
	} else {
788
		return $formatted_price;
789
	}
790
}
791
792
add_filter( 'give_form_price', 'give_format_amount', 10 );
793
add_filter( 'give_form_price', 'give_currency_filter', 20 );
794
795
796
/**
797
 * Retrieves the amount of a variable price option
798
 *
799
 * @since 1.0
800
 *
801
 * @param int $form_id  ID of the form
802
 * @param int $price_id ID of the price option
803
 *
804
 * @return float $amount Amount of the price option
805
 */
806
function give_get_price_option_amount( $form_id = 0, $price_id = 0 ) {
807
	$prices = give_get_variable_prices( $form_id );
808
809
	$amount = 0.00;
810
811
	foreach ( $prices as $price ) {
0 ignored issues
show
Bug introduced by
The expression $prices of type false|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
812
		if ( isset( $price['_give_id']['level_id'] ) && $price['_give_id']['level_id'] == $price_id ) {
813
			$amount = isset( $price['_give_amount'] ) ? $price['_give_amount'] : 0.00;
814
			break;
815
		};
816
	}
817
818
	return apply_filters( 'give_get_price_option_amount', give_sanitize_amount( $amount ), $form_id, $price_id );
819
}
820
821
/**
822
 * Returns the goal of a form
823
 *
824
 * @since 1.0
825
 *
826
 * @param int $form_id ID number of the form to retrieve a goal for
827
 *
828
 * @return mixed string|int Goal of the form
829
 */
830
function give_get_form_goal( $form_id = 0 ) {
831
832
	if ( empty( $form_id ) ) {
833
		return false;
834
	}
835
836
	$form = new Give_Donate_Form( $form_id );
837
838
	return $form->goal;
0 ignored issues
show
Documentation introduced by
The property $goal is declared private in Give_Donate_Form. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
839
840
}
841
842
/**
843
 * Display/Return a formatted goal for a donation form
844
 *
845
 * @since 1.0
846
 *
847
 * @param int  $form_id ID of the form price to show
848
 * @param bool $echo    Whether to echo or return the results
849
 *
850
 * @return string $formatted_goal
851 1
 */
852
function give_goal( $form_id = 0, $echo = true ) {
853 1
854
	if ( empty( $form_id ) ) {
855 1
		$form_id = get_the_ID();
856
	}
857
858
	$goal = give_get_form_goal( $form_id );
859
860
	$goal           = apply_filters( 'give_form_goal', give_sanitize_amount( $goal ), $form_id );
861
	$formatted_goal = '<span class="give_price" id="give_price_' . $form_id . '">' . $goal . '</span>';
862
	$formatted_goal = apply_filters( 'give_form_price_after_html', $formatted_goal, $form_id, $goal );
863
864
	if ( $echo ) {
865
		echo $formatted_goal;
866
	} else {
867
		return $formatted_goal;
868
	}
869 1
}
870
871 1
add_filter( 'give_form_goal', 'give_format_amount', 10 );
872
add_filter( 'give_form_goal', 'give_currency_filter', 20 );
873
874
875
/**
876
 * Checks if users can only donate when logged in
877
 *
878
 * @since  1.0
879
 *
880
 * @global array $give_options
881
 *
882
 * @param  int   $form_id Give form ID
883
 *
884
 * @return bool  $ret Whether or not the logged_in_only setting is set
885
 */
886
function give_logged_in_only( $form_id ) {
887
888
	$form_option = get_post_meta( $form_id, '_give_logged_in_only', true );
889
890
	$ret = ! empty( $form_option ) ? $form_option : false;
891
892
	return (bool) apply_filters( 'give_logged_in_only', $ret, $form_id );
893
894
}
895
896
897
/**
898
 * Checks the option for the "Register / Login Option"
899
 *
900
 * @since 1.4.1
901
 *
902
 * @param int $form_id
903
 *
904
 * @return string
905
 */
906
function give_show_login_register_option( $form_id ) {
907
908
	$show_register_form = get_post_meta( $form_id, '_give_show_register_form', true );
909
910
	return apply_filters( 'give_show_register_form', $show_register_form, $form_id );
911
912
}