Completed
Pull Request — master (#1832)
by Devin
04:50
created

functions.php ➔ give_get_lowest_price_option()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 8
nop 1
dl 0
loc 17
ccs 0
cts 11
cp 0
crap 30
rs 8.8571
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     https://opensource.org/licenses/gpl-license 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 = give_get_meta( $args['form_id'], '_give_form_floating_labels', true );
72 1
	}
73
74 1
	if ( empty( $float_labels ) || ( 'global' === $float_labels ) ) {
75 1
		$float_labels = give_get_option( 'floatlabels', 'disabled' );
76 1
	}
77
78 1
	return give_is_setting_enabled( $float_labels );
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
 *
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
 *
103
 * @return      string
104
 */
105
function give_get_success_page_uri() {
106
	$give_options = give_get_settings();
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
 *
118
 * @return bool True if on the Success page, false otherwise.
119
 */
120
function give_is_success_page() {
121
	$give_options    = give_get_settings();
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 donation form.
155
 *
156
 * Used to redirect a user back to the donation form if there are errors present.
157
 *
158
 * @param array $args
159
 *
160
 * @access public
161
 * @since  1.0
162
 * @return Void
163
 */
164
function give_send_back_to_checkout( $args = array() ) {
165
166
	$url     = isset( $_POST['give-current-url'] ) ? sanitize_text_field( $_POST['give-current-url'] ) : '';
167
	$form_id = 0;
168
169
	// Set the form_id.
170
	if ( isset( $_POST['give-form-id'] ) ) {
171
		$form_id = sanitize_text_field( $_POST['give-form-id'] );
172
	}
173
174
	// Need a URL to continue. If none, redirect back to single form.
175
	if ( empty( $url ) ) {
176
		wp_safe_redirect( get_permalink( $form_id ) );
177
		give_die();
178
	}
179
180
	$defaults = array(
181
		'form-id' => (int) $form_id,
182
	);
183
184
	// Set the $level_id.
185
	if ( isset( $_POST['give-price-id'] ) ) {
186
		$defaults['level-id'] = sanitize_text_field( $_POST['give-price-id'] );
187
	}
188
189
	// Check for backward compatibility.
190
	if ( is_string( $args ) ) {
191
		$args = str_replace( '?', '', $args );
192
	}
193
194
	$args = wp_parse_args( $args, $defaults );
195
196
	// Merge URL query with $args to maintain third-party URL parameters after redirect.
197
	$url_data = wp_parse_url( $url );
198
199
	// Check if an array to prevent notices before parsing.
200
	if ( isset( $url_data['query'] ) && ! empty( $url_data['query'] ) ) {
201
		parse_str( $url_data['query'], $query );
202
203
		// Precaution: don't allow any CC info.
204
		unset( $query['card_number'] );
205
		unset( $query['card_cvc'] );
206
207
	} else {
208
		// No $url_data so pass empty array.
209
		$query = array();
210
	}
211
212
	$new_query        = array_merge( $args, $query );
213
	$new_query_string = http_build_query( $new_query );
214
215
	// Assemble URL parts.
216
	$redirect = home_url( '/' . $url_data['path'] . '?' . $new_query_string . '#give-form-' . $form_id . '-wrap' );
217
218
	// Redirect them.
219
	wp_safe_redirect( apply_filters( 'give_send_back_to_checkout', $redirect, $args ) );
220
	give_die();
221
222
}
223
224
/**
225
 * Get Success Page URL
226
 *
227
 * Gets the success page URL.
228
 *
229
 * @param string $query_string
230
 *
231
 * @access      public
232
 * @since       1.0
233
 * @return      string
234
 */
235
function give_get_success_page_url( $query_string = null ) {
236
237
	$success_page = give_get_option( 'success_page', 0 );
238
	$success_page = get_permalink( $success_page );
239
240
	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...
241
		$success_page .= $query_string;
242
	}
243
244
	return apply_filters( 'give_success_page_url', $success_page );
245
246
}
247
248
/**
249
 * Get the URL of the Failed Donation Page.
250
 *
251
 * @since 1.0
252
 *
253
 * @param bool $extras Extras to append to the URL.
254
 *
255
 * @return mixed Full URL to the Failed Donation Page, if present, home page if it doesn't exist.
256
 */
257
function give_get_failed_transaction_uri( $extras = false ) {
258
	$give_options = give_get_settings();
259
260
	$uri = ! empty( $give_options['failure_page'] ) ? trailingslashit( get_permalink( $give_options['failure_page'] ) ) : home_url();
261
	if ( $extras ) {
262
		$uri .= $extras;
263
	}
264
265
	return apply_filters( 'give_get_failed_transaction_uri', $uri );
266
}
267
268
/**
269
 * Determines if we're currently on the Failed Donation Page.
270
 *
271
 * @since 1.0
272
 * @return bool True if on the Failed Donation Page, false otherwise.
273
 */
274
function give_is_failed_transaction_page() {
275
	$give_options = give_get_settings();
276
	$ret          = isset( $give_options['failure_page'] ) ? is_page( $give_options['failure_page'] ) : false;
277
278
	return apply_filters( 'give_is_failure_page', $ret );
279
}
280
281
/**
282
 * Mark payments as Failed when returning to the Failed Donation Page
283
 *
284
 * @access      public
285
 * @since       1.0
286
 * @return      void
287
 */
288
function give_listen_for_failed_payments() {
289
290
	$failed_page = give_get_option( 'failure_page', 0 );
291
292
	if ( ! empty( $failed_page ) && is_page( $failed_page ) && ! empty( $_GET['payment-id'] ) ) {
293
294
		$payment_id = absint( $_GET['payment-id'] );
295
		give_update_payment_status( $payment_id, 'failed' );
296
297
	}
298 42
299
}
300
301 42
add_action( 'template_redirect', 'give_listen_for_failed_payments' );
302 42
303 42
/**
304 42
 * Retrieve the Donation History page URI
305 42
 *
306
 * @access      public
307
 * @since       1.7
308 42
 *
309
 * @return      string
310 42
 */
311
function give_get_history_page_uri() {
312 42
	$give_options = give_get_settings();
313 42
314
	$history_page = isset( $give_options['history_page'] ) ? get_permalink( absint( $give_options['history_page'] ) ) : get_bloginfo( 'url' );
315
316
	return apply_filters( 'give_get_history_page_uri', $history_page );
317
}
318
319
/**
320
 * Check if a field is required
321
 *
322
 * @param string $field
323
 * @param int    $form_id
324
 *
325
 * @access      public
326
 * @since       1.0
327 42
 * @return      bool
328 42
 */
329
function give_field_is_required( $field = '', $form_id ) {
330 42
331
	$required_fields = give_get_required_fields( $form_id );
332
333
	return array_key_exists( $field, $required_fields );
334
}
335
336
/**
337
 * Record Donation In Log
338
 *
339
 * Stores log information for a donation.
340
 *
341
 * @since 1.0
342
 * @global            $give_logs Give_Logging
343
 *
344 18
 * @param int         $give_form_id Give Form ID.
345 18
 * @param int         $payment_id   Payment ID.
346
 * @param bool|int    $price_id     Price ID, if any.
347 18
 * @param string|null $donation_date    The date of the donation.
348
 *
349
 * @return void
350
 */
351
function give_record_donation_in_log( $give_form_id = 0, $payment_id, $price_id = false, $donation_date = null ) {
352
	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...
353
354
	$log_data = array(
355
		'post_parent'   => $give_form_id,
356
		'log_type'      => 'sale',
357
		'post_date'     => isset( $donation_date ) ? $donation_date : null,
358
		'post_date_gmt' => isset( $donation_date ) ? $donation_date : null,
359
	);
360
361 42
	$log_meta = array(
362
		'payment_id' => $payment_id,
363 42
		'price_id'   => (int) $price_id,
364
	);
365
366
	$give_logs->insert_log( $log_data, $log_meta );
367
}
368
369
370
/**
371
 * Increases the donation total count of a donation form.
372
 *
373
 * @since 1.0
374
 *
375
 * @param int $form_id  Give Form ID
376
 * @param int $quantity Quantity to increase donation count by
377 18
 *
378
 * @return bool|int
379 18
 */
380
function give_increase_donation_count( $form_id = 0, $quantity = 1 ) {
381
	$quantity = (int) $quantity;
382
	$form     = new Give_Donate_Form( $form_id );
383
384
	return $form->increase_sales( $quantity );
385
}
386
387
/**
388
 * Decreases the sale count of a form. Primarily for when a donation is refunded.
389
 *
390
 * @since 1.0
391
 *
392
 * @param int $form_id  Give Form ID
393 42
 * @param int $quantity Quantity to increase donation count by
394
 *
395 42
 * @return bool|int
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
396
 */
397
function give_decrease_donation_count( $form_id = 0, $quantity = 1 ) {
398
	$quantity = (int) $quantity;
399
	$form     = new Give_Donate_Form( $form_id );
400
401
	return $form->decrease_sales( $quantity );
402
}
403
404
/**
405
 * Increases the total earnings of a form.
406
 *
407
 * @since 1.0
408
 *
409 42
 * @param int $give_form_id Give Form ID
410
 * @param int $amount       Earnings
411 42
 *
412
 * @return bool|int
0 ignored issues
show
Documentation introduced by
Should the return type not be double|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
413
 */
414
function give_increase_earnings( $give_form_id = 0, $amount ) {
415
	$form = new Give_Donate_Form( $give_form_id );
416
417
	return $form->increase_earnings( $amount );
418
}
419
420
/**
421
 * Decreases the total earnings of a form. Primarily for when a donation is refunded.
422
 *
423
 * @since 1.0
424
 *
425 11
 * @param int $form_id Give Form ID
426 11
 * @param int $amount  Earnings
427
 *
428 11
 * @return bool|int
0 ignored issues
show
Documentation introduced by
Should the return type not be double|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
429
 */
430 11
function give_decrease_earnings( $form_id = 0, $amount ) {
431
	$form = new Give_Donate_Form( $form_id );
432 11
433
	return $form->decrease_earnings( $amount );
434
}
435
436 11
437
/**
438
 * Returns the total earnings for a form.
439
 *
440
 * @since 1.0
441
 *
442
 * @param int $form_id Give Form ID
443
 *
444
 * @return int $earnings Earnings for a certain form
0 ignored issues
show
Documentation introduced by
Should the return type not be double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
445
 */
446
function give_get_form_earnings_stats( $form_id = 0 ) {
447
	$give_form = new Give_Donate_Form( $form_id );
448
449
	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...
450 11
}
451 11
452
453 11
/**
454
 * Return the sales number for a form.
455 11
 *
456
 * @since 1.0
457 11
 *
458
 * @param int $give_form_id Give Form ID
459
 *
460
 * @return int $sales Amount of sales for a certain form
461 11
 */
462
function give_get_form_sales_stats( $give_form_id = 0 ) {
463
	$give_form = new Give_Donate_Form( $give_form_id );
464
465
	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...
466
}
467
468
469
/**
470
 * Retrieves the average monthly sales for a specific donation form
471
 *
472
 * @since 1.0
473
 *
474
 * @param int $form_id Form ID
475
 *
476
 * @return float $sales Average monthly sales
0 ignored issues
show
Documentation introduced by
Should the return type not be double|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
477
 */
478
function give_get_average_monthly_form_sales( $form_id = 0 ) {
479
	$sales        = give_get_form_sales_stats( $form_id );
480 34
	$release_date = get_post_field( 'post_date', $form_id );
481 34
482
	$diff = abs( current_time( 'timestamp' ) - strtotime( $release_date ) );
483 34
484
	$months = floor( $diff / ( 30 * 60 * 60 * 24 ) ); // Number of months since publication
485 34
486
	if ( $months > 0 ) {
487 34
		$sales = ( $sales / $months );
488 34
	}
489 34
490
	return $sales;
491 34
}
492
493 34
494
/**
495
 * Retrieves the average monthly earnings for a specific form
496 34
 *
497
 * @since 1.0
498
 *
499
 * @param int $form_id Form ID
500
 *
501
 * @return float $earnings Average monthly earnings
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
502
 */
503
function give_get_average_monthly_form_earnings( $form_id = 0 ) {
504
	$earnings     = give_get_form_earnings_stats( $form_id );
505
	$release_date = get_post_field( 'post_date', $form_id );
506
507
	$diff = abs( current_time( 'timestamp' ) - strtotime( $release_date ) );
508
509
	$months = floor( $diff / ( 30 * 60 * 60 * 24 ) ); // Number of months since publication
510
511
	if ( $months > 0 ) {
512
		$earnings = ( $earnings / $months );
513
	}
514
515
	return $earnings < 0 ? 0 : $earnings;
516
}
517
518
519
/**
520
 * Get Price Option Name (Text)
521
 *
522
 * Retrieves the name of a variable price option.
523
 *
524
 * @since       1.0
525
 *
526
 * @param int $form_id    ID of the donation form.
527
 * @param int $price_id   ID of the price option.
528
 * @param int $payment_id payment ID for use in filters ( optional ).
529
 *
530
 * @return string $price_name Name of the price option
531
 */
532
function give_get_price_option_name( $form_id = 0, $price_id = 0, $payment_id = 0 ) {
533
534
	$prices     = give_get_variable_prices( $form_id );
535
	$price_name = '';
536
537
	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...
538
539
		if ( intval( $price['_give_id']['level_id'] ) == intval( $price_id ) ) {
540
541
			$price_text     = isset( $price['_give_text'] ) ? $price['_give_text'] : '';
542
			$price_fallback = give_currency_filter( give_format_amount( $price['_give_amount'] ), '', true );
543
			$price_name     = ! empty( $price_text ) ? $price_text : $price_fallback;
544
545
		}
546
	}
547
548
	return apply_filters( 'give_get_price_option_name', $price_name, $form_id, $payment_id, $price_id );
549
}
550
551
552
/**
553
 * Retrieves a price from from low to high of a variable priced form
554
 *
555
 * @since 1.0
556
 *
557
 * @param int $form_id ID of the form
558
 *
559
 * @return string $range A fully formatted price range
560
 */
561
function give_price_range( $form_id = 0 ) {
562
	$low        = give_get_lowest_price_option( $form_id );
563
	$high       = give_get_highest_price_option( $form_id );
564
	$order_type = ! empty( $_REQUEST['order'] ) ? $_REQUEST['order'] : 'asc';
565
566
	$range = sprintf(
567
		'<span class="give_price_range_%1$s">%2$s</span>
568
				<span class="give_price_range_sep">&nbsp;&ndash;&nbsp;</span>
569
				<span class="give_price_range_%3$s">%4$s</span>',
570
		'asc' === $order_type ? 'low' : 'high',
571
		'asc' === $order_type ? give_currency_filter( give_format_amount( $low ) ) : give_currency_filter( give_format_amount( $high ) ),
572
		'asc' === $order_type ? 'high' : 'low',
573
		'asc' === $order_type ? give_currency_filter( give_format_amount( $high ) ) : give_currency_filter( give_format_amount( $low ) )
574
575
	);
576
577
	return apply_filters( 'give_price_range', $range, $form_id, $low, $high );
578
}
579
580
581
/**
582
 * Get Lowest Price ID
583
 *
584
 * Retrieves the ID for the cheapest price option of a variable donation form
585
 *
586
 * @since 1.5
587
 *
588
 * @param int $form_id ID of the donation
589
 *
590
 * @return int ID of the lowest price
591
 */
592
function give_get_lowest_price_id( $form_id = 0 ) {
593
594
	if ( empty( $form_id ) ) {
595
		$form_id = get_the_ID();
596
	}
597
598
	if ( ! give_has_variable_prices( $form_id ) ) {
599
		return give_get_form_price( $form_id );
600
	}
601
602
	$prices = give_get_variable_prices( $form_id );
603
604
	$min = $min_id = 0;
605
606
	if ( ! empty( $prices ) ) {
607
608
		foreach ( $prices as $key => $price ) {
609
610
			if ( empty( $price['_give_amount'] ) ) {
611
				continue;
612
			}
613
614
			if ( ! isset( $min ) ) {
615
				$min = $price['_give_amount'];
616
			} else {
617
				$min = min( $min, $price['_give_amount'] );
618
			}
619
620
			if ( $price['_give_amount'] == $min ) {
621
				$min_id = $price['_give_id']['level_id'];
622
			}
623
		}
624
	}
625
626
	return (int) $min_id;
627
}
628
629
/**
630
 * Retrieves cheapest price option of a variable priced form
631
 *
632
 * @since 1.0
633
 *
634
 * @param int $form_id ID of the form
635
 *
636
 * @return float Amount of the lowest price
637
 */
638
function give_get_lowest_price_option( $form_id = 0 ) {
639
	if ( empty( $form_id ) ) {
640
		$form_id = get_the_ID();
641
	}
642
643
	if ( ! give_has_variable_prices( $form_id ) ) {
644
		return give_get_form_price( $form_id );
645
	}
646
647
	if ( ! ( $low = get_post_meta( $form_id, '_give_levels_minimum_amount', true ) ) ) {
648
		// Backward compatibility.
649
		$prices = wp_list_pluck( give_get_variable_prices( $form_id ), '_give_amount' );
650
		$low    = ! empty( $prices ) ? min( $prices ) : 0;
651
	}
652
653
	return give_sanitize_amount( $low );
654
}
655
656
/**
657
 * Retrieves most expensive price option of a variable priced form
658
 *
659
 * @since 1.0
660
 *
661
 * @param int $form_id ID of the form
662
 *
663
 * @return float Amount of the highest price
664
 */
665
function give_get_highest_price_option( $form_id = 0 ) {
666
667
	if ( empty( $form_id ) ) {
668
		$form_id = get_the_ID();
669
	}
670
671
	if ( ! give_has_variable_prices( $form_id ) ) {
672
		return give_get_form_price( $form_id );
673
	}
674 12
675
	if ( ! ( $high = get_post_meta( $form_id, '_give_levels_maximum_amount', true ) ) ) {
676
		// Backward compatibility.
677
		$prices = wp_list_pluck( give_get_variable_prices( $form_id ), '_give_amount' );
678 12
		$high   = ! empty( $prices ) ? max( $prices ) : 0;
679
	}
680 12
681
	return give_sanitize_amount( $high );
682
}
683
684
/**
685
 * Returns the price of a form, but only for non-variable priced forms.
686
 *
687
 * @since 1.0
688
 *
689
 * @param int $form_id ID number of the form to retrieve a price for
690
 *
691
 * @return mixed string|int Price of the form
692
 */
693
function give_get_form_price( $form_id = 0 ) {
694 1
695
	if ( empty( $form_id ) ) {
696
		return false;
697
	}
698 1
699
	$form = new Give_Donate_Form( $form_id );
700 1
701
	return $form->__get( 'price' );
702
}
703
704
/**
705
 * Returns the minimum price amount of a form, only enforced for the custom amount input.
706
 *
707
 * @since 1.3.6
708
 *
709
 * @param int $form_id ID number of the form to retrieve the minimum price for
710
 *
711
 * @return mixed string|int Minimum price of the form
712
 */
713
function give_get_form_minimum_price( $form_id = 0 ) {
714
715
	if ( empty( $form_id ) ) {
716
		return false;
717
	}
718
719
	$form = new Give_Donate_Form( $form_id );
720
721
	return $form->__get( 'minimum_price' );
722
723
}
724
725
/**
726
 * Displays a formatted price for a donation form
727
 *
728
 * @since 1.0
729
 *
730
 * @param int      $form_id  ID of the form price to show
731
 * @param bool     $echo     Whether to echo or return the results
732
 * @param bool|int $price_id Optional price id for variable pricing
733
 *
734
 * @return int $formatted_price
735
 */
736
function give_price( $form_id = 0, $echo = true, $price_id = false ) {
737
738
	if ( empty( $form_id ) ) {
739
		$form_id = get_the_ID();
740
	}
741
742
	if ( give_has_variable_prices( $form_id ) ) {
743
744
		$prices = give_get_variable_prices( $form_id );
745
746
		if ( false !== $price_id ) {
747
748
			// loop through multi-prices to see which is default
749
			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...
750
				// this is the default price
751
				if ( isset( $price['_give_default'] ) && $price['_give_default'] === 'default' ) {
752
					$price = (float) $price['_give_amount'];
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
 * @param  int $form_id Give form ID
868
 *
869 1
 * @return bool  $ret Whether or not the logged_in_only setting is set
870
 */
871 1
function give_logged_in_only( $form_id ) {
872
	// If _give_logged_in_only is set to enable then guest can donate from that specific form.
873
	// Otherwise it is member only donation form.
874
	$val = give_get_meta( $form_id, '_give_logged_in_only', true );
875
	$val = ! empty( $val ) ? $val : 'enabled';
876
877
	$ret = ! give_is_setting_enabled( $val );
878
879
	return (bool) apply_filters( 'give_logged_in_only', $ret, $form_id );
880
}
881
882
883
/**
884
 * Checks the option for the "Register / Login Option"
885
 *
886
 * @since 1.4.1
887
 *
888
 * @param int $form_id
889
 *
890
 * @return string
891
 */
892
function give_show_login_register_option( $form_id ) {
893
894
	$show_register_form = give_get_meta( $form_id, '_give_show_register_form', true );
895
896
	return apply_filters( 'give_show_register_form', $show_register_form, $form_id );
897
898
}
899
900
901
/**
902
 * Get pre fill form field values.
903
 *
904
 * Note: this function will extract form field values from give_purchase session data.
905
 *
906
 * @since  1.8
907
 *
908
 * @param  int $form_id Form ID.
909
 *
910
 * @return array
911
 */
912
function _give_get_prefill_form_field_values( $form_id ) {
913
	$logged_in_donor_info = array();
914
915
	if ( is_user_logged_in() ) :
916
		$donor_data    = get_userdata( get_current_user_id() );
917
		$donor_address = get_user_meta( get_current_user_id(), '_give_user_address', true );
918
919
		$logged_in_donor_info = array(
920
			// First name.
921
			'give_first'      => $donor_data->first_name,
922
923
			// Last name.
924
			'give_last'       => $donor_data->last_name,
925
926
			// Email.
927
			'give_email'      => $donor_data->user_email,
928
929
			// Street address 1.
930
			'card_address'    => ( ! empty( $donor_address['line1'] ) ? $donor_address['line1'] : '' ),
931
932
			// Street address 2.
933
			'card_address_2'  => ( ! empty( $donor_address['line2'] ) ? $donor_address['line2'] : '' ),
934
935
			// Country.
936
			'billing_country' => ( ! empty( $donor_address['country'] ) ? $donor_address['country'] : '' ),
937
938
			// State.
939
			'card_state'      => ( ! empty( $donor_address['state'] ) ? $donor_address['state'] : '' ),
940
941
			// City.
942
			'card_city'       => ( ! empty( $donor_address['city'] ) ? $donor_address['city'] : '' ),
943
944
			// Zipcode
945
			'card_zip'        => ( ! empty( $donor_address['zip'] ) ? $donor_address['zip'] : '' ),
946
		);
947
	endif;
948
949
	// Bailout: Auto fill form field values only form form which donor is donating.
950
	if (
951
		empty( $_GET['form-id'] )
952
		|| ! $form_id
953
		|| ( $form_id !== absint( $_GET['form-id'] ) )
954
	) {
955
		return $logged_in_donor_info;
956
	}
957
958
	// Get purchase data.
959
	$give_purchase_data = Give()->session->get( 'give_purchase' );
960
961
	// Get donor info from form data.
962
	$give_donor_info_in_session = empty( $give_purchase_data['post_data'] )
963
		? array()
964
		: $give_purchase_data['post_data'];
965
966
	// Output.
967
	return wp_parse_args( $give_donor_info_in_session, $logged_in_donor_info );
968
}
969