PluginProbe ʕ •ᴥ•ʔ
JetFormBuilder — Dynamic Blocks Form Builder / 1.1.4
JetFormBuilder — Dynamic Blocks Form Builder v1.1.4
3.6.3.1 3.6.3 3.6.2.2 3.6.2.1 3.6.2 3.6.1.1 3.6.1 3.6.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.1.0 2.1.1 2.1.10 2.1.11 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 3.0.0 3.0.0.1 3.0.0.2 3.0.0.3 3.0.1 3.0.1.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.0.1 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.3.2 3.3.3 3.3.3.1 3.3.4 3.3.4.1 3.3.4.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.5.1 3.4.5.2 3.4.6 3.4.7 3.4.7.1 3.5.0 3.5.1 3.5.1.1 3.5.1.2 3.5.2 3.5.2.1 3.5.3 3.5.4 3.5.5 3.5.6 3.5.6.1 3.5.6.2 3.5.6.3 3.6.0
jetformbuilder / includes / gateways / paypal.php
jetformbuilder / includes / gateways Last commit date
paypal 5 years ago base-gateway.php 5 years ago gateway-manager.php 5 years ago gateways-editor-data.php 5 years ago paypal.php 5 years ago
paypal.php
573 lines
1 <?php
2
3 namespace Jet_Form_Builder\Gateways;
4
5 use Jet_Form_Builder\Actions\Action_Handler;
6 use Jet_Form_Builder\Exceptions\Action_Exception;
7 use Jet_Form_Builder\Exceptions\Gateway_Exception;
8 use Jet_Form_Builder\Plugin;
9
10 class Paypal {
11
12 private $options = array();
13 private $gateways_meta;
14 private $action_handler;
15 private $price_field = false;
16 private $order_id;
17 private $price;
18 private $token;
19
20 public $data = false;
21 public $message = false;
22 public $redirect = false;
23
24 public function __construct() {
25 add_action( 'jet-form-builder/actions/before-send', array( $this, 'prevent_notifications' ) );
26 add_action( 'jet-form-builder/actions/after-send', array( $this, 'process_payment' ) );
27 add_action( 'jet-form-builder/gateways/success/paypal', array( $this, 'process_payment_result' ) );
28 }
29
30 /**
31 * Returns current gateway ID
32 *
33 * @return [type] [description]
34 */
35 public function get_id() {
36 return 'paypal';
37 }
38
39 /**
40 * Returns current gateway name
41 *
42 * @return [type] [description]
43 */
44 public function get_name() {
45 return __( 'PayPal Checkout', 'jet-form-builder' );
46 }
47
48 /**
49 * Store payment status into order and show success/failed message
50 * @return [type] [description]
51 */
52 public function process_payment_result() {
53
54 $token = esc_attr( $_GET['token'] );
55 $this->data = $this->get_form_by_payment( $token );
56
57 if ( ! $this->set_gateway_data_on_result() ) {
58 return;
59 }
60
61 $this->data['date'] = date_i18n( 'F j, Y, H:i' );
62
63 $this->data['gateway'] = $this->get_name();
64
65 update_post_meta( $this->data['order_id'], '_jet_gateway_data', $this->data );
66
67 $this->try_do_actions();
68 }
69
70 private function try_do_actions() {
71 $failed_statuses = array( 'VOIDED' );
72
73 Gateway_Manager::instance()->add_data( $this->data );
74
75 try {
76 if ( in_array( $this->data['status'], $failed_statuses ) ) {
77 $this->process_status( 'failed' );
78 } else {
79 $this->process_status( 'success' );
80 }
81 } catch ( Action_Exception $exception ) {
82 //
83 }
84
85 }
86
87 private function set_gateway_data_on_result() {
88 $this->gateways_meta = Plugin::instance()->post_type->get_gateways( $this->data['form_id'] );
89
90 try {
91 $this->set_paypal_options();
92 $this->set_token();
93 $this->set_payment_status();
94
95 } catch ( Gateway_Exception $exception ) {
96 return false;
97 }
98
99 return true;
100 }
101
102 private function set_payment_status() {
103 $payment = $this->request(
104 'v2/checkout/orders/' . $this->data['payment_id'] . '/capture',
105 array(),
106 null,
107 $this->token
108 );
109
110 if ( ! $payment ) {
111 return;
112 }
113
114 $payment = json_decode( $payment, true );
115
116 if ( empty( $payment['status'] ) ) {
117 throw new Gateway_Exception( 'Empty payment status' );
118 }
119
120 $this->data['status'] = $payment['status'];
121
122 $this->set_payer( $payment );
123 $this->set_payment_amount( $payment );
124 }
125
126 private function set_payer( $payment ) {
127 if ( ! empty( $payment['payer'] ) ) {
128 $this->data['payer'] = array(
129 'first_name' => $payment['payer']['name']['given_name'],
130 'last_name' => $payment['payer']['name']['surname'],
131 'email' => $payment['payer']['email_address'],
132 );
133 }
134 }
135
136 private function set_payment_amount( $payment ) {
137 if ( ! empty( $payment['purchase_units'][0]['payments']['captures'] ) ) {
138 $payment_unit = $payment['purchase_units'][0]['payments']['captures'][0];
139 $this->data['amount'] = $payment_unit['amount'];
140 }
141 }
142
143 private function set_gateway_data() {
144 $this->gateways_meta = Plugin::instance()->post_type->get_gateways( $this->action_handler->form_id );
145
146 try {
147 $this->set_order_id();
148 $this->is_paypal_gateway();
149 $this->set_price_field();
150 $this->set_price_from_filed();
151 $this->set_paypal_options();
152 $this->set_token();
153
154 } catch ( Gateway_Exception $exception ) {
155 return false;
156 }
157
158 return true;
159 }
160
161 /**
162 * Process status notification and enqueue message
163 *
164 * @param string $type [description]
165 * @param [type] $form_id [description]
166 * @param array $settings [description]
167 *
168 * @return [type] [description]
169 */
170 public function process_status( $type = 'success' ) {
171
172 $message = ! empty( $settings[ $type . '_message' ] ) ? wp_kses_post( $settings[ $type . '_message' ] ) : null;
173 $notifications = isset( $settings[ 'notifications_' . $type ] ) ? $settings[ 'notifications_' . $type ] : array();
174
175 if ( $message ) {
176 Gateway_Manager::instance()->add_message( $message );
177 }
178
179 do_action( 'jet-form-builder/gateways/on-payment-' . $type, $this->data, $settings );
180
181 if ( ! empty( $notifications ) ) {
182 $notifications = new Action_Handler(
183 $this->data['form_id'],
184 $this->data['form_data']
185 );
186
187 $notifications->unregister_action( 'redirect_to_page' );
188
189 $all = $notifications->get_all();
190 $keep_these = isset( $settings[ 'notifications_' . $type ] ) ? $settings[ 'notifications_' . $type ] : array();
191
192 if ( empty( $all ) ) {
193 return;
194 }
195
196 foreach ( $all as $index => $notification ) {
197
198 if ( ! in_array( $index, $keep_these ) ) {
199 $notifications->unregister_action( $index );
200 }
201
202 }
203
204 $notifications->do_actions();
205 }
206
207 }
208
209 /**
210 * Returns form data by payment ID
211 *
212 * @param [type] $payment [description]
213 *
214 * @return [type] [description]
215 */
216 public function get_form_by_payment( $payment = null ) {
217
218 if ( ! $payment ) {
219 return;
220 }
221
222 global $wpdb;
223 $row = $wpdb->get_row( "SELECT * FROM $wpdb->postmeta WHERE meta_key = '_jet_gateway_data' AND meta_value LIKE '%$payment%'", ARRAY_A );
224
225 if ( empty( $row ) ) {
226 return;
227 }
228
229 $data = $row['meta_value'];
230
231 return maybe_unserialize( $data );
232
233 }
234
235
236 /**
237 * Prevent unnecessary notifications processing before form is send.
238 *
239 * @param [type] $handler [description]
240 *
241 * @return [type] [description]
242 */
243 public function prevent_notifications( $action_handler ) {
244
245 $gateways = Plugin::instance()->post_type->get_gateways( $action_handler->form_id );
246
247 if ( empty( $gateways ) || empty( $gateways['gateway'] ) ) {
248 return;
249 }
250
251 $action_handler->unregister_action( 'redirect_to_page' );
252
253 $keep_these = ! empty( $gateways['notifications_before'] ) ? $gateways['notifications_before'] : array();
254 $form_actions = $action_handler->get_all();
255 $keep_these = apply_filters( 'jet-form-builder/gateways/notifications-before', $keep_these, $form_actions );
256
257 if ( empty( $form_actions ) ) {
258 return;
259 }
260
261 foreach ( $form_actions as $index => $action ) {
262
263 if ( 'insert_post' === $action['type'] ) {
264 continue;
265 }
266
267 if ( 'redirect_to_page' === $action['type'] ) {
268 $this->redirect = $action;
269 }
270
271 if ( ! in_array( $index, $keep_these ) ) {
272 $action_handler->unregister_action( $index );
273 }
274
275 }
276
277 }
278
279
280 private function set_order_id() {
281 $response = $this->action_handler->response_data;
282 if ( ! isset( $response['inserted_post_id'] )
283 || empty( $response['inserted_post_id'] ) ) {
284
285 throw new Gateway_Exception( 'There is not inserted_post_id' );
286 }
287 $this->order_id = $response['inserted_post_id'];
288 }
289
290 private function is_paypal_gateway() {
291 if ( ! isset( $this->gateways_meta['gateway'] ) ||
292 empty( $this->gateways_meta['gateway'] ) ||
293 $this->get_id() !== $this->gateways_meta['gateway'] ) {
294
295 throw new Gateway_Exception( 'Invalid gateway' );
296 }
297 }
298
299 private function set_price_field() {
300 if ( isset( $this->gateways_meta['price_field'] ) && ! empty( $this->gateways_meta['price_field'] ) ) {
301 $this->price_field = esc_attr( $this->gateways_meta['price_field'] );
302 }
303
304 $this->price_field = apply_filters( 'jet-form-builder/gateways/price-field', $this->price_field, $this->action_handler );
305
306 if ( ! $this->price_field ) {
307 throw new Gateway_Exception( 'Invalid price field' );
308 }
309 }
310
311 private function set_price_from_filed() {
312 if ( isset( $this->action_handler->response_data[ $this->price_field ] ) ) {
313 $this->price = $this->action_handler->response_data[ $this->price_field ];
314 }
315
316 if ( ! $this->price ) {
317 throw new Gateway_Exception( 'Empty price field' );
318 }
319 }
320
321 private function set_paypal_options() {
322 $gateway = $this->gateways_meta['paypal'];
323
324 foreach ( [ 'client_id', 'secret', 'currency' ] as $option ) {
325 if ( ! isset( $gateway[ $option ] ) || empty( $gateway[ $option ] ) ) {
326 throw new Gateway_Exception( 'Invalid gateway options' );
327 }
328 $this->options[ $option ] = esc_attr( $gateway[ $option ] );
329 }
330 }
331
332 private function set_token() {
333 $this->token = $this->get_token(
334 $this->options['client_id'],
335 $this->options['secret']
336 );
337
338 if ( ! $this->token ) {
339 throw new Gateway_Exception( 'Invalid token' );
340 }
341 }
342
343 /**
344 * Process gateway payment
345 *
346 * @param $action_handler
347 *
348 * @return void [type] [description]
349 */
350 public function process_payment( $action_handler ) {
351 $this->action_handler = $action_handler;
352
353 if ( ! $this->set_gateway_data() ) {
354 return;
355 }
356
357 $remove_refer_args = array(
358 'jet_gateway',
359 'payment',
360 'token',
361 'PayerID',
362 );
363
364 $success_refer = $action_handler->request_data['__refer'];
365 $cancel_refer = $action_handler->request_data['__refer'];
366
367 $success_redirect = ! empty( $this->gateways_meta['use_success_redirect'] ) ? $this->gateways_meta['use_success_redirect'] : false;
368 $success_redirect = filter_var( $success_redirect, FILTER_VALIDATE_BOOLEAN );
369
370 if ( $success_redirect && $this->redirect ) {
371 $type = ! empty( $this->redirect['redirect_type'] ) ? $this->redirect['redirect_type'] : 'static_page';
372
373 if ( 'static_page' === $type ) {
374 $to_page = ! empty( $this->redirect['redirect_page'] ) ? $this->redirect['redirect_page'] : false;
375 $success_refer = ! empty( $to_page ) ? get_permalink( $to_page ) : false;
376 } else {
377 $success_refer = ! empty( $this->redirect['redirect_url'] ) ? $this->redirect['redirect_url'] : false;
378 }
379 }
380
381 $order = $this->request(
382 'v2/checkout/orders',
383 array(),
384 array(
385 'intent' => 'CAPTURE',
386 'application_context' => array(
387 'landing_page' => 'BILLING',
388 'user_action' => 'PAY_NOW',
389 'brand_name' => get_option( 'blogname' ),
390 'return_url' => add_query_arg(
391 array( 'jet_gateway' => $this->get_id(), 'payment' => 'success' ),
392 trailingslashit( remove_query_arg( $remove_refer_args, $success_refer ) )
393 ),
394 'cancel_url' => add_query_arg(
395 array( 'jet_gateway' => $this->get_id(), 'payment' => 'canceled' ),
396 trailingslashit( remove_query_arg( $remove_refer_args, $cancel_refer ) )
397 ),
398 ),
399 'purchase_units' => array(
400 array(
401 'custom_id' => $action_handler->form_id . '-' . $this->order_id,
402 'amount' => array(
403 'currency_code' => $this->options['currency'],
404 'value' => $this->price,
405 ),
406 ),
407 ),
408 )
409 );
410
411 if ( empty( $order ) || is_wp_error( $order ) ) {
412 return;
413 }
414
415 $order = json_decode( $order, true );
416
417 if ( ! $order ) {
418 return;
419 }
420
421 $pp_order_id = ! empty( $order['id'] ) ? $order['id'] : false;
422
423 if ( ! $pp_order_id ) {
424 return;
425 }
426
427 update_post_meta(
428 $this->order_id,
429 '_jet_gateway_data',
430 array(
431 'payment_id' => $pp_order_id,
432 'order_id' => $this->order_id,
433 'form_id' => $action_handler->form_id,
434 'form_data' => $action_handler->request_data,
435 )
436 );
437
438 foreach ( $order['links'] as $link ) {
439 if ( ! empty( $link['rel'] ) && 'approve' === $link['rel'] ) {
440 wp_redirect( $link['href'] );
441 die();
442 }
443 }
444
445 return;
446
447 }
448
449 /**
450 * Return API url
451 *
452 * @return string
453 */
454 public function api_url( $endpoint ) {
455
456 $sandbox = apply_filters( 'jet-form-builder/gateways/paypal/sandbox-mode', false );
457
458 if ( $sandbox ) {
459 $url = 'https://api.sandbox.paypal.com/';
460 } else {
461 $url = 'https://api.paypal.com/';
462 }
463
464 return esc_url( $url . $endpoint );
465 }
466
467 /**
468 * Returns auth token for current client_id and secret combination
469 *
470 * @param [type] $client_id [description]
471 * @param [type] $secret [description]
472 *
473 * @return [type] [description]
474 */
475 public function get_token( $client_id = false, $secret = false ) {
476
477 $hash = md5( $client_id . $secret );
478 $token = get_transient( $hash );
479
480 if ( ! $client_id ) {
481 $client_id = $this->options['client_id'];
482 }
483
484 if ( ! $secret ) {
485 $secret = $this->options['secret'];
486 }
487
488 if ( ! $client_id || ! $secret ) {
489 return;
490 }
491
492 if ( $token ) {
493 return $token;
494 }
495
496 $key = base64_encode( $client_id . ':' . $secret );
497
498 $response = $this->request(
499 'v1/oauth2/token',
500 array(
501 'Accept' => 'application/json',
502 'Accept-Language' => get_locale(),
503 'Authorization' => 'Basic ' . $key,
504 ),
505 'grant_type=client_credentials'
506 );
507
508 if ( ! $response ) {
509 return false;
510 }
511
512 $response = json_decode( $response, true );
513
514 if ( ! $response || empty( $response['access_token'] ) ) {
515 return false;
516 }
517
518 $token = $response['access_token'];
519
520 set_transient( $hash, $token, 3 * HOUR_IN_SECONDS );
521
522 return $token;
523
524 }
525
526 /**
527 * Make a request
528 *
529 * @param [type] $endpoint [description]
530 * @param array $headers [description]
531 * @param array $body [description]
532 *
533 * @return [type] [description]
534 */
535 public function request( $endpoint = null, $headers = array(), $body = array(), $token = false, $method = 'post' ) {
536
537 $url = $this->api_url( $endpoint );
538
539 if ( empty( $headers ) ) {
540
541 if ( ! $token ) {
542 $token = $this->get_token();
543 }
544
545 $headers = array(
546 'Content-Type' => 'application/json',
547 'Accept-Language' => get_locale(),
548 'Authorization' => 'Bearer ' . $token,
549 );
550 }
551
552 if ( is_array( $body ) ) {
553 $body = json_encode( $body );
554 }
555
556 $args = array(
557 'timeout' => 45,
558 'headers' => $headers,
559 );
560
561 if ( 'post' === $method ) {
562 $args['method'] = 'POST';
563 $args['body'] = $body;
564 $response = wp_remote_post( $url, $args );
565 } else {
566 $response = wp_remote_get( $url, $args );
567 }
568
569 return wp_remote_retrieve_body( $response );
570 }
571
572 }
573