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