WooCommerce PayPal Express Checkout Payment Gateway - Version 1.5.0

Version Description

  • Add - PayPal credit is now available on checkout.
  • Fix - WC 3.3 compatibility.
  • Add - Ability to select existing / upload new image(s) for logo / header fields.
  • Fix - Shipping address overriden when PayPal returns billing address.
Download this release

Release Info

Developer bor0
Plugin Icon 128x128 WooCommerce PayPal Express Checkout Payment Gateway
Version 1.5.0
Comparing to
See all releases

Code changes from version 1.4.7 to 1.5.0

assets/js/wc-gateway-ppec-settings.js ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ;(function ( $, window, document ) {
2
+ 'use strict';
3
+
4
+ var uploadField = {
5
+ frames: [],
6
+ init: function() {
7
+ $( 'button.image_upload' )
8
+ .on( 'click', this.onClickUploadButton );
9
+
10
+ $( 'button.image_remove' )
11
+ .on( 'click', this.removeProductImage );
12
+ },
13
+
14
+ onClickUploadButton: function( event ) {
15
+ event.preventDefault();
16
+
17
+ var data = $( event.target ).data();
18
+
19
+ // If the media frame already exists, reopen it.
20
+ if ( 'undefined' !== typeof uploadField.frames[ data.fieldId ] ) {
21
+ // Open frame.
22
+ uploadField.frames[ data.fieldId ].open();
23
+ return false;
24
+ }
25
+
26
+ // Create the media frame.
27
+ uploadField.frames[ data.fieldId ] = wp.media( {
28
+ title: data.mediaFrameTitle,
29
+ button: {
30
+ text: data.mediaFrameButton
31
+ },
32
+ multiple: false // Set to true to allow multiple files to be selected
33
+ } );
34
+
35
+ // When an image is selected, run a callback.
36
+ var context = {
37
+ fieldId: data.fieldId,
38
+ };
39
+
40
+ uploadField.frames[ data.fieldId ]
41
+ .on( 'select', uploadField.onSelectAttachment, context );
42
+
43
+ // Finally, open the modal.
44
+ uploadField.frames[ data.fieldId ].open();
45
+ },
46
+
47
+ onSelectAttachment: function() {
48
+ // We set multiple to false so only get one image from the uploader.
49
+ var attachment = uploadField.frames[ this.fieldId ]
50
+ .state()
51
+ .get( 'selection' )
52
+ .first()
53
+ .toJSON();
54
+
55
+ var $field = $( '#' + this.fieldId );
56
+ var $img = $( '<img />' )
57
+ .attr( 'src', getAttachmentUrl( attachment ) );
58
+
59
+ $field.siblings( '.image-preview-wrapper' )
60
+ .html( $img );
61
+
62
+ $field.val( attachment.id );
63
+ $field.siblings( 'button.image_remove' ).show();
64
+ $field.siblings( 'button.image_upload' ).hide();
65
+ },
66
+
67
+ removeProductImage: function( event ) {
68
+ event.preventDefault();
69
+ var $button = $( event.target );
70
+ var data = $button.data();
71
+ var $field = $( '#' + data.fieldId );
72
+
73
+ //update fields
74
+ $field.val( '' );
75
+ $field.siblings( '.image-preview-wrapper' ).html( ' ' );
76
+ $button.hide();
77
+ $field.siblings( 'button.image_upload' ).show();
78
+ },
79
+ };
80
+
81
+ function getAttachmentUrl( attachment ) {
82
+ if ( attachment.sizes && attachment.sizes.medium ) {
83
+ return attachment.sizes.medium.url;
84
+ }
85
+ if ( attachment.sizes && attachment.sizes.thumbnail ) {
86
+ return attachment.sizes.thumbnail.url;
87
+ }
88
+ return attachment.url;
89
+ }
90
+
91
+ function run() {
92
+ uploadField.init();
93
+ }
94
+
95
+ $( run );
96
+ }( jQuery ) );
includes/abstracts/abstract-wc-gateway-ppec.php CHANGED
@@ -14,7 +14,6 @@ abstract class WC_Gateway_PPEC extends WC_Payment_Gateway {
14
  */
15
  public function __construct() {
16
  $this->has_fields = false;
17
- $this->icon = 'https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-small.png';
18
  $this->supports[] = 'refunds';
19
  $this->method_title = __( 'PayPal Express Checkout', 'woocommerce-gateway-paypal-express-checkout' );
20
  $this->method_description = __( 'Allow customers to conveniently checkout directly with PayPal.', 'woocommerce-gateway-paypal-express-checkout' );
@@ -54,8 +53,8 @@ abstract class WC_Gateway_PPEC extends WC_Payment_Gateway {
54
  $this->instant_payments = 'yes' === $this->get_option( 'instant_payments', 'no' );
55
  $this->require_billing = 'yes' === $this->get_option( 'require_billing', 'no' );
56
  $this->paymentaction = $this->get_option( 'paymentaction', 'sale' );
57
- $this->logo_image_url = $this->get_option( 'logo_image_url' );
58
  $this->subtotal_mismatch_behavior = $this->get_option( 'subtotal_mismatch_behavior', 'add' );
 
59
 
60
  add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
61
 
@@ -65,6 +64,11 @@ abstract class WC_Gateway_PPEC extends WC_Payment_Gateway {
65
  $this->title = $this->get_option( 'title' );
66
  $this->description = $this->get_option( 'description' );
67
  }
 
 
 
 
 
68
  }
69
  }
70
 
@@ -93,7 +97,7 @@ abstract class WC_Gateway_PPEC extends WC_Payment_Gateway {
93
  try {
94
  return array(
95
  'result' => 'success',
96
- 'redirect' => $checkout->start_checkout_from_checkout( $order_id ),
97
  );
98
  } catch ( PayPal_API_Exception $e ) {
99
  wc_add_notice( $e->getMessage(), 'error' );
@@ -192,14 +196,6 @@ abstract class WC_Gateway_PPEC extends WC_Payment_Gateway {
192
  * Do some additonal validation before saving options via the API.
193
  */
194
  public function process_admin_options() {
195
- // Validate logo.
196
- $logo_image_url = wc_clean( $_POST['woocommerce_ppec_paypal_logo_image_url'] );
197
-
198
- if ( ! empty( $logo_image_url ) && ! preg_match( '/https?:\/\/[a-zA-Z0-9][a-zA-Z0-9.-]+[a-zA-Z0-9](\/[a-zA-Z0-9.\/?&%#]*)?/', $logo_image_url ) ) {
199
- WC_Admin_Settings::add_error( __( 'Error: The logo image URL you provided is not valid and cannot be used.', 'woocommerce-gateway-paypal-express-checkout' ) );
200
- unset( $_POST['woocommerce_ppec_paypal_logo_image_url'] );
201
- }
202
-
203
  // If a certificate has been uploaded, read the contents and save that string instead.
204
  if ( array_key_exists( 'woocommerce_ppec_paypal_api_certificate', $_FILES )
205
  && array_key_exists( 'tmp_name', $_FILES['woocommerce_ppec_paypal_api_certificate'] )
@@ -469,15 +465,90 @@ abstract class WC_Gateway_PPEC extends WC_Payment_Gateway {
469
  }
470
 
471
  /**
472
- * Whether PayPal credit is supported.
473
- *
474
- * @since 1.2.0
475
  *
476
- * @return bool Returns true if PayPal credit is supported
 
 
 
477
  */
478
- public function is_credit_supported() {
479
- $base = wc_get_base_location();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
480
 
481
- return 'US' === $base['country'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
482
  }
483
  }
14
  */
15
  public function __construct() {
16
  $this->has_fields = false;
 
17
  $this->supports[] = 'refunds';
18
  $this->method_title = __( 'PayPal Express Checkout', 'woocommerce-gateway-paypal-express-checkout' );
19
  $this->method_description = __( 'Allow customers to conveniently checkout directly with PayPal.', 'woocommerce-gateway-paypal-express-checkout' );
53
  $this->instant_payments = 'yes' === $this->get_option( 'instant_payments', 'no' );
54
  $this->require_billing = 'yes' === $this->get_option( 'require_billing', 'no' );
55
  $this->paymentaction = $this->get_option( 'paymentaction', 'sale' );
 
56
  $this->subtotal_mismatch_behavior = $this->get_option( 'subtotal_mismatch_behavior', 'add' );
57
+ $this->use_ppc = false;
58
 
59
  add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
60
 
64
  $this->title = $this->get_option( 'title' );
65
  $this->description = $this->get_option( 'description' );
66
  }
67
+ } else {
68
+ // Image upload.
69
+ wp_enqueue_media();
70
+
71
+ wp_enqueue_script( 'wc-gateway-ppec-settings', wc_gateway_ppec()->plugin_url . 'assets/js/wc-gateway-ppec-settings.js', array( 'jquery' ), wc_gateway_ppec()->version, true );
72
  }
73
  }
74
 
97
  try {
98
  return array(
99
  'result' => 'success',
100
+ 'redirect' => $checkout->start_checkout_from_checkout( $order_id, $this->use_ppc ),
101
  );
102
  } catch ( PayPal_API_Exception $e ) {
103
  wc_add_notice( $e->getMessage(), 'error' );
196
  * Do some additonal validation before saving options via the API.
197
  */
198
  public function process_admin_options() {
 
 
 
 
 
 
 
 
199
  // If a certificate has been uploaded, read the contents and save that string instead.
200
  if ( array_key_exists( 'woocommerce_ppec_paypal_api_certificate', $_FILES )
201
  && array_key_exists( 'tmp_name', $_FILES['woocommerce_ppec_paypal_api_certificate'] )
465
  }
466
 
467
  /**
468
+ * Generate Image HTML.
 
 
469
  *
470
+ * @param mixed $key
471
+ * @param mixed $data
472
+ * @since 1.5.0
473
+ * @return string
474
  */
475
+ public function generate_image_html( $key, $data ) {
476
+ $field_key = $this->get_field_key( $key );
477
+ $defaults = array(
478
+ 'title' => '',
479
+ 'disabled' => false,
480
+ 'class' => '',
481
+ 'css' => '',
482
+ 'placeholder' => '',
483
+ 'type' => 'text',
484
+ 'desc_tip' => false,
485
+ 'description' => '',
486
+ 'custom_attributes' => array(),
487
+ );
488
+
489
+ $data = wp_parse_args( $data, $defaults );
490
+ $value = $this->get_option( $key );
491
+
492
+ // Hide show add remove buttons.
493
+ $maybe_hide_add_style = '';
494
+ $maybe_hide_remove_style = '';
495
+
496
+ // For backwards compatibility (customers that already have set a url)
497
+ $value_is_url = filter_var( $value, FILTER_VALIDATE_URL ) !== false;
498
+
499
+ if ( empty( $value ) || $value_is_url ) {
500
+ $maybe_hide_remove_style = 'display: none;';
501
+ } else {
502
+ $maybe_hide_add_style = 'display: none;';
503
+ }
504
 
505
+ ob_start();
506
+ ?>
507
+ <tr valign="top">
508
+ <th scope="row" class="titledesc">
509
+ <?php echo $this->get_tooltip_html( $data ); ?>
510
+ <label for="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
511
+ </th>
512
+
513
+ <td class="image-component-wrapper">
514
+ <div class="image-preview-wrapper">
515
+ <?php
516
+ if ( ! $value_is_url ) {
517
+ echo wp_get_attachment_image( $value, 'thumbnail' );
518
+ } else {
519
+ echo sprintf( __( 'Already using URL as image: %s', 'woocommerce-gateway-paypal-express-checkout' ), $value );
520
+ }
521
+ ?>
522
+ </div>
523
+
524
+ <button
525
+ class="button image_upload"
526
+ data-field-id="<?php echo esc_attr( $field_key ); ?>"
527
+ data-media-frame-title="<?php echo esc_attr( __( 'Select a image to upload', 'woocommerce-gateway-paypal-express-checkout' ) ); ?>"
528
+ data-media-frame-button="<?php echo esc_attr( __( 'Use this image', 'woocommerce-gateway-paypal-express-checkout' ) ); ?>"
529
+ data-add-image-text="<?php echo esc_attr( __( 'Add image', 'woocommerce-gateway-paypal-express-checkout' ) ); ?>"
530
+ style="<?php echo esc_attr( $maybe_hide_add_style ); ?>"
531
+ >
532
+ <?php echo esc_html__( 'Add image', 'woocommerce-gateway-paypal-express-checkout' ); ?>
533
+ </button>
534
+
535
+ <button
536
+ class="button image_remove"
537
+ data-field-id="<?php echo esc_attr( $field_key ); ?>"
538
+ style="<?php echo esc_attr( $maybe_hide_remove_style ); ?>"
539
+ >
540
+ <?php echo esc_html__( 'Remove image', 'woocommerce-gateway-paypal-express-checkout' ); ?>
541
+ </button>
542
+
543
+ <input type="hidden"
544
+ name="<?php echo esc_attr( $field_key ); ?>"
545
+ id="<?php echo esc_attr( $field_key ); ?>"
546
+ value="<?php echo esc_attr( $value ); ?>"
547
+ />
548
+ </td>
549
+ </tr>
550
+ <?php
551
+
552
+ return ob_get_clean();
553
  }
554
  }
includes/class-wc-gateway-ppec-checkout-handler.php CHANGED
@@ -49,7 +49,6 @@ class WC_Gateway_PPEC_Checkout_Handler {
49
  add_action( 'woocommerce_review_order_after_submit', array( $this, 'maybe_render_cancel_link' ) );
50
 
51
  add_action( 'woocommerce_cart_shipping_packages', array( $this, 'maybe_add_shipping_information' ) );
52
- add_filter( 'wc_checkout_params', array( $this, 'filter_wc_checkout_params' ), 10, 1 );
53
  }
54
 
55
  /**
@@ -60,6 +59,11 @@ class WC_Gateway_PPEC_Checkout_Handler {
60
  * sending anything back to the browser.
61
  */
62
  public function init() {
 
 
 
 
 
63
  if ( isset( $_GET['startcheckout'] ) && 'true' === $_GET['startcheckout'] ) {
64
  ob_start();
65
  }
@@ -186,22 +190,30 @@ class WC_Gateway_PPEC_Checkout_Handler {
186
  }
187
 
188
  $shipping_details = $this->get_mapped_shipping_address( $checkout_details );
189
- foreach( $shipping_details as $key => $value ) {
190
- $_POST['shipping_' . $key] = $value;
191
- }
192
 
193
- $billing_details = $this->get_mapped_billing_address( $checkout_details );
194
  // If the billing address is empty, copy address from shipping
195
  if ( empty( $billing_details['address_1'] ) ) {
 
 
 
196
  $copyable_keys = array( 'address_1', 'address_2', 'city', 'state', 'postcode', 'country' );
197
  foreach ( $copyable_keys as $copyable_key ) {
198
  if ( array_key_exists( $copyable_key, $shipping_details ) ) {
199
  $billing_details[ $copyable_key ] = $shipping_details[ $copyable_key ];
200
  }
201
  }
 
 
 
202
  }
203
- foreach( $billing_details as $key => $value ) {
204
- $_POST['billing_' . $key] = $value;
 
 
 
 
 
205
  }
206
  }
207
 
@@ -237,7 +249,16 @@ class WC_Gateway_PPEC_Checkout_Handler {
237
  <?php if ( ! empty( $checkout_details->payer_details->phone_number ) ) : ?>
238
  <li><strong><?php _e( 'Phone:', 'woocommerce-gateway-paypal-express-checkout' ) ?></strong> <?php echo esc_html( $checkout_details->payer_details->phone_number ); ?></li>
239
  <?php elseif ( 'yes' === wc_gateway_ppec()->settings->require_phone_number ) : ?>
240
- <li><?php $fields = WC()->checkout->get_checkout_fields( 'billing' ); woocommerce_form_field( 'billing_phone', $fields['billing_phone'], WC()->checkout->get_value( 'billing_phone' ) ); ?></li>
 
 
 
 
 
 
 
 
 
241
  <?php endif; ?>
242
  </ul>
243
  <?php
@@ -598,74 +619,78 @@ class WC_Gateway_PPEC_Checkout_Handler {
598
  }
599
 
600
  /**
601
- * Handler when buyer is checking out from cart page.
602
  *
603
- * @todo This methods looks similar to start_checkout_from_checkout. Please
604
- * refactor by merging them.
605
  *
606
  * @throws PayPal_API_Exception
 
607
  */
608
- public function start_checkout_from_cart() {
609
  $settings = wc_gateway_ppec()->settings;
610
  $client = wc_gateway_ppec()->client;
611
- $context_args = array(
612
- 'start_from' => 'cart',
613
- );
614
  $context_args['create_billing_agreement'] = $this->needs_billing_agreement_creation( $context_args );
615
 
616
  $params = $client->get_set_express_checkout_params( $context_args );
617
  $response = $client->set_express_checkout( $params );
 
618
  if ( $client->response_has_success_status( $response ) ) {
619
- WC()->session->paypal = new WC_Gateway_PPEC_Session_Data(
620
- array(
621
- 'token' => $response['TOKEN'],
622
- 'source' => 'cart',
623
- 'expires_in' => $settings->get_token_session_length(),
624
- 'use_paypal_credit' => wc_gateway_ppec_is_using_credit(),
625
- )
626
- );
627
 
628
- return $settings->get_paypal_redirect_url( $response['TOKEN'], false );
629
  } else {
630
  throw new PayPal_API_Exception( $response );
631
  }
632
  }
633
 
634
  /**
635
- * Handler when buyer is checking out from checkout page.
636
  *
637
- * @todo This methods looks similar to start_checkout_from_cart. Please
638
- * refactor by merging them.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
639
  *
640
- * @throws PayPal_API_Exception
 
641
  *
642
- * @param int $order_id Order ID
643
  */
644
- public function start_checkout_from_checkout( $order_id ) {
645
  $settings = wc_gateway_ppec()->settings;
646
- $client = wc_gateway_ppec()->client;
647
  $context_args = array(
648
  'start_from' => 'checkout',
649
  'order_id' => $order_id,
650
  );
651
- $context_args['create_billing_agreement'] = $this->needs_billing_agreement_creation( $context_args );
652
 
653
- $params = $client->get_set_express_checkout_params( $context_args );
654
- $response = $client->set_express_checkout( $params );
655
- if ( $client->response_has_success_status( $response ) ) {
656
- WC()->session->paypal = new WC_Gateway_PPEC_Session_Data(
657
- array(
658
- 'token' => $response['TOKEN'],
659
- 'source' => 'order',
660
- 'order_id' => $order_id,
661
- 'expires_in' => $settings->get_token_session_length()
662
- )
663
- );
664
 
665
- return $settings->get_paypal_redirect_url( $response['TOKEN'], true );
666
- } else {
667
- throw new PayPal_API_Exception( $response );
668
- }
669
  }
670
 
671
  /**
@@ -881,15 +906,14 @@ class WC_Gateway_PPEC_Checkout_Handler {
881
  if ( empty( $_GET['woo-paypal-return'] ) || empty( $_GET['token'] ) || empty( $_GET['PayerID'] ) ) {
882
  return $packages;
883
  }
884
- // Shipping details from PayPal
885
 
 
886
  try {
887
  $checkout_details = $this->get_checkout_details( wc_clean( $_GET['token'] ) );
888
  } catch ( PayPal_API_Exception $e ) {
889
  return $packages;
890
  }
891
 
892
-
893
  $destination = $this->get_mapped_shipping_address( $checkout_details );
894
 
895
  $packages[0]['destination']['country'] = $destination['country'];
@@ -971,11 +995,16 @@ class WC_Gateway_PPEC_Checkout_Handler {
971
  *
972
  * @since 1.4.7
973
  *
974
- * @param array $params
 
975
  *
976
  * @return string URL.
977
  */
978
- public function filter_wc_checkout_params( $params ) {
 
 
 
 
979
  $fields = array( 'woo-paypal-return', 'token', 'PayerID' );
980
 
981
  $params['wc_ajax_url'] = remove_query_arg( 'wc-ajax', $params['wc_ajax_url'] );
49
  add_action( 'woocommerce_review_order_after_submit', array( $this, 'maybe_render_cancel_link' ) );
50
 
51
  add_action( 'woocommerce_cart_shipping_packages', array( $this, 'maybe_add_shipping_information' ) );
 
52
  }
53
 
54
  /**
59
  * sending anything back to the browser.
60
  */
61
  public function init() {
62
+ if ( version_compare( WC_VERSION, '3.3', '<' ) ) {
63
+ add_filter( 'wc_checkout_params', array( $this, 'filter_wc_checkout_params' ), 10, 1 );
64
+ } else {
65
+ add_filter( 'woocommerce_get_script_data', array( $this, 'filter_wc_checkout_params' ), 10, 2 );
66
+ }
67
  if ( isset( $_GET['startcheckout'] ) && 'true' === $_GET['startcheckout'] ) {
68
  ob_start();
69
  }
190
  }
191
 
192
  $shipping_details = $this->get_mapped_shipping_address( $checkout_details );
193
+ $billing_details = $this->get_mapped_billing_address( $checkout_details );
 
 
194
 
 
195
  // If the billing address is empty, copy address from shipping
196
  if ( empty( $billing_details['address_1'] ) ) {
197
+ // Set flag so that WC copies billing to shipping
198
+ $_POST['ship_to_different_address'] = 0;
199
+
200
  $copyable_keys = array( 'address_1', 'address_2', 'city', 'state', 'postcode', 'country' );
201
  foreach ( $copyable_keys as $copyable_key ) {
202
  if ( array_key_exists( $copyable_key, $shipping_details ) ) {
203
  $billing_details[ $copyable_key ] = $shipping_details[ $copyable_key ];
204
  }
205
  }
206
+ } else {
207
+ // Shipping may be different from billing, so set flag to not copy address from billing
208
+ $_POST['ship_to_different_address'] = 1;
209
  }
210
+
211
+ foreach ( $shipping_details as $key => $value ) {
212
+ $_POST[ 'shipping_' . $key ] = $value;
213
+ }
214
+
215
+ foreach ( $billing_details as $key => $value ) {
216
+ $_POST[ 'billing_' . $key ] = $value;
217
  }
218
  }
219
 
249
  <?php if ( ! empty( $checkout_details->payer_details->phone_number ) ) : ?>
250
  <li><strong><?php _e( 'Phone:', 'woocommerce-gateway-paypal-express-checkout' ) ?></strong> <?php echo esc_html( $checkout_details->payer_details->phone_number ); ?></li>
251
  <?php elseif ( 'yes' === wc_gateway_ppec()->settings->require_phone_number ) : ?>
252
+ <li>
253
+ <?php
254
+ if ( version_compare( WC_VERSION, '3.0', '<' ) ) {
255
+ $fields = WC()->checkout->checkout_fields['billing'];
256
+ } else {
257
+ $fields = WC()->checkout->get_checkout_fields( 'billing' );
258
+ }
259
+ woocommerce_form_field( 'billing_phone', $fields['billing_phone'], WC()->checkout->get_value( 'billing_phone' ) );
260
+ ?>
261
+ </li>
262
  <?php endif; ?>
263
  </ul>
264
  <?php
619
  }
620
 
621
  /**
622
+ * Generic checkout handler.
623
  *
624
+ * @param array $context_args Context parameters for checkout.
625
+ * @param array $session_data_args Session parameters (token pre-populated).
626
  *
627
  * @throws PayPal_API_Exception
628
+ * @return string Redirect URL.
629
  */
630
+ protected function start_checkout( $context_args, $session_data_args ) {
631
  $settings = wc_gateway_ppec()->settings;
632
  $client = wc_gateway_ppec()->client;
 
 
 
633
  $context_args['create_billing_agreement'] = $this->needs_billing_agreement_creation( $context_args );
634
 
635
  $params = $client->get_set_express_checkout_params( $context_args );
636
  $response = $client->set_express_checkout( $params );
637
+
638
  if ( $client->response_has_success_status( $response ) ) {
639
+ $session_data_args['token'] = $response['TOKEN'];
640
+
641
+ WC()->session->paypal = new WC_Gateway_PPEC_Session_Data( $session_data_args );
 
 
 
 
 
642
 
643
+ return $settings->get_paypal_redirect_url( $response['TOKEN'], false, $session_data_args['use_paypal_credit'] );
644
  } else {
645
  throw new PayPal_API_Exception( $response );
646
  }
647
  }
648
 
649
  /**
650
+ * Handler when buyer is checking out from cart page.
651
  *
652
+ * @return string Redirect URL.
653
+ */
654
+ public function start_checkout_from_cart() {
655
+ $settings = wc_gateway_ppec()->settings;
656
+
657
+ $context_args = array(
658
+ 'start_from' => 'cart',
659
+ );
660
+
661
+ $session_data_args = array(
662
+ 'source' => 'cart',
663
+ 'expires_in' => $settings->get_token_session_length(),
664
+ 'use_paypal_credit' => wc_gateway_ppec_is_using_credit(),
665
+ );
666
+
667
+ return $this->start_checkout( $context_args, $session_data_args );
668
+ }
669
+
670
+ /**
671
+ * Handler when buyer is checking out from checkout page.
672
  *
673
+ * @param int $order_id Order ID.
674
+ * @param bool $use_ppc Whether to use PayPal credit.
675
  *
676
+ * @return string Redirect URL.
677
  */
678
+ public function start_checkout_from_checkout( $order_id, $use_ppc ) {
679
  $settings = wc_gateway_ppec()->settings;
680
+
681
  $context_args = array(
682
  'start_from' => 'checkout',
683
  'order_id' => $order_id,
684
  );
 
685
 
686
+ $session_data_args = array(
687
+ 'source' => 'order',
688
+ 'order_id' => $order_id,
689
+ 'expires_in' => $settings->get_token_session_length(),
690
+ 'use_paypal_credit' => $use_ppc,
691
+ );
 
 
 
 
 
692
 
693
+ return $this->start_checkout( $context_args, $session_data_args );
 
 
 
694
  }
695
 
696
  /**
906
  if ( empty( $_GET['woo-paypal-return'] ) || empty( $_GET['token'] ) || empty( $_GET['PayerID'] ) ) {
907
  return $packages;
908
  }
 
909
 
910
+ // Shipping details from PayPal
911
  try {
912
  $checkout_details = $this->get_checkout_details( wc_clean( $_GET['token'] ) );
913
  } catch ( PayPal_API_Exception $e ) {
914
  return $packages;
915
  }
916
 
 
917
  $destination = $this->get_mapped_shipping_address( $checkout_details );
918
 
919
  $packages[0]['destination']['country'] = $destination['country'];
995
  *
996
  * @since 1.4.7
997
  *
998
+ * @param array $params
999
+ * @param string $handle
1000
  *
1001
  * @return string URL.
1002
  */
1003
+ public function filter_wc_checkout_params( $params, $handle = '' ) {
1004
+ if ( 'wc-checkout' !== $handle && ! doing_action( 'wc_checkout_params' ) ) {
1005
+ return $params;
1006
+ }
1007
+
1008
  $fields = array( 'woo-paypal-return', 'token', 'PayerID' );
1009
 
1010
  $params['wc_ajax_url'] = remove_query_arg( 'wc-ajax', $params['wc_ajax_url'] );
includes/class-wc-gateway-ppec-client.php CHANGED
@@ -248,8 +248,10 @@ class WC_Gateway_PPEC_Client {
248
  $settings = wc_gateway_ppec()->settings;
249
 
250
  $params = array();
251
- $params['LOGOIMG'] = $settings->logo_image_url;
252
- $params['HDRIMG'] = $settings->header_image_url;
 
 
253
  $params['PAGESTYLE'] = $settings->page_style;
254
  $params['BRANDNAME'] = $settings->get_brand_name();
255
  $params['RETURNURL'] = $this->_get_return_url( $args );
@@ -794,13 +796,14 @@ class WC_Gateway_PPEC_Client {
794
  * @return array Params for DoExpressCheckoutPayment call
795
  */
796
  public function get_do_express_checkout_params( array $args ) {
797
- $settings = wc_gateway_ppec()->settings;
798
- $order = wc_get_order( $args['order_id'] );
799
 
800
- $old_wc = version_compare( WC_VERSION, '3.0', '<' );
801
- $order_id = $old_wc ? $order->id : $order->get_id();
802
- $details = $this->_get_details_from_order( $order_id );
803
- $order_key = $old_wc ? $order->order_key : $order->get_order_key();
 
804
 
805
  $params = array(
806
  'TOKEN' => $args['token'],
@@ -817,8 +820,9 @@ class WC_Gateway_PPEC_Client {
817
  'PAYMENTREQUEST_0_PAYMENTACTION' => $settings->get_paymentaction(),
818
  'PAYMENTREQUEST_0_INVNUM' => $settings->invoice_prefix . $order->get_order_number(),
819
  'PAYMENTREQUEST_0_CUSTOM' => json_encode( array(
820
- 'order_id' => $order_id,
821
- 'order_key' => $order_key,
 
822
  ) ),
823
  'NOSHIPPING' => WC_Gateway_PPEC_Plugin::needs_shipping() ? 0 : 1,
824
  );
248
  $settings = wc_gateway_ppec()->settings;
249
 
250
  $params = array();
251
+ $logo_url_or_id = $settings->logo_image_url;
252
+ $header_url_or_id = $settings->header_image_url;
253
+ $params['LOGOIMG'] = filter_var( $logo_url_or_id, FILTER_VALIDATE_URL ) ? $logo_url_or_id : wp_get_attachment_image( $logo_url_or_id, 'thumbnail' );
254
+ $params['HDRIMG'] = filter_var( $header_url_or_id, FILTER_VALIDATE_URL ) ? $header_url_or_id : wp_get_attachment_image( $header_url_or_id, 'thumbnail' );
255
  $params['PAGESTYLE'] = $settings->page_style;
256
  $params['BRANDNAME'] = $settings->get_brand_name();
257
  $params['RETURNURL'] = $this->_get_return_url( $args );
796
  * @return array Params for DoExpressCheckoutPayment call
797
  */
798
  public function get_do_express_checkout_params( array $args ) {
799
+ $settings = wc_gateway_ppec()->settings;
800
+ $order = wc_get_order( $args['order_id'] );
801
 
802
+ $old_wc = version_compare( WC_VERSION, '3.0', '<' );
803
+ $order_id = $old_wc ? $order->id : $order->get_id();
804
+ $order_number = $order->get_order_number();
805
+ $details = $this->_get_details_from_order( $order_id );
806
+ $order_key = $old_wc ? $order->order_key : $order->get_order_key();
807
 
808
  $params = array(
809
  'TOKEN' => $args['token'],
820
  'PAYMENTREQUEST_0_PAYMENTACTION' => $settings->get_paymentaction(),
821
  'PAYMENTREQUEST_0_INVNUM' => $settings->invoice_prefix . $order->get_order_number(),
822
  'PAYMENTREQUEST_0_CUSTOM' => json_encode( array(
823
+ 'order_id' => $order_id,
824
+ 'order_number' => $order_number,
825
+ 'order_key' => $order_key,
826
  ) ),
827
  'NOSHIPPING' => WC_Gateway_PPEC_Plugin::needs_shipping() ? 0 : 1,
828
  );
includes/class-wc-gateway-ppec-gateway-loader.php CHANGED
@@ -19,6 +19,7 @@ class WC_Gateway_PPEC_Gateway_Loader {
19
  require_once( $includes_path . 'abstracts/abstract-wc-gateway-ppec.php' );
20
 
21
  require_once( $includes_path . 'class-wc-gateway-ppec-with-paypal.php' );
 
22
  require_once( $includes_path . 'class-wc-gateway-ppec-with-paypal-addons.php' );
23
 
24
  add_filter( 'woocommerce_payment_gateways', array( $this, 'payment_gateways' ) );
@@ -32,12 +33,18 @@ class WC_Gateway_PPEC_Gateway_Loader {
32
  * @return array Payment methods
33
  */
34
  public function payment_gateways( $methods ) {
 
 
35
  if ( $this->can_use_addons() ) {
36
  $methods[] = 'WC_Gateway_PPEC_With_PayPal_Addons';
37
  } else {
38
  $methods[] = 'WC_Gateway_PPEC_With_PayPal';
39
  }
40
 
 
 
 
 
41
  return $methods;
42
  }
43
 
19
  require_once( $includes_path . 'abstracts/abstract-wc-gateway-ppec.php' );
20
 
21
  require_once( $includes_path . 'class-wc-gateway-ppec-with-paypal.php' );
22
+ require_once( $includes_path . 'class-wc-gateway-ppec-with-paypal-credit.php' );
23
  require_once( $includes_path . 'class-wc-gateway-ppec-with-paypal-addons.php' );
24
 
25
  add_filter( 'woocommerce_payment_gateways', array( $this, 'payment_gateways' ) );
33
  * @return array Payment methods
34
  */
35
  public function payment_gateways( $methods ) {
36
+ $settings = wc_gateway_ppec()->settings;
37
+
38
  if ( $this->can_use_addons() ) {
39
  $methods[] = 'WC_Gateway_PPEC_With_PayPal_Addons';
40
  } else {
41
  $methods[] = 'WC_Gateway_PPEC_With_PayPal';
42
  }
43
 
44
+ if ( $settings->is_credit_enabled() ) {
45
+ $methods[] = 'WC_Gateway_PPEC_With_PayPal_Credit';
46
+ }
47
+
48
  return $methods;
49
  }
50
 
includes/class-wc-gateway-ppec-settings.php CHANGED
@@ -157,10 +157,11 @@ class WC_Gateway_PPEC_Settings {
157
  * to 'commit' which makes PayPal sets the button text
158
  * to **Pay Now** ont the PayPal _Review your information_
159
  * page.
 
160
  *
161
  * @return string PayPal redirect URL
162
  */
163
- public function get_paypal_redirect_url( $token, $commit = false ) {
164
  $url = 'https://www.';
165
 
166
  if ( 'live' !== $this->environment ) {
@@ -173,6 +174,10 @@ class WC_Gateway_PPEC_Settings {
173
  $url .= '&useraction=commit';
174
  }
175
 
 
 
 
 
176
  return $url;
177
  }
178
 
@@ -345,12 +350,7 @@ class WC_Gateway_PPEC_Settings {
345
  * @return bool Returns true if PayPal Credit is enabled and supported
346
  */
347
  public function is_credit_enabled() {
348
- $gateways = WC()->payment_gateways->get_available_payment_gateways();
349
- if ( ! isset( $gateways['ppec_paypal'] ) ) {
350
- return false;
351
- }
352
-
353
- return 'yes' === $this->credit_enabled && $gateways['ppec_paypal']->is_credit_supported();
354
  }
355
 
356
  /**
157
  * to 'commit' which makes PayPal sets the button text
158
  * to **Pay Now** ont the PayPal _Review your information_
159
  * page.
160
+ * @param bool $ppc Whether to use PayPal credit.
161
  *
162
  * @return string PayPal redirect URL
163
  */
164
+ public function get_paypal_redirect_url( $token, $commit = false, $ppc = false ) {
165
  $url = 'https://www.';
166
 
167
  if ( 'live' !== $this->environment ) {
174
  $url .= '&useraction=commit';
175
  }
176
 
177
+ if ( $ppc ) {
178
+ $url .= '#/checkout/chooseCreditOffer';
179
+ }
180
+
181
  return $url;
182
  }
183
 
350
  * @return bool Returns true if PayPal Credit is enabled and supported
351
  */
352
  public function is_credit_enabled() {
353
+ return 'yes' === $this->credit_enabled && wc_gateway_ppec_is_credit_supported();
 
 
 
 
 
354
  }
355
 
356
  /**
includes/class-wc-gateway-ppec-with-paypal-credit.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly
5
+ }
6
+
7
+ class WC_Gateway_PPEC_With_PayPal_Credit extends WC_Gateway_PPEC {
8
+ public function __construct() {
9
+ $this->icon = 'https://www.paypalobjects.com/webstatic/en_US/i/buttons/ppc-acceptance-small.png';
10
+
11
+ parent::__construct();
12
+
13
+ if ( ! is_admin() ) {
14
+ if ( wc_gateway_ppec()->checkout->is_started_from_checkout_page() ) {
15
+ $this->title = __( 'PayPal Credit', 'woocommerce-gateway-paypal-express-checkout' );;
16
+ }
17
+ }
18
+
19
+ if ( $this->is_available() ) {
20
+ $ipn_handler = new WC_Gateway_PPEC_IPN_Handler( $this );
21
+ $ipn_handler->handle();
22
+ }
23
+
24
+ $this->use_ppc = true;
25
+ }
26
+ }
includes/class-wc-gateway-ppec-with-paypal.php CHANGED
@@ -6,7 +6,8 @@ if ( ! defined( 'ABSPATH' ) ) {
6
 
7
  class WC_Gateway_PPEC_With_PayPal extends WC_Gateway_PPEC {
8
  public function __construct() {
9
- $this->id = 'ppec_paypal';
 
10
 
11
  parent::__construct();
12
 
6
 
7
  class WC_Gateway_PPEC_With_PayPal extends WC_Gateway_PPEC {
8
  public function __construct() {
9
+ $this->id = 'ppec_paypal';
10
+ $this->icon = 'https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-small.png';
11
 
12
  parent::__construct();
13
 
includes/functions.php CHANGED
@@ -68,6 +68,19 @@ function wc_gateway_ppec_log( $message ) {
68
  }
69
  }
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  /**
72
  * Checks whether buyer is checking out with PayPal Credit.
73
  *
68
  }
69
  }
70
 
71
+ /**
72
+ * Whether PayPal credit is supported.
73
+ *
74
+ * @since 1.5.0
75
+ *
76
+ * @return bool Returns true if PayPal credit is supported
77
+ */
78
+ function wc_gateway_ppec_is_credit_supported() {
79
+ $base = wc_get_base_location();
80
+
81
+ return 'US' === $base['country'];
82
+ }
83
+
84
  /**
85
  * Checks whether buyer is checking out with PayPal Credit.
86
  *
includes/settings/settings-ppec.php CHANGED
@@ -44,7 +44,7 @@ if ( $enable_ips && $needs_sandbox_creds ) {
44
  }
45
 
46
  $credit_enabled_label = __( 'Enable PayPal Credit', 'woocommerce-gateway-paypal-express-checkout' );
47
- if ( ! $this->is_credit_supported() ) {
48
  $credit_enabled_label .= '<p><em>' . __( 'This option is disabled. Currently PayPal Credit only available for U.S. merchants.', 'woocommerce-gateway-paypal-express-checkout' ) . '</em></p>';
49
  }
50
 
@@ -281,7 +281,7 @@ return array(
281
  ),
282
  'logo_image_url' => array(
283
  'title' => __( 'Logo Image (190×60)', 'woocommerce-gateway-paypal-express-checkout' ),
284
- 'type' => 'text',
285
  'description' => __( 'If you want PayPal to co-brand the checkout page with your logo, enter the URL of your logo image here.<br/>The image must be no larger than 190x60, GIF, PNG, or JPG format, and should be served over HTTPS.', 'woocommerce-gateway-paypal-express-checkout' ),
286
  'default' => '',
287
  'desc_tip' => true,
@@ -289,7 +289,7 @@ return array(
289
  ),
290
  'header_image_url' => array(
291
  'title' => __( 'Header Image (750×90)', 'woocommerce-gateway-paypal-express-checkout' ),
292
- 'type' => 'text',
293
  'description' => __( 'If you want PayPal to co-brand the checkout page with your header, enter the URL of your header image here.<br/>The image must be no larger than 750x90, GIF, PNG, or JPG format, and should be served over HTTPS.', 'woocommerce-gateway-paypal-express-checkout' ),
294
  'default' => '',
295
  'desc_tip' => true,
@@ -319,7 +319,7 @@ return array(
319
  'title' => __( 'Enable PayPal Credit', 'woocommerce-gateway-paypal-express-checkout' ),
320
  'type' => 'checkbox',
321
  'label' => $credit_enabled_label,
322
- 'disabled' => ! $this->is_credit_supported(),
323
  'default' => 'no',
324
  'desc_tip' => true,
325
  'description' => __( 'This enables PayPal Credit, which displays a PayPal Credit button next to the Express Checkout button. PayPal Express Checkout lets you give customers access to financing through PayPal Credit® - at no additional cost to you. You get paid up front, even though customers have more time to pay. A pre-integrated payment button shows up next to the PayPal Button, and lets customers pay quickly with PayPal Credit®.', 'woocommerce-gateway-paypal-express-checkout' ),
44
  }
45
 
46
  $credit_enabled_label = __( 'Enable PayPal Credit', 'woocommerce-gateway-paypal-express-checkout' );
47
+ if ( ! wc_gateway_ppec_is_credit_supported() ) {
48
  $credit_enabled_label .= '<p><em>' . __( 'This option is disabled. Currently PayPal Credit only available for U.S. merchants.', 'woocommerce-gateway-paypal-express-checkout' ) . '</em></p>';
49
  }
50
 
281
  ),
282
  'logo_image_url' => array(
283
  'title' => __( 'Logo Image (190×60)', 'woocommerce-gateway-paypal-express-checkout' ),
284
+ 'type' => 'image',
285
  'description' => __( 'If you want PayPal to co-brand the checkout page with your logo, enter the URL of your logo image here.<br/>The image must be no larger than 190x60, GIF, PNG, or JPG format, and should be served over HTTPS.', 'woocommerce-gateway-paypal-express-checkout' ),
286
  'default' => '',
287
  'desc_tip' => true,
289
  ),
290
  'header_image_url' => array(
291
  'title' => __( 'Header Image (750×90)', 'woocommerce-gateway-paypal-express-checkout' ),
292
+ 'type' => 'image',
293
  'description' => __( 'If you want PayPal to co-brand the checkout page with your header, enter the URL of your header image here.<br/>The image must be no larger than 750x90, GIF, PNG, or JPG format, and should be served over HTTPS.', 'woocommerce-gateway-paypal-express-checkout' ),
294
  'default' => '',
295
  'desc_tip' => true,
319
  'title' => __( 'Enable PayPal Credit', 'woocommerce-gateway-paypal-express-checkout' ),
320
  'type' => 'checkbox',
321
  'label' => $credit_enabled_label,
322
+ 'disabled' => ! wc_gateway_ppec_is_credit_supported(),
323
  'default' => 'no',
324
  'desc_tip' => true,
325
  'description' => __( 'This enables PayPal Credit, which displays a PayPal Credit button next to the Express Checkout button. PayPal Express Checkout lets you give customers access to financing through PayPal Credit® - at no additional cost to you. You get paid up front, even though customers have more time to pay. A pre-integrated payment button shows up next to the PayPal Button, and lets customers pay quickly with PayPal Credit®.', 'woocommerce-gateway-paypal-express-checkout' ),
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: automattic, woothemes, akeda, dwainm, royho, allendav, slash1andy,
3
  Tags: ecommerce, e-commerce, commerce, woothemes, wordpress ecommerce, store, sales, sell, shop, shopping, cart, checkout, configurable, paypal
4
  Requires at least: 4.4
5
  Tested up to: 4.9.0
6
- Stable tag: 1.4.7
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
@@ -85,6 +85,12 @@ https://gist.github.com/mikejolley/ad2ecc286c9ad6cefbb7065ba6dfef48
85
 
86
  == Changelog ==
87
 
 
 
 
 
 
 
88
  = 1.4.7 =
89
  * Fix - Issue with missing paypal session information.
90
  * Fix - Dependency error when using LibreSSL.
3
  Tags: ecommerce, e-commerce, commerce, woothemes, wordpress ecommerce, store, sales, sell, shop, shopping, cart, checkout, configurable, paypal
4
  Requires at least: 4.4
5
  Tested up to: 4.9.0
6
+ Stable tag: 1.5.0
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
85
 
86
  == Changelog ==
87
 
88
+ = 1.5.0 =
89
+ * Add - PayPal credit is now available on checkout.
90
+ * Fix - WC 3.3 compatibility.
91
+ * Add - Ability to select existing / upload new image(s) for logo / header fields.
92
+ * Fix - Shipping address overriden when PayPal returns billing address.
93
+
94
  = 1.4.7 =
95
  * Fix - Issue with missing paypal session information.
96
  * Fix - Dependency error when using LibreSSL.
woocommerce-gateway-paypal-express-checkout.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: WooCommerce PayPal Express Checkout Gateway
4
  * Plugin URI: https://woocommerce.com/products/woocommerce-gateway-paypal-express-checkout/
5
  * Description: A payment gateway for PayPal Express Checkout (https://www.paypal.com/us/webapps/mpp/express-checkout).
6
- * Version: 1.4.7
7
  * Author: WooCommerce
8
  * Author URI: https://woocommerce.com
9
  * Copyright: © 2017 WooCommerce / PayPal.
@@ -11,7 +11,7 @@
11
  * License URI: http://www.gnu.org/licenses/gpl-3.0.html
12
  * Text Domain: woocommerce-gateway-paypal-express-checkout
13
  * Domain Path: /languages
14
- * WC tested up to: 3.2
15
  * WC requires at least: 2.6
16
  */
17
  /**
@@ -27,7 +27,7 @@ if ( ! defined( 'ABSPATH' ) ) {
27
  exit; // Exit if accessed directly
28
  }
29
 
30
- define( 'WC_GATEWAY_PPEC_VERSION', '1.4.7' );
31
 
32
  /**
33
  * Return instance of WC_Gateway_PPEC_Plugin.
3
  * Plugin Name: WooCommerce PayPal Express Checkout Gateway
4
  * Plugin URI: https://woocommerce.com/products/woocommerce-gateway-paypal-express-checkout/
5
  * Description: A payment gateway for PayPal Express Checkout (https://www.paypal.com/us/webapps/mpp/express-checkout).
6
+ * Version: 1.5.0
7
  * Author: WooCommerce
8
  * Author URI: https://woocommerce.com
9
  * Copyright: © 2017 WooCommerce / PayPal.
11
  * License URI: http://www.gnu.org/licenses/gpl-3.0.html
12
  * Text Domain: woocommerce-gateway-paypal-express-checkout
13
  * Domain Path: /languages
14
+ * WC tested up to: 3.3
15
  * WC requires at least: 2.6
16
  */
17
  /**
27
  exit; // Exit if accessed directly
28
  }
29
 
30
+ define( 'WC_GATEWAY_PPEC_VERSION', '1.5.0' );
31
 
32
  /**
33
  * Return instance of WC_Gateway_PPEC_Plugin.