PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.6.1
GiveWP – Donation Plugin and Fundraising Platform v2.6.1
4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / includes / gateways / paypal-standard.php
give / includes / gateways Last commit date
stripe 6 years ago actions.php 6 years ago functions.php 6 years ago manual.php 6 years ago offline-donations.php 6 years ago paypal-standard.php 6 years ago
paypal-standard.php
765 lines
1 <?php
2 /**
3 * PayPal Standard Gateway
4 *
5 * @package Give
6 * @subpackage Gateways
7 * @copyright Copyright (c) 2016, GiveWP
8 * @license https://opensource.org/licenses/gpl-license GNU Public License
9 * @since 1.0
10 */
11
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit;
14 }
15
16 /**
17 * Toggle PayPal CC Billing Detail Fieldset.
18 *
19 * @param int $form_id Form ID.
20 *
21 * @return bool
22 * @since 1.8.5
23 */
24 function give_paypal_standard_billing_fields( $form_id ) {
25
26 if ( give_is_setting_enabled( give_get_option( 'paypal_standard_billing_details' ) ) ) {
27 give_default_cc_address_fields( $form_id );
28
29 return true;
30 }
31
32 return false;
33
34 }
35
36 add_action( 'give_paypal_cc_form', 'give_paypal_standard_billing_fields' );
37
38 /**
39 * Process PayPal Payment.
40 *
41 * @param array $payment_data Payment data.
42 *
43 * @return void
44 * @since 1.0
45 */
46 function give_process_paypal_payment( $payment_data ) {
47
48 // Validate nonce.
49 give_validate_nonce( $payment_data['gateway_nonce'], 'give-gateway' );
50
51 $payment_id = give_create_payment( $payment_data );
52
53 // Check payment.
54 if ( empty( $payment_id ) ) {
55 // Record the error.
56 give_record_gateway_error(
57 __( 'Payment Error', 'give' ),
58 sprintf( /* translators: %s: payment data */
59 __( 'Payment creation failed before sending donor to PayPal. Payment data: %s', 'give' ),
60 json_encode( $payment_data )
61 ),
62 $payment_id
63 );
64 // Problems? Send back.
65 give_send_back_to_checkout( '?payment-mode=' . $payment_data['post_data']['give-gateway'] );
66 }
67
68 // Redirect to PayPal.
69 wp_redirect( give_build_paypal_url( $payment_id, $payment_data ) );
70 exit;
71 }
72
73 add_action( 'give_gateway_paypal', 'give_process_paypal_payment' );
74
75 /**
76 * Listens for a PayPal IPN requests and then sends to the processing function.
77 *
78 * @return void
79 * @since 1.0
80 */
81 function give_listen_for_paypal_ipn() {
82
83 // Regular PayPal IPN.
84 if ( isset( $_GET['give-listener'] ) && 'IPN' === $_GET['give-listener'] ) {
85 /**
86 * Fires while verifying PayPal IPN
87 *
88 * @since 1.0
89 */
90 do_action( 'give_verify_paypal_ipn' );
91 }
92 }
93
94 add_action( 'init', 'give_listen_for_paypal_ipn' );
95
96 /**
97 * Process PayPal IPN
98 *
99 * @return void
100 * @since 1.0
101 */
102 function give_process_paypal_ipn() {
103
104 // Check the request method is POST.
105 if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' !== $_SERVER['REQUEST_METHOD'] ) {
106 return;
107 }
108
109 // Set initial post data to empty string.
110 $post_data = '';
111
112 // Fallback just in case post_max_size is lower than needed.
113 if ( ini_get( 'allow_url_fopen' ) ) {
114 $post_data = file_get_contents( 'php://input' );
115 } else {
116 // If allow_url_fopen is not enabled, then make sure that post_max_size is large enough.
117 ini_set( 'post_max_size', '12M' );
118 }
119 // Start the encoded data collection with notification command.
120 $encoded_data = 'cmd=_notify-validate';
121
122 // Get current arg separator.
123 $arg_separator = give_get_php_arg_separator_output();
124
125 // Verify there is a post_data.
126 if ( $post_data || strlen( $post_data ) > 0 ) {
127 // Append the data.
128 $encoded_data .= $arg_separator . $post_data;
129 } else {
130 // Check if POST is empty.
131 if ( empty( $_POST ) ) {
132 // Nothing to do.
133 return;
134 } else {
135 // Loop through each POST.
136 foreach ( $_POST as $key => $value ) {
137 // Encode the value and append the data.
138 $encoded_data .= $arg_separator . "$key=" . urlencode( $value );
139 }
140 }
141 }
142
143 // Convert collected post data to an array.
144 parse_str( $encoded_data, $encoded_data_array );
145
146 foreach ( $encoded_data_array as $key => $value ) {
147
148 if ( false !== strpos( $key, 'amp;' ) ) {
149 $new_key = str_replace( '&amp;', '&', $key );
150 $new_key = str_replace( 'amp;', '&', $new_key );
151
152 unset( $encoded_data_array[ $key ] );
153 $encoded_data_array[ $new_key ] = $value;
154 }
155 }
156
157 $api_response = false;
158
159 // Validate IPN request w/ PayPal if user hasn't disabled this security measure.
160 if ( give_is_setting_enabled( give_get_option( 'paypal_verification' ) ) ) {
161
162 $remote_post_vars = array(
163 'method' => 'POST',
164 'timeout' => 45,
165 'redirection' => 5,
166 'httpversion' => '1.1',
167 'blocking' => true,
168 'headers' => array(
169 'host' => 'www.paypal.com',
170 'connection' => 'close',
171 'content-type' => 'application/x-www-form-urlencoded',
172 'post' => '/cgi-bin/webscr HTTP/1.1',
173
174 ),
175 'sslverify' => false,
176 'body' => $encoded_data_array,
177 );
178
179 // Validate the IPN.
180 $api_response = wp_remote_post( give_get_paypal_redirect(), $remote_post_vars );
181
182 if ( is_wp_error( $api_response ) ) {
183 give_record_gateway_error(
184 __( 'IPN Error', 'give' ),
185 sprintf( /* translators: %s: Paypal IPN response */
186 __( 'Invalid IPN verification response. IPN data: %s', 'give' ),
187 json_encode( $api_response )
188 )
189 );
190
191 return; // Something went wrong.
192 }
193
194 if ( 'VERIFIED' !== $api_response['body'] ) {
195 give_record_gateway_error(
196 __( 'IPN Error', 'give' ),
197 sprintf( /* translators: %s: Paypal IPN response */
198 __( 'Invalid IPN verification response. IPN data: %s', 'give' ),
199 json_encode( $api_response )
200 )
201 );
202
203 return; // Response not okay.
204 }
205 }// End if().
206
207 // Check if $post_data_array has been populated.
208 if ( ! is_array( $encoded_data_array ) && ! empty( $encoded_data_array ) ) {
209 return;
210 }
211
212 $defaults = array(
213 'txn_type' => '',
214 'payment_status' => '',
215 );
216
217 $encoded_data_array = wp_parse_args( $encoded_data_array, $defaults );
218
219 $payment_id = isset( $encoded_data_array['custom'] ) ? absint( $encoded_data_array['custom'] ) : 0;
220 $txn_type = $encoded_data_array['txn_type'];
221
222 // Check for PayPal IPN Notifications and update data based on it.
223 $current_timestamp = current_time( 'timestamp' );
224 $paypal_ipn_vars = array(
225 'auth_status' => isset( $api_response['body'] ) ? $api_response['body'] : 'N/A',
226 'transaction_id' => isset( $encoded_data_array['txn_id'] ) ? $encoded_data_array['txn_id'] : 'N/A',
227 'payment_id' => $payment_id,
228 );
229 update_option( 'give_last_paypal_ipn_received', $paypal_ipn_vars, false );
230 give_insert_payment_note(
231 $payment_id,
232 sprintf(
233 __( 'IPN received on %1$s at %2$s', 'give' ),
234 date_i18n( 'm/d/Y', $current_timestamp ),
235 date_i18n( 'H:i', $current_timestamp )
236 )
237 );
238 give_update_meta( $payment_id, 'give_last_paypal_ipn_received', $current_timestamp );
239
240 if ( has_action( 'give_paypal_' . $txn_type ) ) {
241 /**
242 * Fires while processing PayPal IPN $txn_type.
243 *
244 * Allow PayPal IPN types to be processed separately.
245 *
246 * @param array $encoded_data_array Encoded data.
247 * @param int $payment_id Payment id.
248 *
249 * @since 1.0
250 */
251 do_action( "give_paypal_{$txn_type}", $encoded_data_array, $payment_id );
252 } else {
253 /**
254 * Fires while process PayPal IPN.
255 *
256 * Fallback to web accept just in case the txn_type isn't present.
257 *
258 * @param array $encoded_data_array Encoded data.
259 * @param int $payment_id Payment id.
260 *
261 * @since 1.0
262 */
263 do_action( 'give_paypal_web_accept', $encoded_data_array, $payment_id );
264 }
265 exit;
266 }
267
268 add_action( 'give_verify_paypal_ipn', 'give_process_paypal_ipn' );
269
270 /**
271 * Process web accept (one time) payment IPNs.
272 *
273 * @param array $data The IPN Data.
274 * @param int $payment_id The payment ID from Give.
275 *
276 * @return void
277 * @since 1.0
278 */
279 function give_process_paypal_web_accept( $data, $payment_id ) {
280
281 // Only allow through these transaction types.
282 if ( 'web_accept' !== $data['txn_type'] && 'cart' !== $data['txn_type'] && 'refunded' !== strtolower( $data['payment_status'] ) ) {
283 return;
284 }
285
286 // Need $payment_id to continue.
287 if ( empty( $payment_id ) ) {
288 return;
289 }
290
291 // Collect donation payment details.
292 $paypal_amount = $data['mc_gross'];
293 $payment_status = strtolower( $data['payment_status'] );
294 $currency_code = strtolower( $data['mc_currency'] );
295 $business_email = isset( $data['business'] ) && is_email( $data['business'] ) ? trim( $data['business'] ) : trim( $data['receiver_email'] );
296 $payment_meta = give_get_payment_meta( $payment_id );
297
298 // Must be a PayPal standard IPN.
299 if ( 'paypal' !== give_get_payment_gateway( $payment_id ) ) {
300 return;
301 }
302
303 // Verify payment recipient.
304 if ( strcasecmp( $business_email, trim( give_get_option( 'paypal_email' ) ) ) !== 0 ) {
305
306 give_record_gateway_error(
307 __( 'IPN Error', 'give' ),
308 sprintf( /* translators: %s: Paypal IPN response */
309 __( 'Invalid business email in IPN response. IPN data: %s', 'give' ),
310 json_encode( $data )
311 ),
312 $payment_id
313 );
314 give_update_payment_status( $payment_id, 'failed' );
315 give_insert_payment_note( $payment_id, __( 'Payment failed due to invalid PayPal business email.', 'give' ) );
316
317 return;
318 }
319
320 // Verify payment currency.
321 if ( $currency_code !== strtolower( $payment_meta['currency'] ) ) {
322
323 give_record_gateway_error(
324 __( 'IPN Error', 'give' ),
325 sprintf( /* translators: %s: Paypal IPN response */
326 __( 'Invalid currency in IPN response. IPN data: %s', 'give' ),
327 json_encode( $data )
328 ),
329 $payment_id
330 );
331 give_update_payment_status( $payment_id, 'failed' );
332 give_insert_payment_note( $payment_id, __( 'Payment failed due to invalid currency in PayPal IPN.', 'give' ) );
333
334 return;
335 }
336
337 // Process refunds & reversed.
338 if ( 'refunded' === $payment_status || 'reversed' === $payment_status ) {
339 give_process_paypal_refund( $data, $payment_id );
340
341 return;
342 }
343
344 // Only complete payments once.
345 if ( 'publish' === get_post_status( $payment_id ) ) {
346 return;
347 }
348
349 // Retrieve the total donation amount (before PayPal).
350 $payment_amount = give_donation_amount( $payment_id );
351
352 // Check that the donation PP and local db amounts match.
353 if ( number_format( (float) $paypal_amount, 2 ) < number_format( (float) $payment_amount, 2 ) ) {
354 // The prices don't match
355 give_record_gateway_error(
356 __( 'IPN Error', 'give' ),
357 sprintf( /* translators: %s: Paypal IPN response */
358 __( 'Invalid payment amount in IPN response. IPN data: %s', 'give' ),
359 json_encode( $data )
360 ),
361 $payment_id
362 );
363 give_update_payment_status( $payment_id, 'failed' );
364 give_insert_payment_note( $payment_id, __( 'Payment failed due to invalid amount in PayPal IPN.', 'give' ) );
365
366 return;
367 }
368
369 // Process completed donations.
370 if ( 'completed' === $payment_status || give_is_test_mode() ) {
371
372 give_insert_payment_note(
373 $payment_id,
374 sprintf( /* translators: %s: Paypal transaction ID */
375 __( 'PayPal Transaction ID: %s', 'give' ),
376 $data['txn_id']
377 )
378 );
379 give_set_payment_transaction_id( $payment_id, $data['txn_id'] );
380 give_update_payment_status( $payment_id, 'publish' );
381
382 } elseif ( 'pending' === $payment_status && isset( $data['pending_reason'] ) ) {
383
384 // Look for possible pending reasons, such as an eCheck.
385 $note = give_paypal_get_pending_donation_note( $data['pending_reason'] );
386
387 if ( ! empty( $note ) ) {
388 give_insert_payment_note( $payment_id, $note );
389 }
390 }
391
392 }
393
394 add_action( 'give_paypal_web_accept', 'give_process_paypal_web_accept', 10, 2 );
395
396 /**
397 * Process PayPal IPN Refunds
398 *
399 * @param array $data IPN Data
400 * @param int $payment_id The payment ID.
401 *
402 * @return void
403 * @since 1.0
404 */
405 function give_process_paypal_refund( $data, $payment_id = 0 ) {
406
407 // Collect payment details.
408 if ( empty( $payment_id ) ) {
409 return;
410 }
411
412 // Only refund payments once.
413 if ( 'refunded' === get_post_status( $payment_id ) ) {
414 return;
415 }
416
417 $payment_amount = give_donation_amount( $payment_id );
418 $refund_amount = $data['payment_gross'] * - 1;
419
420 if ( number_format( (float) $refund_amount, 2 ) < number_format( (float) $payment_amount, 2 ) ) {
421
422 give_insert_payment_note(
423 $payment_id,
424 sprintf( /* translators: %s: Paypal parent transaction ID */
425 __( 'Partial PayPal refund processed: %s', 'give' ),
426 $data['parent_txn_id']
427 )
428 );
429
430 return; // This is a partial refund
431
432 }
433
434 give_insert_payment_note(
435 $payment_id,
436 sprintf( /* translators: 1: Paypal parent transaction ID 2. Paypal reason code */
437 __( 'PayPal Payment #%1$s Refunded for reason: %2$s', 'give' ),
438 $data['parent_txn_id'],
439 $data['reason_code']
440 )
441 );
442 give_insert_payment_note(
443 $payment_id,
444 sprintf( /* translators: %s: Paypal transaction ID */
445 __( 'PayPal Refund Transaction ID: %s', 'give' ),
446 $data['txn_id']
447 )
448 );
449 give_update_payment_status( $payment_id, 'refunded' );
450 }
451
452 /**
453 * Get PayPal Redirect
454 *
455 * @param bool $ssl_check Is SSL?
456 *
457 * @return string
458 * @since 1.0
459 */
460 function give_get_paypal_redirect( $ssl_check = false ) {
461
462 if ( is_ssl() || ! $ssl_check ) {
463 $protocol = 'https://';
464 } else {
465 $protocol = 'http://';
466 }
467
468 // Check the current payment mode
469 if ( give_is_test_mode() ) {
470 // Test mode
471 $paypal_uri = $protocol . 'www.sandbox.paypal.com/cgi-bin/webscr';
472 } else {
473 // Live mode
474 $paypal_uri = $protocol . 'www.paypal.com/cgi-bin/webscr';
475 }
476
477 return apply_filters( 'give_paypal_uri', $paypal_uri );
478 }
479
480 /**
481 * Set the Page Style for offsite PayPal page.
482 *
483 * @return string
484 * @since 1.0
485 */
486 function give_get_paypal_page_style() {
487 $page_style = trim( give_get_option( 'paypal_page_style', 'PayPal' ) );
488
489 return apply_filters( 'give_paypal_page_style', $page_style );
490 }
491
492 /**
493 * PayPal Success Page
494 *
495 * Shows "Donation Processing" message for PayPal payments that are still pending on site return
496 *
497 * @param $content
498 *
499 * @return string
500 * @since 1.0
501 */
502 function give_paypal_success_page_content( $content ) {
503
504 if ( ! isset( $_GET['payment-id'] ) && ! give_get_purchase_session() ) {
505 return $content;
506 }
507
508 $payment_id = isset( $_GET['payment-id'] ) ? absint( $_GET['payment-id'] ) : false;
509
510 if ( ! $payment_id ) {
511 $session = give_get_purchase_session();
512 $payment_id = give_get_donation_id_by_key( $session['purchase_key'] );
513 }
514
515 $payment = get_post( $payment_id );
516 if ( $payment && 'pending' === $payment->post_status ) {
517
518 // Payment is still pending so show processing indicator to fix the race condition.
519 ob_start();
520
521 give_get_template_part( 'payment', 'processing' );
522
523 $content = ob_get_clean();
524
525 }
526
527 return $content;
528
529 }
530
531 add_filter( 'give_payment_confirm_paypal', 'give_paypal_success_page_content' );
532
533 /**
534 * Given a transaction ID, generate a link to the PayPal transaction ID details
535 *
536 * @param string $transaction_id The Transaction ID
537 * @param int $payment_id The payment ID for this transaction
538 *
539 * @return string A link to the PayPal transaction details
540 * @since 1.0
541 */
542 function give_paypal_link_transaction_id( $transaction_id, $payment_id ) {
543
544 $paypal_base_url = 'https://history.paypal.com/cgi-bin/webscr?cmd=_history-details-from-hub&id=';
545 $transaction_url = '<a href="' . esc_url( $paypal_base_url . $transaction_id ) . '" target="_blank">' . $transaction_id . '</a>';
546
547 return apply_filters( 'give_paypal_link_payment_details_transaction_id', $transaction_url );
548
549 }
550
551 add_filter( 'give_payment_details_transaction_id-paypal', 'give_paypal_link_transaction_id', 10, 2 );
552
553
554 /**
555 * Get pending donation note.
556 *
557 * @param $pending_reason
558 *
559 * @return string
560 * @since 1.6.3
561 */
562 function give_paypal_get_pending_donation_note( $pending_reason ) {
563
564 $note = '';
565
566 switch ( $pending_reason ) {
567
568 case 'echeck':
569 $note = __( 'Payment made via eCheck and will clear automatically in 5-8 days.', 'give' );
570 break;
571
572 case 'address':
573 $note = __( 'Payment requires a confirmed donor address and must be accepted manually through PayPal.', 'give' );
574 break;
575
576 case 'intl':
577 $note = __( 'Payment must be accepted manually through PayPal due to international account regulations.', 'give' );
578 break;
579
580 case 'multi-currency':
581 $note = __( 'Payment received in non-shop currency and must be accepted manually through PayPal.', 'give' );
582 break;
583
584 case 'paymentreview':
585 case 'regulatory_review':
586 $note = __( 'Payment is being reviewed by PayPal staff as high-risk or in possible violation of government regulations.', 'give' );
587 break;
588
589 case 'unilateral':
590 $note = __( 'Payment was sent to non-confirmed or non-registered email address.', 'give' );
591 break;
592
593 case 'upgrade':
594 $note = __( 'PayPal account must be upgraded before this payment can be accepted.', 'give' );
595 break;
596
597 case 'verify':
598 $note = __( 'PayPal account is not verified. Verify account in order to accept this donation.', 'give' );
599 break;
600
601 case 'other':
602 $note = __( 'Payment is pending for unknown reasons. Contact PayPal support for assistance.', 'give' );
603 break;
604
605 } // End switch().
606
607 return apply_filters( 'give_paypal_get_pending_donation_note', $note );
608
609 }
610
611 /**
612 * Build paypal url
613 *
614 * @param int $payment_id Payment ID
615 * @param array $payment_data Array of payment data.
616 *
617 * @return mixed|string
618 */
619 function give_build_paypal_url( $payment_id, $payment_data ) {
620 // Only send to PayPal if the pending payment is created successfully.
621 $listener_url = add_query_arg( 'give-listener', 'IPN', home_url( 'index.php' ) );
622
623 // Get the success url.
624 $return_url = add_query_arg(
625 array(
626 'payment-confirmation' => 'paypal',
627 'payment-id' => $payment_id,
628
629 ),
630 get_permalink( give_get_option( 'success_page' ) )
631 );
632
633 // Get the PayPal redirect uri.
634 $paypal_redirect = trailingslashit( give_get_paypal_redirect() ) . '?';
635
636 // Item name.
637 $item_name = give_payment_gateway_item_title( $payment_data );
638
639 // Setup PayPal API params.
640 $paypal_args = array(
641 'business' => give_get_option( 'paypal_email', false ),
642 'first_name' => $payment_data['user_info']['first_name'],
643 'last_name' => $payment_data['user_info']['last_name'],
644 'email' => $payment_data['user_email'],
645 'invoice' => $payment_data['purchase_key'],
646 'amount' => $payment_data['price'],
647 'item_name' => stripslashes( $item_name ),
648 'no_shipping' => '1',
649 'shipping' => '0',
650 'no_note' => '1',
651 'currency_code' => give_get_currency( $payment_id, $payment_data ),
652 'charset' => get_bloginfo( 'charset' ),
653 'custom' => $payment_id,
654 'rm' => '2',
655 'return' => $return_url,
656 'cancel_return' => give_get_failed_transaction_uri( '?payment-id=' . $payment_id ),
657 'notify_url' => $listener_url,
658 'page_style' => give_get_paypal_page_style(),
659 'cbt' => get_bloginfo( 'name' ),
660 'bn' => 'givewp_SP',
661 );
662
663 // Add user address if present.
664 if ( ! empty( $payment_data['user_info']['address'] ) ) {
665 $default_address = array(
666 'line1' => '',
667 'line2' => '',
668 'city' => '',
669 'state' => '',
670 'zip' => '',
671 'country' => '',
672 );
673
674 $address = wp_parse_args( $payment_data['user_info']['address'], $default_address );
675
676 $paypal_args['address1'] = $address['line1'];
677 $paypal_args['address2'] = $address['line2'];
678 $paypal_args['city'] = $address['city'];
679 $paypal_args['state'] = $address['state'];
680 $paypal_args['zip'] = $address['zip'];
681 $paypal_args['country'] = $address['country'];
682 }
683
684 // Donations or regular transactions?
685 $paypal_args['cmd'] = give_get_paypal_button_type();
686
687 /**
688 * Filter the paypal redirect args.
689 *
690 * @param array $paypal_args PayPal Arguments.
691 * @param array $payment_data Payment Data.
692 *
693 * @since 1.8
694 */
695 $paypal_args = apply_filters( 'give_paypal_redirect_args', $paypal_args, $payment_data );
696
697 // Build query.
698 $paypal_redirect .= http_build_query( $paypal_args );
699
700 // Fix for some sites that encode the entities.
701 $paypal_redirect = str_replace( '&amp;', '&', $paypal_redirect );
702
703 return $paypal_redirect;
704 }
705
706
707 /**
708 * Get paypal button type.
709 *
710 * @return string
711 * @since 1.8
712 */
713 function give_get_paypal_button_type() {
714 // paypal_button_type can be donation or standard.
715 $paypal_button_type = '_donations';
716 if ( 'standard' === give_get_option( 'paypal_button_type' ) ) {
717 $paypal_button_type = '_xclick';
718 }
719
720 return $paypal_button_type;
721 }
722
723 /**
724 * Update Purchase key for specific gateway.
725 *
726 * @param string $custom_purchase_key
727 * @param string $gateway
728 * @param string $purchase_key
729 *
730 * @return string
731 * @since 2.2.4
732 */
733 function give_paypal_purchase_key( $custom_purchase_key, $gateway, $purchase_key ) {
734
735 if ( 'paypal' === $gateway ) {
736 $invoice_id_prefix = give_get_option( 'paypal_invoice_prefix', 'GIVE-' );
737 $custom_purchase_key = $invoice_id_prefix . $purchase_key;
738 }
739
740 return $custom_purchase_key;
741 }
742
743 add_filter( 'give_donation_purchase_key', 'give_paypal_purchase_key', 10, 3 );
744
745
746 /**
747 * PayPal Standard Connect button.
748 *
749 * This uses Stripe's Connect button but swaps the link and logo with PayPal's.
750 *
751 * @return string
752 * @since 2.5.0
753 */
754 function give_paypal_connect_button() {
755
756 // Prepare Stripe Connect URL.
757 $link = admin_url( 'edit.php?post_type=give_forms&page=give-settings&tab=gateways&section=paypal-standard' );
758
759 return sprintf(
760 '<a href="%1$s" id="give-paypal-connect"><span>%2$s</span></a>',
761 esc_url( $link ),
762 esc_html__( 'Connect to PayPal', 'give' )
763 );
764 }
765