Completed
Push — master ( 0e8d0d...009de2 )
by Devin
65:10 queued 45:08
created

functions.php ➔ give_send_back_to_checkout()   B

Complexity

Conditions 7
Paths 32

Size

Total Lines 55
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 55
ccs 0
cts 17
cp 0
crap 56
rs 7.8235
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
	//Set the form_id.
170
	if ( isset( $_POST['give-form-id'] ) ) {
171
		$form_id = sanitize_text_field( $_POST['give-form-id'] );
172
	} else {
173
		$form_id = 0;
174
	}
175
176
	//Need a URL to continue. If none, redirect back to single form.
177
	if ( empty( $url ) ) {
178
		wp_safe_redirect( get_permalink( $form_id ) );
179
		give_die();
180
	}
181
182
	$defaults = array(
183
		'form-id' => (int) $form_id
184
	);
185
186
	// Check for backward compatibility.
187
	if ( is_string( $args ) ) {
188
		$args = str_replace( '?', '', $args );
189
	}
190
191
	$args = wp_parse_args( $args, $defaults );
192
193
	// Merge URL query with $args to maintain third-party URL parameters after redirect.
194
	$url_data = wp_parse_url( $url );
195
196
	//Check if an array to prevent notices before parsing.
197
	if ( isset( $url_data['query'] ) && ! empty( $url_data['query'] ) ) {
198
		parse_str( $url_data['query'], $query );
199
200
		//Precaution: don't allow any CC info.
201
		unset( $query['card_number'] );
202
		unset( $query['card_cvc'] );
203
204
	} else {
205
		//No $url_data so pass empty array.
206
		$query = array();
207
	}
208
209
	$new_query        = array_merge( $args, $query );
210
	$new_query_string = http_build_query( $new_query );
211
212
	// Assemble URL parts.
213
	$redirect = home_url( '/' . $url_data['path'] . '?' . $new_query_string . '#give-form-' . $form_id . '-wrap' );
214
215
	//Redirect them.
216
	wp_safe_redirect( apply_filters( 'give_send_back_to_checkout', $redirect, $args ) );
217
	give_die();
218
	
219
}
220
221
/**
222
 * Get Success Page URL
223
 *
224
 * Gets the success page URL.
225
 *
226
 * @param string $query_string
227
 *
228
 * @access      public
229
 * @since       1.0
230
 * @return      string
231
 */
232
function give_get_success_page_url( $query_string = null ) {
233
234
	$success_page = give_get_option( 'success_page', 0 );
235
	$success_page = get_permalink( $success_page );
236
237
	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...
238
		$success_page .= $query_string;
239
	}
240
241
	return apply_filters( 'give_success_page_url', $success_page );
242
243
}
244
245
/**
246
 * Get the URL of the Transaction Failed page
247
 *
248
 * @since 1.0
249
 * @global     $give_options Array of all the Give Options
250
 *
251
 * @param bool $extras       Extras to append to the URL
252
 *
253
 * @return mixed|void Full URL to the Transaction Failed page, if present, home page if it doesn't exist
254
 */
255
function give_get_failed_transaction_uri( $extras = false ) {
256
	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...
257
258
	$uri = ! empty( $give_options['failure_page'] ) ? trailingslashit( get_permalink( $give_options['failure_page'] ) ) : home_url();
259
	if ( $extras ) {
260
		$uri .= $extras;
261
	}
262
263
	return apply_filters( 'give_get_failed_transaction_uri', $uri );
264
}
265
266
/**
267
 * Determines if we're currently on the Failed Transaction page.
268
 *
269
 * @since 1.0
270
 * @return bool True if on the Failed Transaction page, false otherwise.
271
 */
272
function give_is_failed_transaction_page() {
273
	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...
274
	$ret = isset( $give_options['failure_page'] ) ? is_page( $give_options['failure_page'] ) : false;
275
276
	return apply_filters( 'give_is_failure_page', $ret );
277
}
278
279
/**
280
 * Mark payments as Failed when returning to the Failed Transaction page
281
 *
282
 * @access      public
283
 * @since       1.0
284
 * @return      void
285
 */
286
function give_listen_for_failed_payments() {
287
288
	$failed_page = give_get_option( 'failure_page', 0 );
289
290
	if ( ! empty( $failed_page ) && is_page( $failed_page ) && ! empty( $_GET['payment-id'] ) ) {
291
292
		$payment_id = absint( $_GET['payment-id'] );
293
		give_update_payment_status( $payment_id, 'failed' );
294
295
	}
296
297
}
298 42
299
add_action( 'template_redirect', 'give_listen_for_failed_payments' );
300
301 42
302 42
/**
303 42
 * Check if a field is required
304 42
 *
305 42
 * @param string $field
306
 * @param int    $form_id
307
 *
308 42
 * @access      public
309
 * @since       1.0
310 42
 * @return      bool
311
 */
312 42
function give_field_is_required( $field = '', $form_id ) {
313 42
314
	$required_fields = give_purchase_form_required_fields( $form_id );
315
316
	return array_key_exists( $field, $required_fields );
317
}
318
319
/**
320
 * Record Sale In Log
321
 *
322
 * Stores log information for a form sale.
323
 *
324
 * @since 1.0
325
 * @global            $give_logs
326
 *
327 42
 * @param int         $give_form_id Give Form ID
328 42
 * @param int         $payment_id   Payment ID
329
 * @param bool|int    $price_id     Price ID, if any
330 42
 * @param string|null $sale_date    The date of the sale
331
 *
332
 * @return void
333
 */
334
function give_record_sale_in_log( $give_form_id = 0, $payment_id, $price_id = false, $sale_date = null ) {
335
	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...
336
337
	$log_data = array(
338
		'post_parent'   => $give_form_id,
339
		'log_type'      => 'sale',
340
		'post_date'     => isset( $sale_date ) ? $sale_date : null,
341
		'post_date_gmt' => isset( $sale_date ) ? $sale_date : null
342
	);
343
344 18
	$log_meta = array(
345 18
		'payment_id' => $payment_id,
346
		'price_id'   => (int) $price_id
347 18
	);
348
349
	$give_logs->insert_log( $log_data, $log_meta );
350
}
351
352
353
/**
354
 * Increases the donation total count of a donation form.
355
 *
356
 * @since 1.0
357
 *
358
 * @param int $form_id  Give Form ID
359
 * @param int $quantity Quantity to increase purchase count by
360
 *
361 42
 * @return bool|int
362
 */
363 42
function give_increase_purchase_count( $form_id = 0, $quantity = 1 ) {
364
	$quantity = (int) $quantity;
365
	$form     = new Give_Donate_Form( $form_id );
366
367
	return $form->increase_sales( $quantity );
368
}
369
370
/**
371
 * Decreases the sale count of a form. Primarily for when a donation is refunded.
372
 *
373
 * @since 1.0
374
 *
375
 * @param int $form_id  Give Form ID
376
 * @param int $quantity Quantity to increase purchase count by
377 18
 *
378
 * @return bool|int
379 18
 */
380
function give_decrease_purchase_count( $form_id = 0, $quantity = 1 ) {
381
	$quantity = (int) $quantity;
382
	$form     = new Give_Donate_Form( $form_id );
383
384
	return $form->decrease_sales( $quantity );
385
}
386
387
/**
388
 * Increases the total earnings of a form.
389
 *
390
 * @since 1.0
391
 *
392
 * @param int $give_form_id Give Form ID
393 42
 * @param int $amount       Earnings
394
 *
395 42
 * @return bool|int
396
 */
397
function give_increase_earnings( $give_form_id = 0, $amount ) {
398
	$form = new Give_Donate_Form( $give_form_id );
399
400
	return $form->increase_earnings( $amount );
401
}
402
403
/**
404
 * Decreases the total earnings of a form. Primarily for when a purchase is refunded.
405
 *
406
 * @since 1.0
407
 *
408
 * @param int $form_id Give Form ID
409 42
 * @param int $amount  Earnings
410
 *
411 42
 * @return bool|int
412
 */
413
function give_decrease_earnings( $form_id = 0, $amount ) {
414
	$form = new Give_Donate_Form( $form_id );
415
416
	return $form->decrease_earnings( $amount );
417
}
418
419
420
/**
421
 * Returns the total earnings for a form.
422
 *
423
 * @since 1.0
424
 *
425 11
 * @param int $form_id Give Form ID
426 11
 *
427
 * @return int $earnings Earnings for a certain form
428 11
 */
429
function give_get_form_earnings_stats( $form_id = 0 ) {
430 11
	$give_form = new Give_Donate_Form( $form_id );
431
432 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...
433
}
434
435
436 11
/**
437
 * Return the sales number for a form.
438
 *
439
 * @since 1.0
440
 *
441
 * @param int $give_form_id Give Form ID
442
 *
443
 * @return int $sales Amount of sales for a certain form
444
 */
445
function give_get_form_sales_stats( $give_form_id = 0 ) {
446
	$give_form = new Give_Donate_Form( $give_form_id );
447
448
	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...
449
}
450 11
451 11
452
/**
453 11
 * Retrieves the average monthly sales for a specific donation form
454
 *
455 11
 * @since 1.0
456
 *
457 11
 * @param int $form_id Form ID
458
 *
459
 * @return float $sales Average monthly sales
460
 */
461 11
function give_get_average_monthly_form_sales( $form_id = 0 ) {
462
	$sales        = give_get_form_sales_stats( $form_id );
463
	$release_date = get_post_field( 'post_date', $form_id );
464
465
	$diff = abs( current_time( 'timestamp' ) - strtotime( $release_date ) );
466
467
	$months = floor( $diff / ( 30 * 60 * 60 * 24 ) ); // Number of months since publication
468
469
	if ( $months > 0 ) {
470
		$sales = ( $sales / $months );
471
	}
472
473
	return $sales;
474
}
475
476
477
/**
478
 * Retrieves the average monthly earnings for a specific form
479
 *
480 34
 * @since 1.0
481 34
 *
482
 * @param int $form_id Form ID
483 34
 *
484
 * @return float $earnings Average monthly earnings
485 34
 */
486
function give_get_average_monthly_form_earnings( $form_id = 0 ) {
487 34
	$earnings     = give_get_form_earnings_stats( $form_id );
488 34
	$release_date = get_post_field( 'post_date', $form_id );
489 34
490
	$diff = abs( current_time( 'timestamp' ) - strtotime( $release_date ) );
491 34
492
	$months = floor( $diff / ( 30 * 60 * 60 * 24 ) ); // Number of months since publication
493 34
494
	if ( $months > 0 ) {
495
		$earnings = ( $earnings / $months );
496 34
	}
497
498
	return $earnings < 0 ? 0 : $earnings;
499
}
500
501
502
/**
503
 * Get Price Option Name (Text)
504
 *
505
 * Retrieves the name of a variable price option
506
 *
507
 * @since       1.0
508
 *
509
 * @param int $form_id    ID of the download
510
 * @param int $price_id   ID of the price option
511
 * @param int $payment_id payment ID for use in filters ( optional )
512
 *
513
 * @return string $price_name Name of the price option
514
 */
515
function give_get_price_option_name( $form_id = 0, $price_id = 0, $payment_id = 0 ) {
516
517
	$prices     = give_get_variable_prices( $form_id );
518
	$price_name = '';
519
520
	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...
521
522
		if ( intval( $price['_give_id']['level_id'] ) == intval( $price_id ) ) {
523
524
			$price_text     = isset( $price['_give_text'] ) ? $price['_give_text'] : '';
525
			$price_fallback = give_currency_filter( give_format_amount( $price['_give_amount'] ) );
526
			$price_name     = ! empty( $price_text ) ? $price_text : $price_fallback;
527
528
		}
529
530
	}
531
532
533
	return apply_filters( 'give_get_price_option_name', $price_name, $form_id, $payment_id, $price_id );
534
}
535
536
537
/**
538
 * Retrieves a price from from low to high of a variable priced form
539
 *
540
 * @since 1.0
541
 *
542
 * @param int $form_id ID of the form
543
 *
544
 * @return string $range A fully formatted price range
545
 */
546
function give_price_range( $form_id = 0 ) {
547
	$low   = give_get_lowest_price_option( $form_id );
548
	$high  = give_get_highest_price_option( $form_id );
549
	$range = '<span class="give_price_range_low">' . give_currency_filter( give_format_amount( $low ) ) . '</span>';
550
	$range .= '<span class="give_price_range_sep">&nbsp;&ndash;&nbsp;</span>';
551
	$range .= '<span class="give_price_range_high">' . give_currency_filter( give_format_amount( $high ) ) . '</span>';
552
553
	return apply_filters( 'give_price_range', $range, $form_id, $low, $high );
554
}
555
556
557
/**
558
 * Get Lowest Price ID
559
 *
560
 * Retrieves the ID for the cheapest price option of a variable donation form
561
 *
562
 * @since 1.5
563
 *
564
 * @param int $form_id ID of the donation
565
 *
566
 * @return int ID of the lowest price
567
 */
568
function give_get_lowest_price_id( $form_id = 0 ) {
569
570
	if ( empty( $form_id ) ) {
571
		$form_id = get_the_ID();
572
	}
573
574
	if ( ! give_has_variable_prices( $form_id ) ) {
575
		return give_get_form_price( $form_id );
576
	}
577
578
	$prices = give_get_variable_prices( $form_id );
579
580
	$low    = 0.00;
581
	$min_id = 1;
582
583
	if ( ! empty( $prices ) ) {
584
585
		foreach ( $prices as $key => $price ) {
586
587
			if ( empty( $price['_give_amount'] ) ) {
588
				continue;
589
			}
590
591
			if ( ! isset( $min ) ) {
592
				$min = $price['_give_amount'];
593
			} else {
594
				$min = min( $min, $price['_give_amount'] );
595
			}
596
597
			if ( $price['_give_amount'] == $min ) {
598
				$min_id = $price['_give_id']['level_id'];
599
			}
600
		}
601
	}
602
603
	return (int) $min_id;
604
}
605
606
/**
607
 * Retrieves cheapest price option of a variable priced form
608
 *
609
 * @since 1.0
610
 *
611
 * @param int $form_id ID of the form
612
 *
613
 * @return float Amount of the lowest price
614
 */
615
function give_get_lowest_price_option( $form_id = 0 ) {
616
	if ( empty( $form_id ) ) {
617
		$form_id = get_the_ID();
618
	}
619
620
	if ( ! give_has_variable_prices( $form_id ) ) {
621
		return give_get_form_price( $form_id );
622
	}
623
624
	$prices = give_get_variable_prices( $form_id );
625
626
	$low = 0.00;
627
628
	if ( ! empty( $prices ) ) {
629
630
		foreach ( $prices as $key => $price ) {
631
632
			if ( empty( $price['_give_amount'] ) ) {
633
				continue;
634
			}
635
636
			if ( ! isset( $min ) ) {
637
				$min = $price['_give_amount'];
638
			} else {
639
				$min = min( $min, give_sanitize_amount( $price['_give_amount'] ) );
640
			}
641
642
			if ( $price['_give_amount'] == $min ) {
643
				$min_id = $key;
644
			}
645
		}
646
647
		$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...
648
649
	}
650
651
	return give_sanitize_amount( $low );
652
}
653
654
/**
655
 * Retrieves most expensive price option of a variable priced form
656
 *
657
 * @since 1.0
658
 *
659
 * @param int $form_id ID of the form
660
 *
661
 * @return float Amount of the highest price
662
 */
663
function give_get_highest_price_option( $form_id = 0 ) {
664
665
	if ( empty( $form_id ) ) {
666
		$form_id = get_the_ID();
667
	}
668
669
	if ( ! give_has_variable_prices( $form_id ) ) {
670
		return give_get_form_price( $form_id );
671
	}
672
673
	$prices = give_get_variable_prices( $form_id );
674 12
675
	$high = 0.00;
676
677
	if ( ! empty( $prices ) ) {
678 12
679
		$max = 0;
680 12
681
		foreach ( $prices as $key => $price ) {
682
			if ( empty( $price['_give_amount'] ) ) {
683
				continue;
684
			}
685
			$give_amount = give_sanitize_amount( $price['_give_amount'] );
686
687
			$max = max( $max, $give_amount );
688
689
			if ( $give_amount == $max ) {
690
				$max_id = $key;
691
			}
692
		}
693
694 1
		$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...
695
	}
696
697
	return give_sanitize_amount( $high );
698 1
}
699
700 1
/**
701
 * Returns the price of a form, but only for non-variable priced forms.
702
 *
703
 * @since 1.0
704
 *
705
 * @param int $form_id ID number of the form to retrieve a price for
706
 *
707
 * @return mixed string|int Price of the form
708
 */
709
function give_get_form_price( $form_id = 0 ) {
710
711
	if ( empty( $form_id ) ) {
712
		return false;
713
	}
714
715
	$form = new Give_Donate_Form( $form_id );
716
717
	return $form->__get( 'price' );
718
}
719
720
/**
721
 * Returns the minimum price amount of a form, only enforced for the custom amount input.
722
 *
723
 * @since 1.3.6
724
 *
725
 * @param int $form_id ID number of the form to retrieve the minimum price for
726
 *
727
 * @return mixed string|int Minimum price of the form
728
 */
729
function give_get_form_minimum_price( $form_id = 0 ) {
730
731
	if ( empty( $form_id ) ) {
732
		return false;
733
	}
734
735
	$form = new Give_Donate_Form( $form_id );
736
737
	return $form->__get( 'minimum_price' );
738
739
}
740
741
/**
742
 * Displays a formatted price for a donation form
743
 *
744
 * @since 1.0
745
 *
746
 * @param int      $form_id  ID of the form price to show
747
 * @param bool     $echo     Whether to echo or return the results
748
 * @param bool|int $price_id Optional price id for variable pricing
749
 *
750
 * @return int $formatted_price
751
 */
752
function give_price( $form_id = 0, $echo = true, $price_id = false ) {
753
754
	if ( empty( $form_id ) ) {
755
		$form_id = get_the_ID();
756
	}
757
758
	if ( give_has_variable_prices( $form_id ) ) {
759
760
		$prices = give_get_variable_prices( $form_id );
761
762
		if ( false !== $price_id ) {
763
764
			//loop through multi-prices to see which is default
765
			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...
766
				//this is the default price
767
				if ( isset( $price['_give_default'] ) && $price['_give_default'] === 'default' ) {
768
					$price = (float) $price['_give_amount'];
769
				};
770
			}
771
772
		} else {
773
774
			$price = give_get_lowest_price_option( $form_id );
775 11
		}
776
777 11
		$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...
778
779 11
	} else {
780 11
781 11
		$price = give_get_form_price( $form_id );
782 11
783 11
	}
784
785 11
	$price           = apply_filters( 'give_form_price', give_sanitize_amount( $price ), $form_id );
786
	$formatted_price = '<span class="give_price" id="give_price_' . $form_id . '">' . $price . '</span>';
787
	$formatted_price = apply_filters( 'give_form_price_after_html', $formatted_price, $form_id, $price );
788
789
	if ( $echo ) {
790
		echo $formatted_price;
791
	} else {
792
		return $formatted_price;
793
	}
794
}
795
796
add_filter( 'give_form_price', 'give_format_amount', 10 );
797
add_filter( 'give_form_price', 'give_currency_filter', 20 );
798
799
800
/**
801
 * Retrieves the amount of a variable price option
802
 *
803
 * @since 1.0
804
 *
805
 * @param int $form_id  ID of the form
806
 * @param int $price_id ID of the price option
807
 *
808
 * @return float $amount Amount of the price option
809
 */
810
function give_get_price_option_amount( $form_id = 0, $price_id = 0 ) {
811
	$prices = give_get_variable_prices( $form_id );
812
813
	$amount = 0.00;
814
815
	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...
816
		if ( isset( $price['_give_id']['level_id'] ) && $price['_give_id']['level_id'] == $price_id ) {
817
			$amount = isset( $price['_give_amount'] ) ? $price['_give_amount'] : 0.00;
818
			break;
819
		};
820
	}
821
822
	return apply_filters( 'give_get_price_option_amount', give_sanitize_amount( $amount ), $form_id, $price_id );
823
}
824
825
/**
826
 * Returns the goal of a form
827
 *
828
 * @since 1.0
829
 *
830
 * @param int $form_id ID number of the form to retrieve a goal for
831
 *
832
 * @return mixed string|int Goal of the form
833
 */
834
function give_get_form_goal( $form_id = 0 ) {
835
836
	if ( empty( $form_id ) ) {
837
		return false;
838
	}
839
840
	$form = new Give_Donate_Form( $form_id );
841
842
	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...
843
844
}
845
846
/**
847
 * Display/Return a formatted goal for a donation form
848
 *
849
 * @since 1.0
850
 *
851 1
 * @param int  $form_id ID of the form price to show
852
 * @param bool $echo    Whether to echo or return the results
853 1
 *
854
 * @return string $formatted_goal
855 1
 */
856
function give_goal( $form_id = 0, $echo = true ) {
857
858
	if ( empty( $form_id ) ) {
859
		$form_id = get_the_ID();
860
	}
861
862
	$goal = give_get_form_goal( $form_id );
863
864
	$goal           = apply_filters( 'give_form_goal', give_sanitize_amount( $goal ), $form_id );
865
	$formatted_goal = '<span class="give_price" id="give_price_' . $form_id . '">' . $goal . '</span>';
866
	$formatted_goal = apply_filters( 'give_form_price_after_html', $formatted_goal, $form_id, $goal );
867
868
	if ( $echo ) {
869 1
		echo $formatted_goal;
870
	} else {
871 1
		return $formatted_goal;
872
	}
873
}
874
875
add_filter( 'give_form_goal', 'give_format_amount', 10 );
876
add_filter( 'give_form_goal', 'give_currency_filter', 20 );
877
878
879
/**
880
 * Checks if users can only donate when logged in
881
 *
882
 * @since  1.0
883
 *
884
 * @global array $give_options
885
 *
886
 * @param  int   $form_id Give form ID
887
 *
888
 * @return bool  $ret Whether or not the logged_in_only setting is set
889
 */
890
function give_logged_in_only( $form_id ) {
891
892
	$form_option = get_post_meta( $form_id, '_give_logged_in_only', true );
893
894
	$ret = ! empty( $form_option ) ? $form_option : false;
895
896
	return (bool) apply_filters( 'give_logged_in_only', $ret, $form_id );
897
898
}
899
900
901
/**
902
 * Checks the option for the "Register / Login Option"
903
 *
904
 * @since 1.4.1
905
 *
906
 * @param int $form_id
907
 *
908
 * @return string
909
 */
910
function give_show_login_register_option( $form_id ) {
911
912
	$show_register_form = get_post_meta( $form_id, '_give_show_register_form', true );
913
914
	return apply_filters( 'give_show_register_form', $show_register_form, $form_id );
915
916
}