Completed
Pull Request — master (#1155)
by Devin
18:24
created

paypal-standard.php ➔ give_paypal_get_pending_donation_note()   C

Complexity

Conditions 11
Paths 11

Size

Total Lines 63
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 132

Importance

Changes 0
Metric Value
cc 11
eloc 31
nc 11
nop 1
dl 0
loc 63
ccs 0
cts 22
cp 0
crap 132
rs 6.1137
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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 35 and the first side effect is on line 13.

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
 * PayPal Standard Gateway
4
 *
5
 * @package     Give
6
 * @subpackage  Gateways
7
 * @copyright   Copyright (c) 2016, WordImpress
8
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
9
 * @since       1.0
10
 */
11
12
if ( ! defined( 'ABSPATH' ) ) {
13
	exit;
14
}
15
16
/**
17
 * PayPal Remove CC Form.
18
 *
19
 * PayPal Standard does not need a CC form, so remove it.
20
 *
21
 * @access private
22
 * @since  1.0
23
 */
24
add_action( 'give_paypal_cc_form', '__return_false' );
25
26
/**
27
 * Process PayPal Purchase.
28
 *
29
 * @since 1.0
30
 *
31
 * @param array $purchase_data Purchase Data
32
 *
33
 * @return void
34
 */
35
function give_process_paypal_purchase( $purchase_data ) {
36
37
	if ( ! wp_verify_nonce( $purchase_data['gateway_nonce'], 'give-gateway' ) ) {
38
		wp_die( esc_html__( 'Nonce verification has failed.', 'give' ), esc_html__( 'Error', 'give' ), array( 'response' => 403 ) );
39
	}
40
41
	$form_id  = intval( $purchase_data['post_data']['give-form-id'] );
42
	$price_id = isset( $purchase_data['post_data']['give-price-id'] ) ? $purchase_data['post_data']['give-price-id'] : '';
43
44
	// Collect payment data.
45
	$payment_data = array(
46
		'price'           => $purchase_data['price'],
47
		'give_form_title' => $purchase_data['post_data']['give-form-title'],
48
		'give_form_id'    => $form_id,
49
		'give_price_id'   => $price_id,
50
		'date'            => $purchase_data['date'],
51
		'user_email'      => $purchase_data['user_email'],
52
		'purchase_key'    => $purchase_data['purchase_key'],
53
		'currency'        => give_get_currency(),
54
		'user_info'       => $purchase_data['user_info'],
55
		'status'          => 'pending',
56
		'gateway'         => 'paypal'
57
	);
58
59
	// Record the pending payment.
60
	$payment_id = give_insert_payment( $payment_data );
61
62
	// Check payment.
63
	if ( ! $payment_id ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $payment_id of type false|integer is loosely compared to false; this is ambiguous if the integer can be zero. 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 integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
64
		// Record the error.
65
		give_record_gateway_error(
66
			esc_html__( 'Payment Error', 'give' ),
67
			sprintf(
68
			/* translators: %s: payment data */
69
				esc_html__( 'Payment creation failed before sending donor to PayPal. Payment data: %s', 'give' ),
70
				json_encode( $payment_data )
71
			),
72
			$payment_id
73
		);
74
		// Problems? Send back.
75
		give_send_back_to_checkout( '?payment-mode=' . $purchase_data['post_data']['give-gateway'] );
76
77
	} else {
78
79
		// Only send to PayPal if the pending payment is created successfully.
80
		$listener_url = add_query_arg( 'give-listener', 'IPN', home_url( 'index.php' ) );
81
82
		// Get the success url.
83
		$return_url = add_query_arg( array(
84
			'payment-confirmation' => 'paypal',
85
			'payment-id'           => $payment_id
86
87
		), get_permalink( give_get_option( 'success_page' ) ) );
88
89
		// Get the PayPal redirect uri.
90
		$paypal_redirect = trailingslashit( give_get_paypal_redirect() ) . '?';
91
92
		//Item name - pass level name if variable priced.
93
		$item_name = $purchase_data['post_data']['give-form-title'];
94
95
		//Verify has variable prices.
96
		if ( give_has_variable_prices( $form_id ) && isset( $purchase_data['post_data']['give-price-id'] ) ) {
97
98
			$item_price_level_text = give_get_price_option_name( $form_id, $purchase_data['post_data']['give-price-id'] );
99
100
			$price_level_amount = give_get_price_option_amount( $form_id, $purchase_data['post_data']['give-price-id'] );
101
102
			//Donation given doesn't match selected level (must be a custom amount).
103
			if ( $price_level_amount != give_sanitize_amount( $purchase_data['price'] ) ) {
104
				$custom_amount_text = get_post_meta( $form_id, '_give_custom_amount_text', true );
105
				//user custom amount text if any, fallback to default if not.
106
				$item_name .= ' - ' . ( ! empty( $custom_amount_text ) ? $custom_amount_text : esc_html__( 'Custom Amount', 'give' ) );
107
108
			} //Is there any donation level text?
109
			elseif ( ! empty( $item_price_level_text ) ) {
110
				$item_name .= ' - ' . $item_price_level_text;
111
			}
112
113
		} //Single donation: Custom Amount.
114
		elseif ( give_get_form_price( $form_id ) !== give_sanitize_amount( $purchase_data['price'] ) ) {
115
			$custom_amount_text = get_post_meta( $form_id, '_give_custom_amount_text', true );
116
			//user custom amount text if any, fallback to default if not.
117
			$item_name .= ' - ' . ( ! empty( $custom_amount_text ) ? $custom_amount_text : esc_html__( 'Custom Amount', 'give' ) );
118
		}
119
120
		// Setup PayPal API params.
121
		$paypal_args = array(
122
			'business'      => give_get_option( 'paypal_email', false ),
123
			'first_name'    => $purchase_data['user_info']['first_name'],
124
			'last_name'     => $purchase_data['user_info']['last_name'],
125
			'email'         => $purchase_data['user_email'],
126
			'invoice'       => $purchase_data['purchase_key'],
127
			'amount'        => $purchase_data['price'],
128
			'item_name'     => stripslashes( $item_name ),
129
			'no_shipping'   => '1',
130
			'shipping'      => '0',
131
			'no_note'       => '1',
132
			'currency_code' => give_get_currency(),
133
			'charset'       => get_bloginfo( 'charset' ),
134
			'custom'        => $payment_id,
135
			'rm'            => '2',
136
			'return'        => $return_url,
137
			'cancel_return' => give_get_failed_transaction_uri( '?payment-id=' . $payment_id ),
138
			'notify_url'    => $listener_url,
139
			'page_style'    => give_get_paypal_page_style(),
140
			'cbt'           => get_bloginfo( 'name' ),
141
			'bn'            => 'givewp_SP'
142
		);
143
144
		//Add user address if present.
145
		if ( ! empty( $purchase_data['user_info']['address'] ) ) {
146
			$paypal_args['address1'] = isset( $purchase_data['user_info']['address']['line1'] ) ? $purchase_data['user_info']['address']['line1'] : '';
147
			$paypal_args['address2'] = isset( $purchase_data['user_info']['address']['line2'] ) ? $purchase_data['user_info']['address']['line2'] : '';
148
			$paypal_args['city']     = isset( $purchase_data['user_info']['address']['city'] ) ? $purchase_data['user_info']['address']['city'] : '';
149
			$paypal_args['state']    = isset( $purchase_data['user_info']['address']['state'] ) ? $purchase_data['user_info']['address']['state'] : '';
150
			$paypal_args['country']  = isset( $purchase_data['user_info']['address']['country'] ) ? $purchase_data['user_info']['address']['country'] : '';
151
		}
152
153
		//Donations or regular transactions?
154
		if ( give_get_option( 'paypal_button_type' ) === 'standard' ) {
155
			$paypal_extra_args = array(
156
				'cmd' => '_xclick',
157
			);
158
		} else {
159
			$paypal_extra_args = array(
160
				'cmd' => '_donations',
161
			);
162
		}
163
164
		$paypal_args = array_merge( $paypal_extra_args, $paypal_args );
165
		$paypal_args = apply_filters( 'give_paypal_redirect_args', $paypal_args, $purchase_data );
166
167
		// Build query.
168
		$paypal_redirect .= http_build_query( $paypal_args );
169
170
		// Fix for some sites that encode the entities.
171
		$paypal_redirect = str_replace( '&amp;', '&', $paypal_redirect );
172
173
		// Redirect to PayPal.
174
		wp_redirect( $paypal_redirect );
175
		exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The function give_process_paypal_purchase() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
176
	}
177
178
}
179
180
add_action( 'give_gateway_paypal', 'give_process_paypal_purchase' );
181
182
/**
183
 * Listens for a PayPal IPN requests and then sends to the processing function
184
 *
185
 * @since 1.0
186
 * @return void
187
 */
188
function give_listen_for_paypal_ipn() {
189
	// Regular PayPal IPN
190
	if ( isset( $_GET['give-listener'] ) && $_GET['give-listener'] == 'IPN' ) {
191
		do_action( 'give_verify_paypal_ipn' );
192
	}
193
}
194
195
add_action( 'init', 'give_listen_for_paypal_ipn' );
196
197
/**
198
 * Process PayPal IPN
199
 *
200
 * @since 1.0
201
 * @return void
202
 */
203
function give_process_paypal_ipn() {
204
205
	// Check the request method is POST
206
	if ( isset( $_SERVER['REQUEST_METHOD'] ) && $_SERVER['REQUEST_METHOD'] != 'POST' ) {
207
		return;
208
	}
209
210
	// Set initial post data to empty string
211
	$post_data = '';
212
213
	// Fallback just in case post_max_size is lower than needed
214
	if ( ini_get( 'allow_url_fopen' ) ) {
215
		$post_data = file_get_contents( 'php://input' );
216
	} else {
217
		// If allow_url_fopen is not enabled, then make sure that post_max_size is large enough
218
		ini_set( 'post_max_size', '12M' );
219
	}
220
	// Start the encoded data collection with notification command
221
	$encoded_data = 'cmd=_notify-validate';
222
223
	// Get current arg separator
224
	$arg_separator = give_get_php_arg_separator_output();
225
226
	// Verify there is a post_data
227
	if ( $post_data || strlen( $post_data ) > 0 ) {
228
		// Append the data
229
		$encoded_data .= $arg_separator . $post_data;
230
	} else {
231
		// Check if POST is empty
232
		if ( empty( $_POST ) ) {
233
			// Nothing to do
234
			return;
235
		} else {
236
			// Loop through each POST
237
			foreach ( $_POST as $key => $value ) {
238
				// Encode the value and append the data.
239
				$encoded_data .= $arg_separator . "$key=" . urlencode( $value );
240
			}
241
		}
242
	}
243
244
	// Convert collected post data to an array.
245
	parse_str( $encoded_data, $encoded_data_array );
246
247
	foreach ( $encoded_data_array as $key => $value ) {
0 ignored issues
show
Bug introduced by
The expression $encoded_data_array of type null|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...
248
249
		if ( false !== strpos( $key, 'amp;' ) ) {
250
			$new_key = str_replace( '&amp;', '&', $key );
251
			$new_key = str_replace( 'amp;', '&', $new_key );
252
253
			unset( $encoded_data_array[ $key ] );
254
			$encoded_data_array[ $new_key ] = $value;
255
		}
256
257
	}
258
259
	//Validate IPN request w/ PayPal if user hasn't disabled this security measure.
260
	if ( ! give_get_option( 'disable_paypal_verification' ) ) {
261
262
		$remote_post_vars = array(
263
			'method'      => 'POST',
264
			'timeout'     => 45,
265
			'redirection' => 5,
266
			'httpversion' => '1.1',
267
			'blocking'    => true,
268
			'headers'     => array(
269
				'host'         => 'www.paypal.com',
270
				'connection'   => 'close',
271
				'content-type' => 'application/x-www-form-urlencoded',
272
				'post'         => '/cgi-bin/webscr HTTP/1.1',
273
274
			),
275
			'sslverify'   => false,
276
			'body'        => $encoded_data_array
277
		);
278
279
		// Validate the IPN.
280
		$api_response = wp_remote_post( give_get_paypal_redirect(), $remote_post_vars );
281
282
		if ( is_wp_error( $api_response ) ) {
283
			give_record_gateway_error(
284
				esc_html__( 'IPN Error', 'give' ),
285
				sprintf(
286
				/* translators: %s: Paypal IPN response */
287
					esc_html__( 'Invalid IPN verification response. IPN data: %s', 'give' ),
288
					json_encode( $api_response )
289
				)
290
			);
291
292
			return; // Something went wrong
293
		}
294
295
		if ( $api_response['body'] !== 'VERIFIED' && give_get_option( 'disable_paypal_verification', false ) ) {
296
			give_record_gateway_error(
297
				esc_html__( 'IPN Error', 'give' ),
298
				sprintf(
299
				/* translators: %s: Paypal IPN response */
300
					esc_html__( 'Invalid IPN verification response. IPN data: %s', 'give' ),
301
					json_encode( $api_response )
302
				)
303
			);
304
305
			return; // Response not okay
306
		}
307
308
	}
309
310
	// Check if $post_data_array has been populated
311
	if ( ! is_array( $encoded_data_array ) && ! empty( $encoded_data_array ) ) {
312
		return;
313
	}
314
315
	$defaults = array(
316
		'txn_type'       => '',
317
		'payment_status' => ''
318
	);
319
320
	$encoded_data_array = wp_parse_args( $encoded_data_array, $defaults );
321
322
	$payment_id = isset( $encoded_data_array['custom'] ) ? absint( $encoded_data_array['custom'] ) : 0;
323
324
	if ( has_action( 'give_paypal_' . $encoded_data_array['txn_type'] ) ) {
325
		// Allow PayPal IPN types to be processed separately.
326
		do_action( 'give_paypal_' . $encoded_data_array['txn_type'], $encoded_data_array, $payment_id );
327
	} else {
328
		// Fallback to web accept just in case the txn_type isn't present.
329
		do_action( 'give_paypal_web_accept', $encoded_data_array, $payment_id );
330
	}
331
	exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The function give_process_paypal_ipn() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
332
}
333
334
add_action( 'give_verify_paypal_ipn', 'give_process_paypal_ipn' );
335
336
/**
337
 * Process web accept (one time) payment IPNs.
338
 *
339
 * @since 1.0
340
 *
341
 * @param array $data       IPN Data
342
 * @param int   $payment_id The payment ID from Give.
343
 *
344
 * @return void
345
 */
346
function give_process_paypal_web_accept_and_cart( $data, $payment_id ) {
347
348
	//Only allow through these transaction types.
349
	if ( $data['txn_type'] != 'web_accept' && $data['txn_type'] != 'cart' && strtolower( $data['payment_status'] ) != 'refunded' ) {
350
		return;
351
	}
352
353
	//Need $payment_id to continue.
354
	if ( empty( $payment_id ) ) {
355
		return;
356
	}
357
358
	// Collect donation payment details.
359
	$paypal_amount  = $data['mc_gross'];
360
	$payment_status = strtolower( $data['payment_status'] );
361
	$currency_code  = strtolower( $data['mc_currency'] );
362
	$business_email = isset( $data['business'] ) && is_email( $data['business'] ) ? trim( $data['business'] ) : trim( $data['receiver_email'] );
363
	$payment_meta   = give_get_payment_meta( $payment_id );
364
365
	// Must be a PayPal standard IPN.
366
	if ( give_get_payment_gateway( $payment_id ) != 'paypal' ) {
367
		return;
368
	}
369
370
	// Verify payment recipient
371
	if ( strcasecmp( $business_email, trim( give_get_option( 'paypal_email' ) ) ) != 0 ) {
372
373
		give_record_gateway_error(
374
			esc_html__( 'IPN Error', 'give' ),
375
			sprintf(
376
			/* translators: %s: Paypal IPN response */
377
				esc_html__( 'Invalid business email in IPN response. IPN data: %s', 'give' ),
378
				json_encode( $data )
379
			),
380
			$payment_id
381
		);
382
		give_update_payment_status( $payment_id, 'failed' );
383
		give_insert_payment_note( $payment_id, esc_html__( 'Payment failed due to invalid PayPal business email.', 'give' ) );
384
385
		return;
386
	}
387
388
	// Verify payment currency.
389
	if ( $currency_code != strtolower( $payment_meta['currency'] ) ) {
390
391
		give_record_gateway_error(
392
			esc_html__( 'IPN Error', 'give' ),
393
			sprintf(
394
			/* translators: %s: Paypal IPN response */
395
				esc_html__( 'Invalid currency in IPN response. IPN data: %s', 'give' ),
396
				json_encode( $data )
397
			),
398
			$payment_id
399
		);
400
		give_update_payment_status( $payment_id, 'failed' );
401
		give_insert_payment_note( $payment_id, esc_html__( 'Payment failed due to invalid currency in PayPal IPN.', 'give' ) );
402
403
		return;
404
	}
405
406
	//Process refunds & reversed.
407
	if ( $payment_status == 'refunded' || $payment_status == 'reversed' ) {
408
		give_process_paypal_refund( $data, $payment_id );
409
		return;
410
	}
411
412
	// Only complete payments once.
413
	if ( get_post_status( $payment_id ) == 'publish' ) {
414
		return;
415
	}
416
417
	// Retrieve the total donation amount (before PayPal).
418
	$payment_amount = give_get_payment_amount( $payment_id );
419
420
	//Check that the donation PP and local db amounts match.
421
	if ( number_format( (float) $paypal_amount, 2 ) < number_format( (float) $payment_amount, 2 ) ) {
422
		// The prices don't match
423
		give_record_gateway_error(
424
			esc_html__( 'IPN Error', 'give' ),
425
			sprintf(
426
			/* translators: %s: Paypal IPN response */
427
				esc_html__( 'Invalid payment amount in IPN response. IPN data: %s', 'give' ),
428
				json_encode( $data )
429
			),
430
			$payment_id
431
		);
432
		give_update_payment_status( $payment_id, 'failed' );
433
		give_insert_payment_note( $payment_id, esc_html__( 'Payment failed due to invalid amount in PayPal IPN.', 'give' ) );
434
435
		return;
436
	}
437
438
	//Process completed donations.
439
	if ( $payment_status == 'completed' || give_is_test_mode() ) {
440
441
		give_insert_payment_note(
442
			$payment_id,
443
			sprintf(
444
			/* translators: %s: Paypal transaction ID */
445
				esc_html__( 'PayPal Transaction ID: %s', 'give' ),
446
				$data['txn_id']
447
			)
448
		);
449
		give_set_payment_transaction_id( $payment_id, $data['txn_id'] );
450
		give_update_payment_status( $payment_id, 'publish' );
451
452
	} elseif ( 'pending' == $payment_status && isset( $data['pending_reason'] ) ) {
453
454
		// Look for possible pending reasons, such as an echeck.
455
		$note = give_paypal_get_pending_donation_note( strtolower( $data['pending_reason'] ) );
456
457
		if ( ! empty( $note ) ) {
458
459
			give_insert_payment_note( $payment_id, $note );
460
461
		}
462
	}
463
464
}
465
466
add_action( 'give_paypal_web_accept', 'give_process_paypal_web_accept_and_cart', 10, 2 );
467
468
/**
469
 * Process PayPal IPN Refunds
470
 *
471
 * @since 1.0
472
 *
473
 * @param array $data       IPN Data
474
 * @param int   $payment_id The payment ID.
475
 *
476
 * @return void
477
 */
478
function give_process_paypal_refund( $data, $payment_id = 0 ) {
479
480
	// Collect payment details
481
482
	if ( empty( $payment_id ) ) {
483
		return;
484
	}
485
486
	if ( get_post_status( $payment_id ) == 'refunded' ) {
487
		return; // Only refund payments once
488
	}
489
490
	$payment_amount = give_get_payment_amount( $payment_id );
491
	$refund_amount  = $data['payment_gross'] * - 1;
492
493
	if ( number_format( (float) $refund_amount, 2 ) < number_format( (float) $payment_amount, 2 ) ) {
494
495
		give_insert_payment_note(
496
			$payment_id,
497
			sprintf(
498
			/* translators: %s: Paypal parent transaction ID */
499
				esc_html__( 'Partial PayPal refund processed: %s', 'give' ),
500
				$data['parent_txn_id']
501
			)
502
		);
503
504
		return; // This is a partial refund
505
506
	}
507
508
	give_insert_payment_note(
509
		$payment_id,
510
		sprintf(
511
		/* translators: %s: Paypal parent transaction ID */
512
			esc_html__( 'PayPal Payment #%s Refunded for reason: %s', 'give' ),
513
			$data['parent_txn_id'], $data['reason_code']
514
		)
515
	);
516
	give_insert_payment_note(
517
		$payment_id,
518
		sprintf(
519
		/* translators: %s: Paypal transaction ID */
520
			esc_html__( 'PayPal Refund Transaction ID: %s', 'give' ),
521
			$data['txn_id']
522
		)
523
	);
524
	give_update_payment_status( $payment_id, 'refunded' );
525
}
526
527
/**
528
 * Get PayPal Redirect
529
 *
530
 * @since 1.0
531
 *
532
 * @param bool $ssl_check Is SSL?
533
 *
534
 * @return string
535
 */
536
function give_get_paypal_redirect( $ssl_check = false ) {
537
538
	if ( is_ssl() || ! $ssl_check ) {
539
		$protocal = 'https://';
540
	} else {
541
		$protocal = 'http://';
542
	}
543
544
	// Check the current payment mode
545
	if ( give_is_test_mode() ) {
546
		// Test mode
547
		$paypal_uri = $protocal . 'www.sandbox.paypal.com/cgi-bin/webscr';
548
	} else {
549
		// Live mode
550
		$paypal_uri = $protocal . 'www.paypal.com/cgi-bin/webscr';
551
	}
552
553
	return apply_filters( 'give_paypal_uri', $paypal_uri );
554
}
555
556
/**
557
 * Set the Page Style for PayPal Purchase page
558
 *
559
 * @since 1.0
560
 * @return string
561
 */
562
function give_get_paypal_page_style() {
563
	$page_style = trim( give_get_option( 'paypal_page_style', 'PayPal' ) );
564
565
	return apply_filters( 'give_paypal_page_style', $page_style );
566
}
567
568
/**
569
 * PayPal Success Page
570
 *
571
 * Shows "Donation Processing" message for PayPal payments that are still pending on site return
572
 *
573
 * @since      1.0
574
 *
575
 * @param $content
576
 *
577
 * @return string
578
 *
579
 */
580
function give_paypal_success_page_content( $content ) {
581
582
	if ( ! isset( $_GET['payment-id'] ) && ! give_get_purchase_session() ) {
583
		return $content;
584
	}
585
586
	$payment_id = isset( $_GET['payment-id'] ) ? absint( $_GET['payment-id'] ) : false;
587
588
	if ( ! $payment_id ) {
589
		$session    = give_get_purchase_session();
590
		$payment_id = give_get_purchase_id_by_key( $session['purchase_key'] );
591
	}
592
593
	$payment = get_post( $payment_id );
594
	if ( $payment && 'pending' == $payment->post_status ) {
595
596
		// Payment is still pending so show processing indicator to fix the race condition.
597
		ob_start();
598
599
		give_get_template_part( 'payment', 'processing' );
600
601
		$content = ob_get_clean();
602
603
	}
604
605
	return $content;
606
607
}
608
609
add_filter( 'give_payment_confirm_paypal', 'give_paypal_success_page_content' );
610
611
/**
612
 * Given a Payment ID, extract the transaction ID
613
 *
614
 * @since  1.0
615
 *
616
 * @param  string $payment_id Payment ID
617
 *
618
 * @return string                   Transaction ID
619
 */
620
function give_paypal_get_payment_transaction_id( $payment_id ) {
621
622
	$transaction_id = '';
623
	$notes          = give_get_payment_notes( $payment_id );
624
625
	foreach ( $notes as $note ) {
626
		if ( preg_match( '/^PayPal Transaction ID: ([^\s]+)/', $note->comment_content, $match ) ) {
627
			$transaction_id = $match[1];
628
			continue;
629
		}
630
	}
631
632
	return apply_filters( 'give_paypal_set_payment_transaction_id', $transaction_id, $payment_id );
633
}
634
635
add_filter( 'give_get_payment_transaction_id-paypal', 'give_paypal_get_payment_transaction_id', 10, 1 );
636
637
/**
638
 * Given a transaction ID, generate a link to the PayPal transaction ID details
639
 *
640
 * @since  1.0
641
 *
642
 * @param  string $transaction_id The Transaction ID
643
 * @param  int    $payment_id     The payment ID for this transaction
644
 *
645
 * @return string                 A link to the PayPal transaction details
646
 */
647
function give_paypal_link_transaction_id( $transaction_id, $payment_id ) {
0 ignored issues
show
Unused Code introduced by
The parameter $payment_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
648
649
	$paypal_base_url = 'https://history.paypal.com/cgi-bin/webscr?cmd=_history-details-from-hub&id=';
650
	$transaction_url = '<a href="' . esc_url( $paypal_base_url . $transaction_id ) . '" target="_blank">' . $transaction_id . '</a>';
651
652
	return apply_filters( 'give_paypal_link_payment_details_transaction_id', $transaction_url );
653
654
}
655
656
add_filter( 'give_payment_details_transaction_id-paypal', 'give_paypal_link_transaction_id', 10, 2 );
657
658
659
/**
660
 * Get pending donation note.
661
 *
662
 * @since 1.6.3
663
 *
664
 * @param $pending_reason
665
 *
666
 * @return string
667
 */
668
function give_paypal_get_pending_donation_note( $pending_reason ) {
669
670
	switch ( $pending_reason ) {
671
672
		case 'echeck' :
673
674
			$note = esc_html__( 'Payment made via eCheck and will clear automatically in 5-8 days.', 'give' );
675
676
			break;
677
678
		case 'address' :
679
680
			$note = esc_html__( 'Payment requires a confirmed donor address and must be accepted manually through PayPal.', 'give' );
681
682
			break;
683
684
		case 'intl' :
685
686
			$note = esc_html__( 'Payment must be accepted manually through PayPal due to international account regulations.', 'give' );
687
688
			break;
689
690
		case 'multi-currency' :
691
692
			$note = esc_html__( 'Payment received in non-shop currency and must be accepted manually through PayPal.', 'give' );
693
694
			break;
695
696
		case 'paymentreview' :
697
		case 'regulatory_review' :
698
699
			$note = esc_html__( 'Payment is being reviewed by PayPal staff as high-risk or in possible violation of government regulations.', 'give' );
700
701
			break;
702
703
		case 'unilateral' :
704
705
			$note = esc_html__( 'Payment was sent to non-confirmed or non-registered email address.', 'give' );
706
707
			break;
708
709
		case 'upgrade' :
710
711
			$note = esc_html__( 'PayPal account must be upgraded before this payment can be accepted.', 'give' );
712
713
			break;
714
715
		case 'verify' :
716
717
			$note = esc_html__( 'PayPal account is not verified. Verify account in order to accept this donation.', 'give' );
718
719
			break;
720
721
		case 'other' :
722
723
			$note = esc_html__( 'Payment is pending for unknown reasons. Contact PayPal support for assistance.', 'give' );
724
725
			break;
726
727
	}
728
729
	return $note;
0 ignored issues
show
Bug introduced by
The variable $note 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...
730
}