WooCommerce PayPal Express Checkout Payment Gateway - Version 1.6.4

Version Description

  • 2018-09-27 =
  • Fix - Billing address from Checkout form not being passed to PayPal via Smart Payment Button.
  • Fix - Checkout form not being validated until after Smart Payment Button payment flow.
Download this release

Release Info

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

Code changes from version 1.6.3 to 1.6.4

assets/js/wc-gateway-ppec-smart-payment-buttons.js CHANGED
@@ -2,6 +2,39 @@
2
  ;( function ( $, window, document ) {
3
  'use strict';
4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  // Map funding method settings to enumerated options provided by PayPal.
6
  var getFundingMethods = function( methods ) {
7
  if ( ! methods ) {
@@ -68,19 +101,26 @@
68
  }
69
  } ).then( function() {
70
  // Make PayPal Checkout initialization request.
 
 
 
 
 
 
 
 
 
71
  return paypal.request( {
72
  method: 'post',
73
  url: wc_ppec_context.start_checkout_url,
74
- data: {
75
- 'nonce': wc_ppec_context.start_checkout_nonce,
76
- 'from_checkout': 'checkout' === wc_ppec_context.page && ! isMiniCart ? 'yes' : 'no',
77
- },
78
  } ).then( function( response ) {
79
  if ( ! response.success ) {
80
- // Render error notice inside button container.
81
- var $message = $( '<ul class="woocommerce-error" role="alert">' )
82
- .append( $( '<li>' ).text( response.data.message ) );
83
- $( selector ).prepend( $message );
 
84
  return null;
85
  }
86
  return response.data.token;
2
  ;( function ( $, window, document ) {
3
  'use strict';
4
 
5
+ // Show error notice at top of checkout form, or else within button container
6
+ var showError = function( errorMessage, selector ) {
7
+ var $container = $( '.woocommerce-notices-wrapper, form.checkout' );
8
+
9
+ if ( ! $container || ! $container.length ) {
10
+ $( selector ).prepend( errorMessage );
11
+ return;
12
+ } else {
13
+ $container = $container.first();
14
+ }
15
+
16
+ // Adapted from https://github.com/woocommerce/woocommerce/blob/ea9aa8cd59c9fa735460abf0ebcb97fa18f80d03/assets/js/frontend/checkout.js#L514-L529
17
+ $( '.woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message' ).remove();
18
+ $container.prepend( '<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-checkout">' + errorMessage + '</div>' );
19
+ $container.find( '.input-text, select, input:checkbox' ).trigger( 'validate' ).blur();
20
+
21
+ var scrollElement = $( '.woocommerce-NoticeGroup-checkout' );
22
+ if ( ! scrollElement.length ) {
23
+ scrollElement = $container;
24
+ }
25
+
26
+ if ( $.scroll_to_notices ) {
27
+ $.scroll_to_notices( scrollElement );
28
+ } else {
29
+ // Compatibility with WC <3.3
30
+ $( 'html, body' ).animate( {
31
+ scrollTop: ( $container.offset().top - 100 )
32
+ }, 1000 );
33
+ }
34
+
35
+ $( document.body ).trigger( 'checkout_error' );
36
+ }
37
+
38
  // Map funding method settings to enumerated options provided by PayPal.
39
  var getFundingMethods = function( methods ) {
40
  if ( ! methods ) {
101
  }
102
  } ).then( function() {
103
  // Make PayPal Checkout initialization request.
104
+ var data = $( selector ).closest( 'form' )
105
+ .add( $( '<input type="hidden" name="nonce" /> ' )
106
+ .attr( 'value', wc_ppec_context.start_checkout_nonce )
107
+ )
108
+ .add( $( '<input type="hidden" name="from_checkout" /> ' )
109
+ .attr( 'value', 'checkout' === wc_ppec_context.page && ! isMiniCart ? 'yes' : 'no' )
110
+ )
111
+ .serialize();
112
+
113
  return paypal.request( {
114
  method: 'post',
115
  url: wc_ppec_context.start_checkout_url,
116
+ body: data,
 
 
 
117
  } ).then( function( response ) {
118
  if ( ! response.success ) {
119
+ var messageItems = response.data.messages.map( function( message ) {
120
+ return '<li>' + message + '</li>';
121
+ } ).join( '' );
122
+
123
+ showError( '<ul class="woocommerce-error" role="alert">' + messageItems + '</ul>', selector );
124
  return null;
125
  }
126
  return response.data.token;
changelog.txt CHANGED
@@ -1,5 +1,9 @@
1
  *** Changelog ***
2
 
 
 
 
 
3
  = 1.6.3 - 2018-08-15 =
4
  * Fix - Fatal error caused by a fix for Smart Payment Buttons.
5
 
1
  *** Changelog ***
2
 
3
+ = 1.6.4 - 2018-09-27 =
4
+ * Fix - Billing address from Checkout form not being passed to PayPal via Smart Payment Button.
5
+ * Fix - Checkout form not being validated until after Smart Payment Button payment flow.
6
+
7
  = 1.6.3 - 2018-08-15 =
8
  * Fix - Fatal error caused by a fix for Smart Payment Buttons.
9
 
includes/class-wc-gateway-ppec-cart-handler.php CHANGED
@@ -126,7 +126,7 @@ class WC_Gateway_PPEC_Cart_Handler {
126
  }
127
 
128
  /**
129
- * Set Express Checkout and return token in response.
130
  *
131
  * @since 1.6.0
132
  */
@@ -137,13 +137,115 @@ class WC_Gateway_PPEC_Cart_Handler {
137
 
138
  if ( isset( $_POST['from_checkout'] ) && 'yes' === $_POST['from_checkout'] ) {
139
  add_filter( 'woocommerce_cart_needs_shipping', '__return_false' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  }
141
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  try {
143
  wc_gateway_ppec()->checkout->start_checkout_from_cart();
144
  wp_send_json_success( array( 'token' => WC()->session->paypal->token ) );
145
  } catch( PayPal_API_Exception $e ) {
146
- wp_send_json_error( array( 'message' => $e->getMessage() ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  }
148
  }
149
 
126
  }
127
 
128
  /**
129
+ * Handle AJAX request to start checkout flow, first triggering form validation if necessary.
130
  *
131
  * @since 1.6.0
132
  */
137
 
138
  if ( isset( $_POST['from_checkout'] ) && 'yes' === $_POST['from_checkout'] ) {
139
  add_filter( 'woocommerce_cart_needs_shipping', '__return_false' );
140
+
141
+ // Intercept process_checkout call to exit after validation.
142
+ add_action( 'woocommerce_after_checkout_validation', array( $this, 'maybe_start_checkout' ), 10, 2 );
143
+ WC()->checkout->process_checkout();
144
+ } else {
145
+ $this->start_checkout();
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Report validation errors if any, or else save form data in session and proceed with checkout flow.
151
+ *
152
+ * @since 1.6.4
153
+ */
154
+ public function maybe_start_checkout( $data, $errors = null ) {
155
+ if ( is_null( $errors ) ) {
156
+ // Compatibility with WC <3.0: get notices and clear them so they don't re-appear.
157
+ $error_messages = wc_get_notices( 'error' );
158
+ wc_clear_notices();
159
+ } else {
160
+ $error_messages = $errors->get_error_messages();
161
  }
162
 
163
+ if ( empty( $error_messages ) ) {
164
+ $this->set_customer_data( $_POST );
165
+ $this->start_checkout();
166
+ } else {
167
+ wp_send_json_error( array( 'messages' => $error_messages ) );
168
+ }
169
+ exit;
170
+ }
171
+
172
+ /**
173
+ * Set Express Checkout and return token in response.
174
+ *
175
+ * @since 1.6.4
176
+ */
177
+ protected function start_checkout() {
178
  try {
179
  wc_gateway_ppec()->checkout->start_checkout_from_cart();
180
  wp_send_json_success( array( 'token' => WC()->session->paypal->token ) );
181
  } catch( PayPal_API_Exception $e ) {
182
+ wp_send_json_error( array( 'messages' => array( $e->getMessage() ) ) );
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Store checkout form data in customer session.
188
+ *
189
+ * @since 1.6.4
190
+ */
191
+ protected function set_customer_data( $data ) {
192
+ $customer = WC()->customer;
193
+
194
+ $billing_first_name = empty( $data[ 'billing_first_name' ] ) ? '' : wc_clean( $data[ 'billing_first_name' ] );
195
+ $billing_last_name = empty( $data[ 'billing_last_name' ] ) ? '' : wc_clean( $data[ 'billing_last_name' ] );
196
+ $billing_address_1 = empty( $data[ 'billing_address_1' ] ) ? '' : wc_clean( $data[ 'billing_address_1' ] );
197
+ $billing_address_2 = empty( $data[ 'billing_address_2' ] ) ? '' : wc_clean( $data[ 'billing_address_2' ] );
198
+ $billing_city = empty( $data[ 'billing_city' ] ) ? '' : wc_clean( $data[ 'billing_city' ] );
199
+ $billing_state = empty( $data[ 'billing_state' ] ) ? '' : wc_clean( $data[ 'billing_state' ] );
200
+ $billing_postcode = empty( $data[ 'billing_postcode' ] ) ? '' : wc_clean( $data[ 'billing_postcode' ] );
201
+ $billing_country = empty( $data[ 'billing_country' ] ) ? '' : wc_clean( $data[ 'billing_country' ] );
202
+
203
+ if ( isset( $data['ship_to_different_address'] ) ) {
204
+ $shipping_first_name = empty( $data[ 'shipping_first_name' ] ) ? '' : wc_clean( $data[ 'shipping_first_name' ] );
205
+ $shipping_last_name = empty( $data[ 'shipping_last_name' ] ) ? '' : wc_clean( $data[ 'shipping_last_name' ] );
206
+ $shipping_address_1 = empty( $data[ 'shipping_address_1' ] ) ? '' : wc_clean( $data[ 'shipping_address_1' ] );
207
+ $shipping_address_2 = empty( $data[ 'shipping_address_2' ] ) ? '' : wc_clean( $data[ 'shipping_address_2' ] );
208
+ $shipping_city = empty( $data[ 'shipping_city' ] ) ? '' : wc_clean( $data[ 'shipping_city' ] );
209
+ $shipping_state = empty( $data[ 'shipping_state' ] ) ? '' : wc_clean( $data[ 'shipping_state' ] );
210
+ $shipping_postcode = empty( $data[ 'shipping_postcode' ] ) ? '' : wc_clean( $data[ 'shipping_postcode' ] );
211
+ $shipping_country = empty( $data[ 'shipping_country' ] ) ? '' : wc_clean( $data[ 'shipping_country' ] );
212
+ } else {
213
+ $shipping_first_name = $billing_first_name;
214
+ $shipping_last_name = $billing_last_name;
215
+ $shipping_address_1 = $billing_address_1;
216
+ $shipping_address_2 = $billing_address_2;
217
+ $shipping_city = $billing_city;
218
+ $shipping_state = $billing_state;
219
+ $shipping_postcode = $billing_postcode;
220
+ $shipping_country = $billing_country;
221
+ }
222
+
223
+ $customer->set_shipping_address( $shipping_address_1 );
224
+ $customer->set_shipping_address_2( $shipping_address_2 );
225
+ $customer->set_shipping_city( $shipping_city );
226
+ $customer->set_shipping_state( $shipping_state );
227
+ $customer->set_shipping_postcode( $shipping_postcode );
228
+ $customer->set_shipping_country( $shipping_country );
229
+
230
+ if ( version_compare( WC_VERSION, '3.0', '<' ) ) {
231
+ $customer->set_address( $billing_address_1 );
232
+ $customer->set_address_2( $billing_address_2 );
233
+ $customer->set_city( $billing_city );
234
+ $customer->set_state( $billing_state );
235
+ $customer->set_postcode( $billing_postcode );
236
+ $customer->set_country( $billing_country );
237
+ } else {
238
+ $customer->set_shipping_first_name( $shipping_first_name );
239
+ $customer->set_shipping_last_name( $shipping_last_name );
240
+ $customer->set_billing_first_name( $billing_first_name );
241
+ $customer->set_billing_last_name( $billing_last_name );
242
+
243
+ $customer->set_billing_address_1( $billing_address_1 );
244
+ $customer->set_billing_address_2( $billing_address_2 );
245
+ $customer->set_billing_city( $billing_city );
246
+ $customer->set_billing_state( $billing_state );
247
+ $customer->set_billing_postcode( $billing_postcode );
248
+ $customer->set_billing_country( $billing_country );
249
  }
250
  }
251
 
includes/class-wc-gateway-ppec-client.php CHANGED
@@ -464,6 +464,7 @@ class WC_Gateway_PPEC_Client {
464
  'order_tax' => round( WC()->cart->tax_total + WC()->cart->shipping_tax_total, $decimals ),
465
  'shipping' => round( WC()->cart->shipping_total, $decimals ),
466
  'items' => $this->_get_paypal_line_items_from_cart(),
 
467
  );
468
 
469
  return $this->get_details( $details, $discounts, $rounded_total, WC()->cart->total );
@@ -698,6 +699,51 @@ class WC_Gateway_PPEC_Client {
698
  return $details;
699
  }
700
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
701
  /**
702
  * Get line items from given order.
703
  *
464
  'order_tax' => round( WC()->cart->tax_total + WC()->cart->shipping_tax_total, $decimals ),
465
  'shipping' => round( WC()->cart->shipping_total, $decimals ),
466
  'items' => $this->_get_paypal_line_items_from_cart(),
467
+ 'shipping_address' => $this->_get_address_from_customer(),
468
  );
469
 
470
  return $this->get_details( $details, $discounts, $rounded_total, WC()->cart->total );
699
  return $details;
700
  }
701
 
702
+ /**
703
+ * Get PayPal shipping address from customer.
704
+ *
705
+ * @return array Address
706
+ */
707
+ protected function _get_address_from_customer() {
708
+ $customer = WC()->customer;
709
+
710
+ $shipping_address = new PayPal_Address;
711
+
712
+ $old_wc = version_compare( WC_VERSION, '3.0', '<' );
713
+
714
+ if ( $customer->get_shipping_address() || $customer->get_shipping_address_2() ) {
715
+ $shipping_first_name = $old_wc ? '' : $customer->get_shipping_first_name();
716
+ $shipping_last_name = $old_wc ? '' : $customer->get_shipping_last_name();
717
+ $shipping_address_1 = $customer->get_shipping_address();
718
+ $shipping_address_2 = $customer->get_shipping_address_2();
719
+ $shipping_city = $customer->get_shipping_city();
720
+ $shipping_state = $customer->get_shipping_state();
721
+ $shipping_postcode = $customer->get_shipping_postcode();
722
+ $shipping_country = $customer->get_shipping_country();
723
+ } else {
724
+ // Fallback to billing in case no shipping methods are set. The address returned from PayPal
725
+ // will be stored in the order as billing.
726
+ $shipping_first_name = $old_wc ? '' : $customer->get_billing_first_name();
727
+ $shipping_last_name = $old_wc ? '' : $customer->get_billing_last_name();
728
+ $shipping_address_1 = $old_wc ? $customer->get_address() : $customer->get_billing_address_1();
729
+ $shipping_address_2 = $old_wc ? $customer->get_address_2() : $customer->get_billing_address_2();
730
+ $shipping_city = $old_wc ? $customer->get_city() : $customer->get_billing_city();
731
+ $shipping_state = $old_wc ? $customer->get_state() : $customer->get_billing_state();
732
+ $shipping_postcode = $old_wc ? $customer->get_postcode() : $customer->get_billing_postcode();
733
+ $shipping_country = $old_wc ? $customer->get_country() : $customer->get_billing_country();
734
+ }
735
+
736
+ $shipping_address->setName( $shipping_first_name . ' ' . $shipping_last_name );
737
+ $shipping_address->setStreet1( $shipping_address_1 );
738
+ $shipping_address->setStreet2( $shipping_address_2 );
739
+ $shipping_address->setCity( $shipping_city );
740
+ $shipping_address->setState( $shipping_state );
741
+ $shipping_address->setZip( $shipping_postcode );
742
+ $shipping_address->setCountry( $shipping_country );
743
+
744
+ return $shipping_address;
745
+ }
746
+
747
  /**
748
  * Get line items from given order.
749
  *
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.6
6
- Stable tag: 1.6.3
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
@@ -101,6 +101,10 @@ Please use this to inform us about bugs, or make contributions via PRs.
101
 
102
  == Changelog ==
103
 
 
 
 
 
104
  = 1.6.3 - 2018-08-15 =
105
  * Fix - Fatal error caused by a fix for Smart Payment Buttons.
106
 
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.6
6
+ Stable tag: 1.6.4
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
101
 
102
  == Changelog ==
103
 
104
+ = 1.6.4 - 2018-09-27 =
105
+ * Fix - Billing address from Checkout form not being passed to PayPal via Smart Payment Button.
106
+ * Fix - Checkout form not being validated until after Smart Payment Button payment flow.
107
+
108
  = 1.6.3 - 2018-08-15 =
109
  * Fix - Fatal error caused by a fix for Smart Payment Buttons.
110
 
woocommerce-gateway-paypal-express-checkout.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: WooCommerce PayPal Checkout Gateway
4
  * Plugin URI: https://woocommerce.com/products/woocommerce-gateway-paypal-express-checkout/
5
  * Description: A payment gateway for PayPal Checkout (https://www.paypal.com/us/webapps/mpp/paypal-checkout).
6
- * Version: 1.6.3
7
  * Author: WooCommerce
8
  * Author URI: https://woocommerce.com
9
  * Copyright: © 2018 WooCommerce / PayPal.
@@ -27,7 +27,7 @@ if ( ! defined( 'ABSPATH' ) ) {
27
  exit; // Exit if accessed directly
28
  }
29
 
30
- define( 'WC_GATEWAY_PPEC_VERSION', '1.6.3' );
31
 
32
  /**
33
  * Return instance of WC_Gateway_PPEC_Plugin.
3
  * Plugin Name: WooCommerce PayPal Checkout Gateway
4
  * Plugin URI: https://woocommerce.com/products/woocommerce-gateway-paypal-express-checkout/
5
  * Description: A payment gateway for PayPal Checkout (https://www.paypal.com/us/webapps/mpp/paypal-checkout).
6
+ * Version: 1.6.4
7
  * Author: WooCommerce
8
  * Author URI: https://woocommerce.com
9
  * Copyright: © 2018 WooCommerce / PayPal.
27
  exit; // Exit if accessed directly
28
  }
29
 
30
+ define( 'WC_GATEWAY_PPEC_VERSION', '1.6.4' );
31
 
32
  /**
33
  * Return instance of WC_Gateway_PPEC_Plugin.