Completed
Push — master ( 9a5cf9...f11a89 )
by Devin
37:27 queued 17:25
created

functions.php ➔ give_send_back_to_checkout()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 38
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

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