From 555d680f6e45ae70dab2ccbdfb01205af8c84bd4 Mon Sep 17 00:00:00 2001
From: mksunlab
Date: Fri, 16 Mar 2018 10:25:37 +0100
Subject: [PATCH 01/34] add autocomplete attributes to account and register
forms
patch for issue #19425
---
templates/myaccount/form-login.php | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/templates/myaccount/form-login.php b/templates/myaccount/form-login.php
index e9f0f0ab429..3f7e7c7723e 100644
--- a/templates/myaccount/form-login.php
+++ b/templates/myaccount/form-login.php
@@ -42,11 +42,11 @@ if ( ! defined( 'ABSPATH' ) ) {
-
+
-
+
@@ -82,21 +82,21 @@ if ( ! defined( 'ABSPATH' ) ) {
-
+
-
+
-
+
From 6a29551979d474203a5ee9176f23811743caff76 Mon Sep 17 00:00:00 2001
From: mksunlab
Date: Fri, 16 Mar 2018 11:00:54 +0100
Subject: [PATCH 02/34] Revert "add autocomplete attributes to account and
register forms"
This reverts commit 555d680f6e45ae70dab2ccbdfb01205af8c84bd4.
---
templates/myaccount/form-login.php | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/templates/myaccount/form-login.php b/templates/myaccount/form-login.php
index 3f7e7c7723e..e9f0f0ab429 100644
--- a/templates/myaccount/form-login.php
+++ b/templates/myaccount/form-login.php
@@ -42,11 +42,11 @@ if ( ! defined( 'ABSPATH' ) ) {
-
+
-
+
@@ -82,21 +82,21 @@ if ( ! defined( 'ABSPATH' ) ) {
-
+
-
+
-
+
From 5a19f00c5a3532843b6bbca2142d378d317d27b8 Mon Sep 17 00:00:00 2001
From: michakrapp
Date: Fri, 16 Mar 2018 11:07:02 +0100
Subject: [PATCH 03/34] accout login autocomplete - commit with correct user
account
on first commit used false user account
---
templates/myaccount/form-login.php | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/templates/myaccount/form-login.php b/templates/myaccount/form-login.php
index e9f0f0ab429..3f7e7c7723e 100644
--- a/templates/myaccount/form-login.php
+++ b/templates/myaccount/form-login.php
@@ -42,11 +42,11 @@ if ( ! defined( 'ABSPATH' ) ) {
-
+
-
+
@@ -82,21 +82,21 @@ if ( ! defined( 'ABSPATH' ) ) {
-
+
-
+
-
+
From 7145b8f7291e94965b8692a485aab9ee356a0005 Mon Sep 17 00:00:00 2001
From: michakrapp
Date: Mon, 19 Mar 2018 08:53:53 +0100
Subject: [PATCH 04/34] template global form-login autocomplete attributes
---
templates/global/form-login.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/templates/global/form-login.php b/templates/global/form-login.php
index 2f509421eff..f335396844f 100644
--- a/templates/global/form-login.php
+++ b/templates/global/form-login.php
@@ -33,11 +33,11 @@ if ( is_user_logged_in() ) {
-
+
-
+
From 4283804f38057468b89506ffd00ee3ff74104e45 Mon Sep 17 00:00:00 2001
From: michakrapp
Date: Mon, 19 Mar 2018 09:22:00 +0100
Subject: [PATCH 05/34] Add autocomplete attributes to account edit form
maybe "password-current" should get autocomplete="off" to prevent trigger password change on default
---
templates/myaccount/form-edit-account.php | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/templates/myaccount/form-edit-account.php b/templates/myaccount/form-edit-account.php
index cea11aa5b1b..c181257952c 100644
--- a/templates/myaccount/form-edit-account.php
+++ b/templates/myaccount/form-edit-account.php
@@ -28,11 +28,11 @@ do_action( 'woocommerce_before_edit_account_form' ); ?>
-
+
-
+
@@ -44,7 +44,7 @@ do_action( 'woocommerce_before_edit_account_form' ); ?>
-
+
From cc742b908a643b794711b92802deaa7b3df41c42 Mon Sep 17 00:00:00 2001
From: michakrapp
Date: Mon, 19 Mar 2018 09:25:57 +0100
Subject: [PATCH 06/34] Add autocomplete attributes to lost password form
---
templates/myaccount/form-lost-password.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/templates/myaccount/form-lost-password.php b/templates/myaccount/form-lost-password.php
index ac543384442..5fe47b7b091 100644
--- a/templates/myaccount/form-lost-password.php
+++ b/templates/myaccount/form-lost-password.php
@@ -28,7 +28,7 @@ wc_print_notices(); ?>
-
+
From cef2b1ee131c3edbf4f22c8da6a5206ec39dcf87 Mon Sep 17 00:00:00 2001
From: michakrapp
Date: Mon, 19 Mar 2018 09:30:11 +0100
Subject: [PATCH 07/34] Add autocomplete attributes to reset password form
---
templates/myaccount/form-reset-password.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/templates/myaccount/form-reset-password.php b/templates/myaccount/form-reset-password.php
index 72b19647ae6..d6e3a41709a 100644
--- a/templates/myaccount/form-reset-password.php
+++ b/templates/myaccount/form-reset-password.php
@@ -28,11 +28,11 @@ wc_print_notices(); ?>
-
+
-
+
From 27a309d2dfc6546d51fc962a2e417c42edb9e766 Mon Sep 17 00:00:00 2001
From: Peter Fabian
Date: Thu, 22 Mar 2018 15:39:30 +0100
Subject: [PATCH 08/34] Removed line item limit and make sure the URL is
shorter than 2083 characters
- removed limit to 9 line items per Paypal order
- if the request URL with all line items will be longer than 2083 characters, send it as one line item
- fix the character limit function to account for URL encoding happening in http_build_query
---
.../class-wc-gateway-paypal-request.php | 187 ++++++++-----
tests/unit-tests/gateways/paypal/request.php | 261 ++++++++++++++++++
2 files changed, 376 insertions(+), 72 deletions(-)
create mode 100644 tests/unit-tests/gateways/paypal/request.php
diff --git a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
index 3df9a58a0c2..29cf2e2d026 100644
--- a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
+++ b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
@@ -53,15 +53,16 @@ class WC_Gateway_Paypal_Request {
* @return string
*/
public function get_request_url( $order, $sandbox = false ) {
+ if ( $sandbox ) {
+ $this->request_url_prefix = 'https://www.sandbox.paypal.com/cgi-bin/webscr?test_ipn=1&';
+ } else {
+ $this->request_url_prefix = 'https://www.paypal.com/cgi-bin/webscr?';
+ }
$paypal_args = http_build_query( $this->get_paypal_args( $order ), '', '&' );
WC_Gateway_Paypal::log( 'PayPal Request Args for order ' . $order->get_order_number() . ': ' . wc_print_r( $paypal_args, true ) );
- if ( $sandbox ) {
- return 'https://www.sandbox.paypal.com/cgi-bin/webscr?test_ipn=1&' . $paypal_args;
- } else {
- return 'https://www.paypal.com/cgi-bin/webscr?' . $paypal_args;
- }
+ return $this->request_url_prefix . $paypal_args;
}
/**
@@ -72,8 +73,12 @@ class WC_Gateway_Paypal_Request {
* @return string
*/
protected function limit_length( $string, $limit = 127 ) {
- if ( strlen( $string ) > $limit ) {
- $string = substr( $string, 0, $limit - 3 ) . '...';
+ // As the output is to be used in http_build_query which applies URL encoding, the string needs to be
+ // cut as if it was URL-encoded, but returned non-encoded (it will be encoded by http_build_query later).
+ $url_encoded_str = rawurlencode( $string );
+
+ if ( strlen( $url_encoded_str ) > $limit ) {
+ $string = rawurldecode( substr( $url_encoded_str, 0, $limit - 3 ) . '...' );
}
return $string;
}
@@ -87,43 +92,49 @@ class WC_Gateway_Paypal_Request {
protected function get_paypal_args( $order ) {
WC_Gateway_Paypal::log( 'Generating payment form for order ' . $order->get_order_number() . '. Notify URL: ' . $this->notify_url );
+ $initial_paypal_args = array(
+ 'cmd' => '_cart',
+ 'business' => $this->gateway->get_option( 'email' ),
+ 'no_note' => 1,
+ 'currency_code' => get_woocommerce_currency(),
+ 'charset' => 'utf-8',
+ 'rm' => is_ssl() ? 2 : 1,
+ 'upload' => 1,
+ 'return' => esc_url_raw( add_query_arg( 'utm_nooverride', '1', $this->gateway->get_return_url( $order ) ) ),
+ 'cancel_return' => esc_url_raw( $order->get_cancel_order_url_raw() ),
+ 'page_style' => $this->gateway->get_option( 'page_style' ),
+ 'image_url' => esc_url_raw( $this->gateway->get_option( 'image_url' ) ),
+ 'paymentaction' => $this->gateway->get_option( 'paymentaction' ),
+ 'bn' => 'WooThemes_Cart',
+ 'invoice' => $this->limit_length( $this->gateway->get_option( 'invoice_prefix' ) . $order->get_order_number(), 127 ),
+ 'custom' => wp_json_encode(
+ array(
+ 'order_id' => $order->get_id(),
+ 'order_key' => $order->get_order_key(),
+ )
+ ),
+ 'notify_url' => $this->limit_length( $this->notify_url, 255 ),
+ 'first_name' => $this->limit_length( $order->get_billing_first_name(), 32 ),
+ 'last_name' => $this->limit_length( $order->get_billing_last_name(), 64 ),
+ 'address1' => $this->limit_length( $order->get_billing_address_1(), 100 ),
+ 'address2' => $this->limit_length( $order->get_billing_address_2(), 100 ),
+ 'city' => $this->limit_length( $order->get_billing_city(), 40 ),
+ 'state' => $this->get_paypal_state( $order->get_billing_country(), $order->get_billing_state() ),
+ 'zip' => $this->limit_length( wc_format_postcode( $order->get_billing_postcode(), $order->get_billing_country() ), 32 ),
+ 'country' => $this->limit_length( $order->get_billing_country(), 2 ),
+ 'email' => $this->limit_length( $order->get_billing_email() ),
+ );
+ $phone_number_args = $this->get_phone_number_args( $order );
+ $shipping_args = $this->get_shipping_args( $order );
+ $query_str_except_line_items = http_build_query( array_merge( $initial_paypal_args, $phone_number_args, $shipping_args ), '', '&' );
+ $url_except_line_items_length = strlen( $this->request_url_prefix . $query_str_except_line_items );
+
return apply_filters(
'woocommerce_paypal_args', array_merge(
- array(
- 'cmd' => '_cart',
- 'business' => $this->gateway->get_option( 'email' ),
- 'no_note' => 1,
- 'currency_code' => get_woocommerce_currency(),
- 'charset' => 'utf-8',
- 'rm' => is_ssl() ? 2 : 1,
- 'upload' => 1,
- 'return' => esc_url_raw( add_query_arg( 'utm_nooverride', '1', $this->gateway->get_return_url( $order ) ) ),
- 'cancel_return' => esc_url_raw( $order->get_cancel_order_url_raw() ),
- 'page_style' => $this->gateway->get_option( 'page_style' ),
- 'image_url' => esc_url_raw( $this->gateway->get_option( 'image_url' ) ),
- 'paymentaction' => $this->gateway->get_option( 'paymentaction' ),
- 'bn' => 'WooThemes_Cart',
- 'invoice' => $this->limit_length( $this->gateway->get_option( 'invoice_prefix' ) . $order->get_order_number(), 127 ),
- 'custom' => wp_json_encode(
- array(
- 'order_id' => $order->get_id(),
- 'order_key' => $order->get_order_key(),
- )
- ),
- 'notify_url' => $this->limit_length( $this->notify_url, 255 ),
- 'first_name' => $this->limit_length( $order->get_billing_first_name(), 32 ),
- 'last_name' => $this->limit_length( $order->get_billing_last_name(), 64 ),
- 'address1' => $this->limit_length( $order->get_billing_address_1(), 100 ),
- 'address2' => $this->limit_length( $order->get_billing_address_2(), 100 ),
- 'city' => $this->limit_length( $order->get_billing_city(), 40 ),
- 'state' => $this->get_paypal_state( $order->get_billing_country(), $order->get_billing_state() ),
- 'zip' => $this->limit_length( wc_format_postcode( $order->get_billing_postcode(), $order->get_billing_country() ), 32 ),
- 'country' => $this->limit_length( $order->get_billing_country(), 2 ),
- 'email' => $this->limit_length( $order->get_billing_email() ),
- ),
- $this->get_phone_number_args( $order ),
- $this->get_shipping_args( $order ),
- $this->get_line_item_args( $order )
+ $initial_paypal_args,
+ $phone_number_args,
+ $shipping_args,
+ $this->get_line_item_args( $order, $url_except_line_items_length )
), $order
);
}
@@ -180,19 +191,63 @@ class WC_Gateway_Paypal_Request {
return $shipping_args;
}
+ /**
+ * Get shipping cost line item args for paypal request.
+ *
+ * @param WC_Order $order Order object.
+ * @param bool $include_shipping_tax Whether to include shipping tax or not.
+ * @return array
+ */
+ protected function get_shipping_cost_line_item( $order, $include_shipping_tax ) {
+ $line_item_args = array();
+ $shipping_total = $order->get_shipping_total();
+ if ( $include_shipping_tax ) {
+ $shipping_total += $order->get_shipping_tax();
+ }
+
+ // Add shipping costs. Paypal ignores anything over 5 digits (999.99 is the max).
+ // We also check that shipping is not the **only** cost as PayPal won't allow payment
+ // if the items have no cost.
+ if ( $order->get_shipping_total() > 0 && $order->get_shipping_total() < 999.99 && $this->number_format( $order->get_shipping_total() + $order->get_shipping_tax(), $order ) !== $this->number_format( $order->get_total(), $order ) ) {
+ $line_item_args['shipping_1'] = $this->number_format( $shipping_total, $order );
+ } elseif ( $order->get_shipping_total() > 0 ) {
+ /* translators: %s: Order shipping method */
+ $this->add_line_item( sprintf( __( 'Shipping via %s', 'woocommerce' ), $order->get_shipping_method() ), 1, $this->number_format( $shipping_total, $order ) );
+ }
+
+ return $line_item_args;
+ }
+
+ /**
+ * Get line item args for paypal request as a single line item.
+ *
+ * @param WC_Order $order Order object.
+ * @param bool $include_shipping_tax Whether to include shipping tax or not.
+ * @return array
+ */
+ protected function get_line_item_args_single_item( $order, $include_shipping_tax ) {
+ $this->delete_line_items();
+
+ $all_items_name = $this->get_order_item_names( $order );
+ $this->add_line_item( $all_items_name ? $all_items_name : __( 'Order', 'woocommerce' ), 1, $this->number_format( $order->get_total() - $this->round( $order->get_shipping_total() + $order->get_shipping_tax(), $order ), $order ), $order->get_order_number() );
+ $line_item_args = $this->get_shipping_cost_line_item( $order, $include_shipping_tax );
+
+ return array_merge( $line_item_args, $this->get_line_items() );
+ }
+
/**
* Get line item args for paypal request.
*
* @param WC_Order $order Order object.
+ * @param int $url_except_line_items_length Length of URL without line items.
* @return array
*/
- protected function get_line_item_args( $order ) {
+ protected function get_line_item_args( $order, $url_except_line_items_length ) {
/**
* Try passing a line item per product if supported.
*/
if ( ( ! wc_tax_enabled() || ! wc_prices_include_tax() ) && $this->prepare_line_items( $order ) ) {
-
$line_item_args = array();
$line_item_args['tax_cart'] = $this->number_format( $order->get_total_tax(), $order );
@@ -200,41 +255,29 @@ class WC_Gateway_Paypal_Request {
$line_item_args['discount_amount_cart'] = $this->number_format( $this->round( $order->get_total_discount(), $order ), $order );
}
- // Add shipping costs. Paypal ignores anything over 5 digits (999.99 is the max).
- // We also check that shipping is not the **only** cost as PayPal won't allow payment
- // if the items have no cost.
- if ( $order->get_shipping_total() > 0 && $order->get_shipping_total() < 999.99 && $this->number_format( $order->get_shipping_total() + $order->get_shipping_tax(), $order ) !== $this->number_format( $order->get_total(), $order ) ) {
- $line_item_args['shipping_1'] = $this->number_format( $order->get_shipping_total(), $order );
- } elseif ( $order->get_shipping_total() > 0 ) {
- /* translators: %s: Order shipping method */
- $this->add_line_item( sprintf( __( 'Shipping via %s', 'woocommerce' ), $order->get_shipping_method() ), 1, $this->number_format( $order->get_shipping_total(), $order ) );
- }
-
+ $include_shipping_tax = false;
+ $line_item_args = array_merge( $line_item_args, $this->get_shipping_cost_line_item( $order, $include_shipping_tax ) );
$line_item_args = array_merge( $line_item_args, $this->get_line_items() );
+
+ $line_items_query_str_length = strlen( http_build_query( $line_item_args, '', '&' ) );
+
+ // If URL is longer than 2,083 chars, ignore line items and send cart to Paypal as a single item.
+ // One item's name can only be 127 characters long, so the URL should not be longer than limit.
+ // URL character limit via:
+ // https://support.microsoft.com/en-us/help/208427/maximum-url-length-is-2-083-characters-in-internet-explorer
+ // +1 for '&' that needs to connect 2 query strings.
+ if ( $url_except_line_items_length + 1 + $line_items_query_str_length > 2083 ) {
+ $line_item_args = $this->get_line_item_args_single_item( $order, $include_shipping_tax );
+ }
} else {
/**
* Send order as a single item.
*
* For shipping, we longer use shipping_1 because paypal ignores it if *any* shipping rules are within paypal, and paypal ignores anything over 5 digits (999.99 is the max).
*/
+ $include_shipping_tax = true;
+ $line_item_args = $this->get_line_item_args_single_item( $order, $include_shipping_tax );
- $this->delete_line_items();
-
- $line_item_args = array();
- $all_items_name = $this->get_order_item_names( $order );
- $this->add_line_item( $all_items_name ? $all_items_name : __( 'Order', 'woocommerce' ), 1, $this->number_format( $order->get_total() - $this->round( $order->get_shipping_total() + $order->get_shipping_tax(), $order ), $order ), $order->get_order_number() );
-
- // Add shipping costs. Paypal ignores anything over 5 digits (999.99 is the max).
- // We also check that shipping is not the **only** cost as PayPal won't allow payment
- // if the items have no cost.
- if ( $order->get_shipping_total() > 0 && $order->get_shipping_total() < 999.99 && $this->number_format( $order->get_shipping_total() + $order->get_shipping_tax(), $order ) !== $this->number_format( $order->get_total(), $order ) ) {
- $line_item_args['shipping_1'] = $this->number_format( $order->get_shipping_total() + $order->get_shipping_tax(), $order );
- } elseif ( $order->get_shipping_total() > 0 ) {
- /* translators: %s: Order shipping method */
- $this->add_line_item( sprintf( __( 'Shipping via %s', 'woocommerce' ), $order->get_shipping_method() ), 1, $this->number_format( $order->get_shipping_total() + $order->get_shipping_tax(), $order ) );
- }
-
- $line_item_args = array_merge( $line_item_args, $this->get_line_items() );
}
return $line_item_args;
@@ -364,7 +407,7 @@ class WC_Gateway_Paypal_Request {
protected function add_line_item( $item_name, $quantity = 1, $amount = 0.0, $item_number = '' ) {
$index = ( count( $this->line_items ) / 4 ) + 1;
- if ( $amount < 0 || $index > 9 ) {
+ if ( $amount < 0 ) {
return false;
}
diff --git a/tests/unit-tests/gateways/paypal/request.php b/tests/unit-tests/gateways/paypal/request.php
new file mode 100644
index 00000000000..8d544913b68
--- /dev/null
+++ b/tests/unit-tests/gateways/paypal/request.php
@@ -0,0 +1,261 @@
+products.
+ *
+ * @param int $product_count Number of products to create.
+ */
+ protected function create_products( $product_count = 30 ) {
+ $this->products = array();
+ for ( $i = 0; $i < $product_count; $i++ ) {
+ $product = WC_Helper_Product::create_simple_product();
+ $product->set_name( 'Dummy Product ' . $i );
+ $this->products[] = $product;
+
+ }
+
+ // To test limit length properly, we need a product with a name that is shorter than 127 chars,
+ // but longer than 127 chars when URL-encoded.
+ if ( array_key_exists( 0, $this->products ) ) {
+ $this->products[0]->set_name( 'Dummy Product 😎😎😎😎😎😎😎😎😎😎😎' );
+ }
+
+ }
+
+ /**
+ * Add products from $this->products to $order as items, clearing existing order items.
+ *
+ * @param WC_Order $order Order to which the products should be added.
+ */
+ protected function add_products_to_order( $order ) {
+ // Remove previous items.
+ foreach ( $order->get_items() as $item ) {
+ $order->remove_item( $item->get_id() );
+ }
+
+ // Add new products.
+ foreach ( $this->products as $product ) {
+ $item = new WC_Order_Item_Product();
+ $item->set_props( array(
+ 'product' => $product,
+ 'quantity' => 3,
+ 'subtotal' => wc_get_price_excluding_tax( $product, array( 'qty' => 3 ) ),
+ 'total' => wc_get_price_excluding_tax( $product, array( 'qty' => 3 ) ),
+ ) );
+
+ $item->save();
+ $order->add_item( $item );
+ }
+
+ }
+
+ /**
+ * Initialize the Paypal gateway and Request objects.
+ */
+ public function setUp() {
+ parent::setUp();
+
+ $bootstrap = WC_Unit_Tests_Bootstrap::instance();
+ include_once $bootstrap->plugin_dir . '/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php';
+
+ $this->paypal_gateway = new WC_Gateway_Paypal();
+ $this->paypal_request = new WC_Gateway_Paypal_Request( $this->paypal_gateway );
+ }
+
+
+ /**
+ * Create Paypal request URL for $product_count number of products.
+ *
+ * @param int $product_count Number of products to include in the order.
+ * @param bool $testmode Whether to test using sandbox or not.
+ *
+ * @return string
+ * @throws WC_Data_Exception
+ */
+ protected function get_request_url( $product_count, $testmode ) {
+ // Create products.
+ $this->create_products( $product_count );
+
+ $this->order = WC_Helper_Order::create_order( $this->user );
+ $this->add_products_to_order( $this->order );
+
+ // Set payment method to Paypal.
+ $payment_gateways = WC()->payment_gateways->payment_gateways();
+ $this->order->set_payment_method( $payment_gateways['paypal'] );
+ $this->order->calculate_totals();
+ $this->order->calculate_shipping();
+
+ return $this->paypal_request->get_request_url( $this->order, $testmode );
+ }
+
+ /**
+ * Clean up order, deletes all products in order, too.
+ */
+ protected function clean_up() {
+ WC_Helper_Order::delete_order( $this->order->get_id() );
+ }
+
+ /**
+ * Check if the shipping tax is included in the total according to $shipping_tax_included.
+ *
+ * @param array $query_array Request URL parsed into associative array.
+ * @param bool $shipping_tax_included Whether the shipping tax should be included or not.
+ */
+ protected function check_shipping_tax( $query_array, $shipping_tax_included ) {
+ $shipping_total = $this->order->get_shipping_total();
+ if ( $shipping_tax_included ) {
+ $shipping_total += $this->order->get_shipping_tax();
+ }
+ $epsilon = 0.01;
+ $this->assertTrue( abs( $shipping_total - floatval( $query_array['shipping_1'] ) ) < $epsilon );
+
+ }
+
+ /**
+ * Test common order asserts.
+ *
+ * @param string $request_url Paypal request URL.
+ * @param bool $testmode Whether Paypal sandbox is used or not.
+ */
+ protected function check_order_common_props( $request_url, $testmode ) {
+ if ( $testmode ) {
+ $this->assertEquals( 'https://www.sandbox.paypal.com', substr( $request_url, 0, 30 ) );
+ } else {
+ $this->assertEquals( 'https://www.paypal.com', substr( $request_url, 0, 22 ) );
+ }
+ $this->assertLessThanOrEqual( 2083, strlen( $request_url ) );
+ }
+
+ /**
+ * Test large order with 30 items, URL length > 2083 characters.
+ *
+ * @param bool $shipping_tax_included Whether the shipping tax should be included or not.
+ * @param bool $testmode Whether to use Paypal sandbox.
+ *
+ * @throws WC_Data_Exception
+ */
+ protected function check_large_order( $shipping_tax_included, $testmode ) {
+ $request_url = $this->get_request_url( 30, $testmode );
+
+ $this->check_order_common_props( $request_url, $testmode );
+
+ // Check fields limited to 127 characters for length.
+ $fields_limited_to_127_chars = array(
+ 'invoice',
+ 'item_name_1',
+ 'item_number_1',
+ );
+
+ $query_string = wp_parse_url( $request_url, PHP_URL_QUERY )
+ ? wp_parse_url( $request_url, PHP_URL_QUERY )
+ : '';
+ $query_array = array();
+ parse_str( $query_string, $query_array );
+ foreach ( $fields_limited_to_127_chars as $field_name ) {
+ $this->assertLessThanOrEqual( 127, strlen( $query_array[ $field_name ] ) );
+ }
+
+ // Check that there is actually only one item for order with URL length > limit.
+ $this->assertFalse( array_key_exists( 'item_name_2', $query_array ) );
+
+ $this->check_shipping_tax( $query_array, $shipping_tax_included );
+
+ // Remove order and created products.
+ $this->clean_up();
+
+ }
+
+ /**
+ * Test small order with fewer items, URL length should be < 2083 characters.
+ *
+ * @param int $product_count Number of products to include in the order.
+ * @param bool $shipping_tax_included Whether the shipping tax should be included or not.
+ * @param bool $testmode Whether to use Paypal sandbox.
+ *
+ * @throws WC_Data_Exception
+ */
+ protected function check_small_order( $product_count, $shipping_tax_included, $testmode ) {
+ $request_url = $this->get_request_url( $product_count, $testmode );
+
+ $this->check_order_common_props( $request_url, $testmode );
+
+ $query_string = wp_parse_url( $request_url, PHP_URL_QUERY )
+ ? wp_parse_url( $request_url, PHP_URL_QUERY )
+ : '';
+ $query_array = array();
+ parse_str( $query_string, $query_array );
+
+ // Check that there are $product_count line items in the request URL.
+ // However, if shipping tax is included, there is only one item.
+ if ( $shipping_tax_included ) {
+ $product_count = 1;
+ }
+
+ for ( $i = 1; $i <= $product_count; $i++ ) {
+ $this->assertTrue( array_key_exists( 'item_name_' . $i, $query_array ), 'Item name ' . $i . ' does not exist' );
+ $this->assertTrue( array_key_exists( 'quantity_' . $i, $query_array ) );
+ $this->assertTrue( array_key_exists( 'amount_' . $i, $query_array ) );
+ $this->assertTrue( array_key_exists( 'item_number_' . $i, $query_array ) );
+
+ $this->assertLessThanOrEqual( 127, strlen( $query_array[ 'item_name_' . $i ] ) );
+ $this->assertLessThanOrEqual( 127, strlen( $query_array[ 'item_number_' . $i ] ) );
+
+ }
+
+ $this->check_shipping_tax( $query_array, $shipping_tax_included );
+
+ // Remove order and created products.
+ $this->clean_up();
+ }
+
+ /**
+ * @throws WC_Data_Exception
+ */
+ public function test_request_url() {
+ // User set up.
+ $this->user = $this->factory->user->create( array(
+ 'role' => 'administrator',
+ ) );
+ wp_set_current_user( $this->user );
+
+ // Paths through code changed by:
+ // $sandbox (true/false)
+ // wc_tax_enabled() === get_option( 'woocommerce_calc_taxes' ) === 'yes'
+ // wc_prices_include_tax() === wc_tax_enabled() && 'yes' === get_option( 'woocommerce_prices_include_tax' );.
+ $correct_options = array(
+ [ 'no', 'no', false ],
+ [ 'yes', 'no', false ],
+ // ['no', 'yes', false], // this is not a valid option due to definition of wc_prices_include_tax
+ [ 'yes', 'yes', true ],
+ );
+ foreach ( array( true, false ) as $testmode ) {
+ foreach ( $correct_options as $values ) {
+ update_option( 'woocommerce_calc_taxes', $values[0] );
+ update_option( 'woocommerce_prices_include_tax', $values[1] );
+ $shipping_tax_included = $values[2];
+
+ // Test order with < 9 items (URL shorter than limit).
+ $this->check_small_order( 5, $shipping_tax_included, $testmode );
+
+ // Test order with >9 items with URL shorter than limit.
+ $this->check_small_order( 11, $shipping_tax_included, $testmode );
+
+ // Test order with URL longer than limit.
+ $this->check_large_order( $shipping_tax_included, $testmode );
+
+ }
+ }
+
+ }
+
+}
+
From fda6421deea53cdfd0d175509348e8e4dfb4b9be Mon Sep 17 00:00:00 2001
From: Peter Fabian
Date: Thu, 22 Mar 2018 20:42:19 +0100
Subject: [PATCH 09/34] Fixed compatibility with older PHP versions, removed
superfluous asserts.
---
tests/unit-tests/gateways/paypal/request.php | 40 ++++++++++++--------
1 file changed, 24 insertions(+), 16 deletions(-)
diff --git a/tests/unit-tests/gateways/paypal/request.php b/tests/unit-tests/gateways/paypal/request.php
index 8d544913b68..2840adcde0a 100644
--- a/tests/unit-tests/gateways/paypal/request.php
+++ b/tests/unit-tests/gateways/paypal/request.php
@@ -232,27 +232,35 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
// wc_tax_enabled() === get_option( 'woocommerce_calc_taxes' ) === 'yes'
// wc_prices_include_tax() === wc_tax_enabled() && 'yes' === get_option( 'woocommerce_prices_include_tax' );.
$correct_options = array(
- [ 'no', 'no', false ],
- [ 'yes', 'no', false ],
- // ['no', 'yes', false], // this is not a valid option due to definition of wc_prices_include_tax
- [ 'yes', 'yes', true ],
+ array( 'no', 'no', false ),
+ array( 'yes', 'no', false ),
+ // array( 'no', 'yes', false ), // this is not a valid option due to definition of wc_prices_include_tax
+ array( 'yes', 'yes', true ),
);
- foreach ( array( true, false ) as $testmode ) {
- foreach ( $correct_options as $values ) {
- update_option( 'woocommerce_calc_taxes', $values[0] );
- update_option( 'woocommerce_prices_include_tax', $values[1] );
- $shipping_tax_included = $values[2];
- // Test order with < 9 items (URL shorter than limit).
- $this->check_small_order( 5, $shipping_tax_included, $testmode );
+ // One test without sandbox.
+ $testmode = false;
+ update_option( 'woocommerce_calc_taxes', 'no' );
+ update_option( 'woocommerce_prices_include_tax', 'no' );
+ $shipping_tax_included = false;
+ $this->check_small_order( 5, $shipping_tax_included, $testmode );
- // Test order with >9 items with URL shorter than limit.
- $this->check_small_order( 11, $shipping_tax_included, $testmode );
+ // Other tests with sandbox active.
+ $testmode = true;
+ foreach ( $correct_options as $values ) {
+ update_option( 'woocommerce_calc_taxes', $values[0] );
+ update_option( 'woocommerce_prices_include_tax', $values[1] );
+ $shipping_tax_included = $values[2];
- // Test order with URL longer than limit.
- $this->check_large_order( $shipping_tax_included, $testmode );
+ // Test order with < 9 items (URL shorter than limit).
+ $this->check_small_order( 5, $shipping_tax_included, $testmode );
+
+ // Test order with >9 items with URL shorter than limit.
+ $this->check_small_order( 11, $shipping_tax_included, $testmode );
+
+ // Test order with URL longer than limit.
+ $this->check_large_order( $shipping_tax_included, $testmode );
- }
}
}
From 04cce41b6b257701451d88debfa71aad822f5e86 Mon Sep 17 00:00:00 2001
From: Gerhard Potgieter
Date: Fri, 23 Mar 2018 11:19:02 +0200
Subject: [PATCH 10/34] Default to no when importing backorders.
---
includes/import/class-wc-product-csv-importer.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/includes/import/class-wc-product-csv-importer.php b/includes/import/class-wc-product-csv-importer.php
index efcad3f9811..30e6c6b86c9 100644
--- a/includes/import/class-wc-product-csv-importer.php
+++ b/includes/import/class-wc-product-csv-importer.php
@@ -502,7 +502,7 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
return $value ? 'yes' : 'no';
}
- return '';
+ return 'no';
}
/**
From e876f0dfb24e5b44b5129a9b451f86f4947d227b Mon Sep 17 00:00:00 2001
From: Gerhard Potgieter
Date: Fri, 23 Mar 2018 11:21:59 +0200
Subject: [PATCH 11/34] empty check on 0 will be true, return no when empty.
---
includes/import/class-wc-product-csv-importer.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/includes/import/class-wc-product-csv-importer.php b/includes/import/class-wc-product-csv-importer.php
index 30e6c6b86c9..8e3c646cdd8 100644
--- a/includes/import/class-wc-product-csv-importer.php
+++ b/includes/import/class-wc-product-csv-importer.php
@@ -491,7 +491,7 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
*/
public function parse_backorders_field( $value ) {
if ( empty( $value ) ) {
- return '';
+ return 'no';
}
$value = $this->parse_bool_field( $value );
From 0573232c62a13ef7ad1730952599193fff81342f Mon Sep 17 00:00:00 2001
From: Mike Jolley
Date: Fri, 23 Mar 2018 12:54:03 +0000
Subject: [PATCH 12/34] Call empty cart when completing payment in PayPal
---
.../paypal/includes/class-wc-gateway-paypal-response.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/includes/gateways/paypal/includes/class-wc-gateway-paypal-response.php b/includes/gateways/paypal/includes/class-wc-gateway-paypal-response.php
index c917a8aeec3..05f00fb47c6 100644
--- a/includes/gateways/paypal/includes/class-wc-gateway-paypal-response.php
+++ b/includes/gateways/paypal/includes/class-wc-gateway-paypal-response.php
@@ -65,6 +65,7 @@ abstract class WC_Gateway_Paypal_Response {
protected function payment_complete( $order, $txn_id = '', $note = '' ) {
$order->add_order_note( $note );
$order->payment_complete( $txn_id );
+ WC()->cart->empty_cart();
}
/**
From 26144afbc655c1d183ae9cd6956d9f1cd7b2e6e1 Mon Sep 17 00:00:00 2001
From: Peter Fabian
Date: Fri, 23 Mar 2018 17:22:09 +0100
Subject: [PATCH 13/34] Test request length after applying filter
- added default value to get_line_item_args to not break interface
- smaller code review updates
---
.../class-wc-gateway-paypal-request.php | 189 ++++++++++++------
tests/unit-tests/gateways/paypal/request.php | 11 +-
2 files changed, 131 insertions(+), 69 deletions(-)
diff --git a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
index 29cf2e2d026..b462fc42225 100644
--- a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
+++ b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
@@ -35,6 +35,14 @@ class WC_Gateway_Paypal_Request {
*/
protected $notify_url;
+ /**
+ * Endpoint for requests from PayPal.
+ *
+ * @var string
+ */
+ protected $endpoint;
+
+
/**
* Constructor.
*
@@ -54,15 +62,15 @@ class WC_Gateway_Paypal_Request {
*/
public function get_request_url( $order, $sandbox = false ) {
if ( $sandbox ) {
- $this->request_url_prefix = 'https://www.sandbox.paypal.com/cgi-bin/webscr?test_ipn=1&';
+ $this->endpoint = 'https://www.sandbox.paypal.com/cgi-bin/webscr?test_ipn=1&';
} else {
- $this->request_url_prefix = 'https://www.paypal.com/cgi-bin/webscr?';
+ $this->endpoint = 'https://www.paypal.com/cgi-bin/webscr?';
}
$paypal_args = http_build_query( $this->get_paypal_args( $order ), '', '&' );
WC_Gateway_Paypal::log( 'PayPal Request Args for order ' . $order->get_order_number() . ': ' . wc_print_r( $paypal_args, true ) );
- return $this->request_url_prefix . $paypal_args;
+ return $this->endpoint . $paypal_args;
}
/**
@@ -83,6 +91,67 @@ class WC_Gateway_Paypal_Request {
return $string;
}
+ /**
+ * If the default request with line items is too long, generate a new one with only one line item.
+ *
+ * @param WC_Order $order Order to be sent to Paypal.
+ * @param array $paypal_args Arguments sent to Paypal in the request.
+ *
+ * @return array
+ */
+ protected function fix_request_legth( $order, $paypal_args ) {
+ $max_paypal_length = 2083;
+ $query_candidate = http_build_query( $paypal_args, '', '&' );
+ // If URL is longer than 2,083 chars, ignore line items and send cart to Paypal as a single item.
+ // One item's name can only be 127 characters long, so the URL should not be longer than limit.
+ // URL character limit via:
+ // https://support.microsoft.com/en-us/help/208427/maximum-url-length-is-2-083-characters-in-internet-explorer
+ if ( strlen( $this->endpoint . $query_candidate ) <= $max_paypal_length ) {
+ return $paypal_args;
+ }
+
+ return apply_filters(
+ 'woocommerce_paypal_args', array_merge(
+ array(
+ 'cmd' => '_cart',
+ 'business' => $this->gateway->get_option( 'email' ),
+ 'no_note' => 1,
+ 'currency_code' => get_woocommerce_currency(),
+ 'charset' => 'utf-8',
+ 'rm' => is_ssl() ? 2 : 1,
+ 'upload' => 1,
+ 'return' => esc_url_raw( add_query_arg( 'utm_nooverride', '1', $this->gateway->get_return_url( $order ) ) ),
+ 'cancel_return' => esc_url_raw( $order->get_cancel_order_url_raw() ),
+ 'page_style' => $this->gateway->get_option( 'page_style' ),
+ 'image_url' => esc_url_raw( $this->gateway->get_option( 'image_url' ) ),
+ 'paymentaction' => $this->gateway->get_option( 'paymentaction' ),
+ 'bn' => 'WooThemes_Cart',
+ 'invoice' => $this->limit_length( $this->gateway->get_option( 'invoice_prefix' ) . $order->get_order_number(), 127 ),
+ 'custom' => wp_json_encode(
+ array(
+ 'order_id' => $order->get_id(),
+ 'order_key' => $order->get_order_key(),
+ )
+ ),
+ 'notify_url' => $this->limit_length( $this->notify_url, 255 ),
+ 'first_name' => $this->limit_length( $order->get_billing_first_name(), 32 ),
+ 'last_name' => $this->limit_length( $order->get_billing_last_name(), 64 ),
+ 'address1' => $this->limit_length( $order->get_billing_address_1(), 100 ),
+ 'address2' => $this->limit_length( $order->get_billing_address_2(), 100 ),
+ 'city' => $this->limit_length( $order->get_billing_city(), 40 ),
+ 'state' => $this->get_paypal_state( $order->get_billing_country(), $order->get_billing_state() ),
+ 'zip' => $this->limit_length( wc_format_postcode( $order->get_billing_postcode(), $order->get_billing_country() ), 32 ),
+ 'country' => $this->limit_length( $order->get_billing_country(), 2 ),
+ 'email' => $this->limit_length( $order->get_billing_email() ),
+ ),
+ $this->get_phone_number_args( $order ),
+ $this->get_shipping_args( $order ),
+ $this->get_line_item_args( $order, true )
+ ), $order
+ );
+
+ }
+
/**
* Get PayPal Args for passing to PP.
*
@@ -92,51 +161,47 @@ class WC_Gateway_Paypal_Request {
protected function get_paypal_args( $order ) {
WC_Gateway_Paypal::log( 'Generating payment form for order ' . $order->get_order_number() . '. Notify URL: ' . $this->notify_url );
- $initial_paypal_args = array(
- 'cmd' => '_cart',
- 'business' => $this->gateway->get_option( 'email' ),
- 'no_note' => 1,
- 'currency_code' => get_woocommerce_currency(),
- 'charset' => 'utf-8',
- 'rm' => is_ssl() ? 2 : 1,
- 'upload' => 1,
- 'return' => esc_url_raw( add_query_arg( 'utm_nooverride', '1', $this->gateway->get_return_url( $order ) ) ),
- 'cancel_return' => esc_url_raw( $order->get_cancel_order_url_raw() ),
- 'page_style' => $this->gateway->get_option( 'page_style' ),
- 'image_url' => esc_url_raw( $this->gateway->get_option( 'image_url' ) ),
- 'paymentaction' => $this->gateway->get_option( 'paymentaction' ),
- 'bn' => 'WooThemes_Cart',
- 'invoice' => $this->limit_length( $this->gateway->get_option( 'invoice_prefix' ) . $order->get_order_number(), 127 ),
- 'custom' => wp_json_encode(
- array(
- 'order_id' => $order->get_id(),
- 'order_key' => $order->get_order_key(),
- )
- ),
- 'notify_url' => $this->limit_length( $this->notify_url, 255 ),
- 'first_name' => $this->limit_length( $order->get_billing_first_name(), 32 ),
- 'last_name' => $this->limit_length( $order->get_billing_last_name(), 64 ),
- 'address1' => $this->limit_length( $order->get_billing_address_1(), 100 ),
- 'address2' => $this->limit_length( $order->get_billing_address_2(), 100 ),
- 'city' => $this->limit_length( $order->get_billing_city(), 40 ),
- 'state' => $this->get_paypal_state( $order->get_billing_country(), $order->get_billing_state() ),
- 'zip' => $this->limit_length( wc_format_postcode( $order->get_billing_postcode(), $order->get_billing_country() ), 32 ),
- 'country' => $this->limit_length( $order->get_billing_country(), 2 ),
- 'email' => $this->limit_length( $order->get_billing_email() ),
- );
- $phone_number_args = $this->get_phone_number_args( $order );
- $shipping_args = $this->get_shipping_args( $order );
- $query_str_except_line_items = http_build_query( array_merge( $initial_paypal_args, $phone_number_args, $shipping_args ), '', '&' );
- $url_except_line_items_length = strlen( $this->request_url_prefix . $query_str_except_line_items );
-
- return apply_filters(
+ $paypal_args = apply_filters(
'woocommerce_paypal_args', array_merge(
- $initial_paypal_args,
- $phone_number_args,
- $shipping_args,
- $this->get_line_item_args( $order, $url_except_line_items_length )
+ array(
+ 'cmd' => '_cart',
+ 'business' => $this->gateway->get_option( 'email' ),
+ 'no_note' => 1,
+ 'currency_code' => get_woocommerce_currency(),
+ 'charset' => 'utf-8',
+ 'rm' => is_ssl() ? 2 : 1,
+ 'upload' => 1,
+ 'return' => esc_url_raw( add_query_arg( 'utm_nooverride', '1', $this->gateway->get_return_url( $order ) ) ),
+ 'cancel_return' => esc_url_raw( $order->get_cancel_order_url_raw() ),
+ 'page_style' => $this->gateway->get_option( 'page_style' ),
+ 'image_url' => esc_url_raw( $this->gateway->get_option( 'image_url' ) ),
+ 'paymentaction' => $this->gateway->get_option( 'paymentaction' ),
+ 'bn' => 'WooThemes_Cart',
+ 'invoice' => $this->limit_length( $this->gateway->get_option( 'invoice_prefix' ) . $order->get_order_number(), 127 ),
+ 'custom' => wp_json_encode(
+ array(
+ 'order_id' => $order->get_id(),
+ 'order_key' => $order->get_order_key(),
+ )
+ ),
+ 'notify_url' => $this->limit_length( $this->notify_url, 255 ),
+ 'first_name' => $this->limit_length( $order->get_billing_first_name(), 32 ),
+ 'last_name' => $this->limit_length( $order->get_billing_last_name(), 64 ),
+ 'address1' => $this->limit_length( $order->get_billing_address_1(), 100 ),
+ 'address2' => $this->limit_length( $order->get_billing_address_2(), 100 ),
+ 'city' => $this->limit_length( $order->get_billing_city(), 40 ),
+ 'state' => $this->get_paypal_state( $order->get_billing_country(), $order->get_billing_state() ),
+ 'zip' => $this->limit_length( wc_format_postcode( $order->get_billing_postcode(), $order->get_billing_country() ), 32 ),
+ 'country' => $this->limit_length( $order->get_billing_country(), 2 ),
+ 'email' => $this->limit_length( $order->get_billing_email() ),
+ ),
+ $this->get_phone_number_args( $order ),
+ $this->get_shipping_args( $order ),
+ $this->get_line_item_args( $order )
), $order
);
+
+ return $this->fix_request_legth( $order, $paypal_args );
}
/**
@@ -239,35 +304,29 @@ class WC_Gateway_Paypal_Request {
* Get line item args for paypal request.
*
* @param WC_Order $order Order object.
- * @param int $url_except_line_items_length Length of URL without line items.
+ * @param bool $force_one_line_item Create only one item for this order.
* @return array
*/
- protected function get_line_item_args( $order, $url_except_line_items_length ) {
+ protected function get_line_item_args( $order, $force_one_line_item = false ) {
/**
* Try passing a line item per product if supported.
*/
if ( ( ! wc_tax_enabled() || ! wc_prices_include_tax() ) && $this->prepare_line_items( $order ) ) {
- $line_item_args = array();
- $line_item_args['tax_cart'] = $this->number_format( $order->get_total_tax(), $order );
-
- if ( $order->get_total_discount() > 0 ) {
- $line_item_args['discount_amount_cart'] = $this->number_format( $this->round( $order->get_total_discount(), $order ), $order );
- }
-
+ $line_item_args = array();
$include_shipping_tax = false;
- $line_item_args = array_merge( $line_item_args, $this->get_shipping_cost_line_item( $order, $include_shipping_tax ) );
- $line_item_args = array_merge( $line_item_args, $this->get_line_items() );
-
- $line_items_query_str_length = strlen( http_build_query( $line_item_args, '', '&' ) );
-
- // If URL is longer than 2,083 chars, ignore line items and send cart to Paypal as a single item.
- // One item's name can only be 127 characters long, so the URL should not be longer than limit.
- // URL character limit via:
- // https://support.microsoft.com/en-us/help/208427/maximum-url-length-is-2-083-characters-in-internet-explorer
- // +1 for '&' that needs to connect 2 query strings.
- if ( $url_except_line_items_length + 1 + $line_items_query_str_length > 2083 ) {
+ if ( $force_one_line_item ) {
$line_item_args = $this->get_line_item_args_single_item( $order, $include_shipping_tax );
+ } else {
+ $line_item_args['tax_cart'] = $this->number_format( $order->get_total_tax(), $order );
+
+ if ( $order->get_total_discount() > 0 ) {
+ $line_item_args['discount_amount_cart'] = $this->number_format( $this->round( $order->get_total_discount(), $order ), $order );
+ }
+
+ $line_item_args = array_merge( $line_item_args, $this->get_shipping_cost_line_item( $order, $include_shipping_tax ) );
+ $line_item_args = array_merge( $line_item_args, $this->get_line_items() );
+
}
} else {
/**
diff --git a/tests/unit-tests/gateways/paypal/request.php b/tests/unit-tests/gateways/paypal/request.php
index 2840adcde0a..66179069d60 100644
--- a/tests/unit-tests/gateways/paypal/request.php
+++ b/tests/unit-tests/gateways/paypal/request.php
@@ -228,13 +228,16 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
wp_set_current_user( $this->user );
// Paths through code changed by:
- // $sandbox (true/false)
- // wc_tax_enabled() === get_option( 'woocommerce_calc_taxes' ) === 'yes'
- // wc_prices_include_tax() === wc_tax_enabled() && 'yes' === get_option( 'woocommerce_prices_include_tax' );.
+ // - $sandbox (true/false)
+ // - wc_tax_enabled()
+ // - wc_prices_include_tax().
+ // wc_tax_enabled() and wc_prices_include_tax() determine if shipping tax should be included,
+ // these are the correct options.
$correct_options = array(
+ // woocommerce_calc_taxes, woocommerce_prices_include_tax, $shipping_tax_included values.
array( 'no', 'no', false ),
array( 'yes', 'no', false ),
- // array( 'no', 'yes', false ), // this is not a valid option due to definition of wc_prices_include_tax
+ // array( 'no', 'yes', false ), // this is not a valid option due to definition of wc_prices_include_tax()
array( 'yes', 'yes', true ),
);
From a940c0bfca30a194e747d8c4d32db8cb81795901 Mon Sep 17 00:00:00 2001
From: Peter Fabian
Date: Fri, 23 Mar 2018 18:13:50 +0100
Subject: [PATCH 14/34] Apply strip_tags to attributes in loop template
Fixes #19491
---
templates/loop/add-to-cart.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/templates/loop/add-to-cart.php b/templates/loop/add-to-cart.php
index 67182c69576..27c999956fc 100644
--- a/templates/loop/add-to-cart.php
+++ b/templates/loop/add-to-cart.php
@@ -27,7 +27,7 @@ echo apply_filters( 'woocommerce_loop_add_to_cart_link', // WPCS: XSS ok.
esc_url( $product->add_to_cart_url() ),
esc_attr( isset( $args['quantity'] ) ? $args['quantity'] : 1 ),
esc_attr( isset( $args['class'] ) ? $args['class'] : 'button' ),
- isset( $args['attributes'] ) ? wc_implode_html_attributes( $args['attributes'] ) : '',
+ isset( $args['attributes'] ) ? wc_implode_html_attributes( array_map( 'strip_tags', $args['attributes'] ) ) : '',
esc_html( $product->add_to_cart_text() )
),
$product, $args );
From b6860803a513e1c80f2610acc7a0b00136d18915 Mon Sep 17 00:00:00 2001
From: Peter Fabian
Date: Mon, 26 Mar 2018 09:02:51 +0200
Subject: [PATCH 15/34] Fix PHPCS violations
---
templates/loop/add-to-cart.php | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/templates/loop/add-to-cart.php b/templates/loop/add-to-cart.php
index 27c999956fc..edb46e36116 100644
--- a/templates/loop/add-to-cart.php
+++ b/templates/loop/add-to-cart.php
@@ -10,9 +10,8 @@
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
- * @see https://docs.woocommerce.com/document/template-structure/
- * @author WooThemes
- * @package WooCommerce/Templates
+ * @see https://docs.woocommerce.com/document/template-structure/
+ * @package WooCommerce/Templates
* @version 3.3.0
*/
From e19d64e51e6be32c097128696bcb0165a3501e1c Mon Sep 17 00:00:00 2001
From: Peter Fabian
Date: Mon, 26 Mar 2018 11:00:28 +0200
Subject: [PATCH 16/34] Fixed PHPCS violations
---
.../paypal/includes/class-wc-gateway-paypal-request.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
index b462fc42225..8eb541ce756 100644
--- a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
+++ b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
@@ -105,7 +105,7 @@ class WC_Gateway_Paypal_Request {
// If URL is longer than 2,083 chars, ignore line items and send cart to Paypal as a single item.
// One item's name can only be 127 characters long, so the URL should not be longer than limit.
// URL character limit via:
- // https://support.microsoft.com/en-us/help/208427/maximum-url-length-is-2-083-characters-in-internet-explorer
+ // https://support.microsoft.com/en-us/help/208427/maximum-url-length-is-2-083-characters-in-internet-explorer.
if ( strlen( $this->endpoint . $query_candidate ) <= $max_paypal_length ) {
return $paypal_args;
}
From ced5980e792d9da836a9349cc178e512eeaaf632 Mon Sep 17 00:00:00 2001
From: Mike Jolley
Date: Mon, 26 Mar 2018 12:03:00 +0100
Subject: [PATCH 17/34] Tweak `wc_get_price_excluding_tax` to not round the
return value so calculations in admin are not pre-rounded.
---
includes/wc-product-functions.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/includes/wc-product-functions.php b/includes/wc-product-functions.php
index eee69f05bff..23a8c1a7327 100644
--- a/includes/wc-product-functions.php
+++ b/includes/wc-product-functions.php
@@ -999,7 +999,7 @@ function wc_get_price_excluding_tax( $product, $args = array() ) {
$tax_rates = WC_Tax::get_rates( $product->get_tax_class() );
$base_tax_rates = WC_Tax::get_base_tax_rates( $product->get_tax_class( 'unfiltered' ) );
$remove_taxes = apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) ? WC_Tax::calc_tax( $line_price, $base_tax_rates, true ) : WC_Tax::calc_tax( $line_price, $tax_rates, true );
- $return_price = WC_Tax::round( $line_price - wc_round_tax_total( array_sum( $remove_taxes ) ) );
+ $return_price = $line_price - array_sum( $remove_taxes );
} else {
$return_price = $line_price;
}
From 88588eccbcb9c2bbd11d7656f71753862df66cd3 Mon Sep 17 00:00:00 2001
From: Peter Fabian
Date: Mon, 26 Mar 2018 13:05:55 +0200
Subject: [PATCH 18/34] Code duplication removed
Added test for non line item agrument presence
Fixed incorrect comment
---
.../class-wc-gateway-paypal-request.php | 122 ++++++++----------
tests/unit-tests/gateways/paypal/request.php | 9 ++
2 files changed, 60 insertions(+), 71 deletions(-)
diff --git a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
index 8eb541ce756..c887b497505 100644
--- a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
+++ b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
@@ -36,7 +36,7 @@ class WC_Gateway_Paypal_Request {
protected $notify_url;
/**
- * Endpoint for requests from PayPal.
+ * Endpoint for requests to PayPal.
*
* @var string
*/
@@ -91,6 +91,52 @@ class WC_Gateway_Paypal_Request {
return $string;
}
+ /**
+ * Get args for paypal request, except for line item args.
+ *
+ * @param WC_Order $order Order object.
+ *
+ * @return array
+ */
+ protected function get_non_line_item_args( $order ) {
+ return array_merge(
+ array(
+ 'cmd' => '_cart',
+ 'business' => $this->gateway->get_option( 'email' ),
+ 'no_note' => 1,
+ 'currency_code' => get_woocommerce_currency(),
+ 'charset' => 'utf-8',
+ 'rm' => is_ssl() ? 2 : 1,
+ 'upload' => 1,
+ 'return' => esc_url_raw( add_query_arg( 'utm_nooverride', '1', $this->gateway->get_return_url( $order ) ) ),
+ 'cancel_return' => esc_url_raw( $order->get_cancel_order_url_raw() ),
+ 'page_style' => $this->gateway->get_option( 'page_style' ),
+ 'image_url' => esc_url_raw( $this->gateway->get_option( 'image_url' ) ),
+ 'paymentaction' => $this->gateway->get_option( 'paymentaction' ),
+ 'bn' => 'WooThemes_Cart',
+ 'invoice' => $this->limit_length( $this->gateway->get_option( 'invoice_prefix' ) . $order->get_order_number(), 127 ),
+ 'custom' => wp_json_encode(
+ array(
+ 'order_id' => $order->get_id(),
+ 'order_key' => $order->get_order_key(),
+ )
+ ),
+ 'notify_url' => $this->limit_length( $this->notify_url, 255 ),
+ 'first_name' => $this->limit_length( $order->get_billing_first_name(), 32 ),
+ 'last_name' => $this->limit_length( $order->get_billing_last_name(), 64 ),
+ 'address1' => $this->limit_length( $order->get_billing_address_1(), 100 ),
+ 'address2' => $this->limit_length( $order->get_billing_address_2(), 100 ),
+ 'city' => $this->limit_length( $order->get_billing_city(), 40 ),
+ 'state' => $this->get_paypal_state( $order->get_billing_country(), $order->get_billing_state() ),
+ 'zip' => $this->limit_length( wc_format_postcode( $order->get_billing_postcode(), $order->get_billing_country() ), 32 ),
+ 'country' => $this->limit_length( $order->get_billing_country(), 2 ),
+ 'email' => $this->limit_length( $order->get_billing_email() ),
+ ),
+ $this->get_phone_number_args( $order ),
+ $this->get_shipping_args( $order )
+ );
+ }
+
/**
* If the default request with line items is too long, generate a new one with only one line item.
*
@@ -99,7 +145,7 @@ class WC_Gateway_Paypal_Request {
*
* @return array
*/
- protected function fix_request_legth( $order, $paypal_args ) {
+ protected function fix_request_length( $order, $paypal_args ) {
$max_paypal_length = 2083;
$query_candidate = http_build_query( $paypal_args, '', '&' );
// If URL is longer than 2,083 chars, ignore line items and send cart to Paypal as a single item.
@@ -112,40 +158,7 @@ class WC_Gateway_Paypal_Request {
return apply_filters(
'woocommerce_paypal_args', array_merge(
- array(
- 'cmd' => '_cart',
- 'business' => $this->gateway->get_option( 'email' ),
- 'no_note' => 1,
- 'currency_code' => get_woocommerce_currency(),
- 'charset' => 'utf-8',
- 'rm' => is_ssl() ? 2 : 1,
- 'upload' => 1,
- 'return' => esc_url_raw( add_query_arg( 'utm_nooverride', '1', $this->gateway->get_return_url( $order ) ) ),
- 'cancel_return' => esc_url_raw( $order->get_cancel_order_url_raw() ),
- 'page_style' => $this->gateway->get_option( 'page_style' ),
- 'image_url' => esc_url_raw( $this->gateway->get_option( 'image_url' ) ),
- 'paymentaction' => $this->gateway->get_option( 'paymentaction' ),
- 'bn' => 'WooThemes_Cart',
- 'invoice' => $this->limit_length( $this->gateway->get_option( 'invoice_prefix' ) . $order->get_order_number(), 127 ),
- 'custom' => wp_json_encode(
- array(
- 'order_id' => $order->get_id(),
- 'order_key' => $order->get_order_key(),
- )
- ),
- 'notify_url' => $this->limit_length( $this->notify_url, 255 ),
- 'first_name' => $this->limit_length( $order->get_billing_first_name(), 32 ),
- 'last_name' => $this->limit_length( $order->get_billing_last_name(), 64 ),
- 'address1' => $this->limit_length( $order->get_billing_address_1(), 100 ),
- 'address2' => $this->limit_length( $order->get_billing_address_2(), 100 ),
- 'city' => $this->limit_length( $order->get_billing_city(), 40 ),
- 'state' => $this->get_paypal_state( $order->get_billing_country(), $order->get_billing_state() ),
- 'zip' => $this->limit_length( wc_format_postcode( $order->get_billing_postcode(), $order->get_billing_country() ), 32 ),
- 'country' => $this->limit_length( $order->get_billing_country(), 2 ),
- 'email' => $this->limit_length( $order->get_billing_email() ),
- ),
- $this->get_phone_number_args( $order ),
- $this->get_shipping_args( $order ),
+ $this->get_non_line_item_args( $order ),
$this->get_line_item_args( $order, true )
), $order
);
@@ -163,45 +176,12 @@ class WC_Gateway_Paypal_Request {
$paypal_args = apply_filters(
'woocommerce_paypal_args', array_merge(
- array(
- 'cmd' => '_cart',
- 'business' => $this->gateway->get_option( 'email' ),
- 'no_note' => 1,
- 'currency_code' => get_woocommerce_currency(),
- 'charset' => 'utf-8',
- 'rm' => is_ssl() ? 2 : 1,
- 'upload' => 1,
- 'return' => esc_url_raw( add_query_arg( 'utm_nooverride', '1', $this->gateway->get_return_url( $order ) ) ),
- 'cancel_return' => esc_url_raw( $order->get_cancel_order_url_raw() ),
- 'page_style' => $this->gateway->get_option( 'page_style' ),
- 'image_url' => esc_url_raw( $this->gateway->get_option( 'image_url' ) ),
- 'paymentaction' => $this->gateway->get_option( 'paymentaction' ),
- 'bn' => 'WooThemes_Cart',
- 'invoice' => $this->limit_length( $this->gateway->get_option( 'invoice_prefix' ) . $order->get_order_number(), 127 ),
- 'custom' => wp_json_encode(
- array(
- 'order_id' => $order->get_id(),
- 'order_key' => $order->get_order_key(),
- )
- ),
- 'notify_url' => $this->limit_length( $this->notify_url, 255 ),
- 'first_name' => $this->limit_length( $order->get_billing_first_name(), 32 ),
- 'last_name' => $this->limit_length( $order->get_billing_last_name(), 64 ),
- 'address1' => $this->limit_length( $order->get_billing_address_1(), 100 ),
- 'address2' => $this->limit_length( $order->get_billing_address_2(), 100 ),
- 'city' => $this->limit_length( $order->get_billing_city(), 40 ),
- 'state' => $this->get_paypal_state( $order->get_billing_country(), $order->get_billing_state() ),
- 'zip' => $this->limit_length( wc_format_postcode( $order->get_billing_postcode(), $order->get_billing_country() ), 32 ),
- 'country' => $this->limit_length( $order->get_billing_country(), 2 ),
- 'email' => $this->limit_length( $order->get_billing_email() ),
- ),
- $this->get_phone_number_args( $order ),
- $this->get_shipping_args( $order ),
+ $this->get_non_line_item_args( $order ),
$this->get_line_item_args( $order )
), $order
);
- return $this->fix_request_legth( $order, $paypal_args );
+ return $this->fix_request_length( $order, $paypal_args );
}
/**
diff --git a/tests/unit-tests/gateways/paypal/request.php b/tests/unit-tests/gateways/paypal/request.php
index 66179069d60..8bb7617fc3c 100644
--- a/tests/unit-tests/gateways/paypal/request.php
+++ b/tests/unit-tests/gateways/paypal/request.php
@@ -167,6 +167,10 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
// Check that there is actually only one item for order with URL length > limit.
$this->assertFalse( array_key_exists( 'item_name_2', $query_array ) );
+ // Check that non-line item parameters are included.
+ $this->assertTrue( array_key_exists( 'cmd', $query_array ) );
+ $this->assertEquals( '_cart', $query_array['cmd'] );
+
$this->check_shipping_tax( $query_array, $shipping_tax_included );
// Remove order and created products.
@@ -206,6 +210,11 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
$this->assertTrue( array_key_exists( 'amount_' . $i, $query_array ) );
$this->assertTrue( array_key_exists( 'item_number_' . $i, $query_array ) );
+ // Check that non-line item parameters are included.
+ $this->assertTrue( array_key_exists( 'cmd', $query_array ) );
+ $this->assertEquals( '_cart', $query_array['cmd'] );
+
+
$this->assertLessThanOrEqual( 127, strlen( $query_array[ 'item_name_' . $i ] ) );
$this->assertLessThanOrEqual( 127, strlen( $query_array[ 'item_number_' . $i ] ) );
From f6d748a812b8ade535858096c62ba6022a641ed6 Mon Sep 17 00:00:00 2001
From: Peter Fabian
Date: Mon, 26 Mar 2018 13:31:29 +0200
Subject: [PATCH 19/34] Fixed PHPCS violation
---
tests/unit-tests/gateways/paypal/request.php | 1 -
1 file changed, 1 deletion(-)
diff --git a/tests/unit-tests/gateways/paypal/request.php b/tests/unit-tests/gateways/paypal/request.php
index 8bb7617fc3c..0ba20e10f16 100644
--- a/tests/unit-tests/gateways/paypal/request.php
+++ b/tests/unit-tests/gateways/paypal/request.php
@@ -214,7 +214,6 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
$this->assertTrue( array_key_exists( 'cmd', $query_array ) );
$this->assertEquals( '_cart', $query_array['cmd'] );
-
$this->assertLessThanOrEqual( 127, strlen( $query_array[ 'item_name_' . $i ] ) );
$this->assertLessThanOrEqual( 127, strlen( $query_array[ 'item_number_' . $i ] ) );
From 97c591a5e5920a4e838849a0606102791df0131b Mon Sep 17 00:00:00 2001
From: Jonathan Belcher
Date: Mon, 26 Mar 2018 13:44:16 -0400
Subject: [PATCH 20/34] Add escaping to piblish date
---
templates/single-product/review-meta.php | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/templates/single-product/review-meta.php b/templates/single-product/review-meta.php
index 991432fae28..ab7ab0db9cb 100644
--- a/templates/single-product/review-meta.php
+++ b/templates/single-product/review-meta.php
@@ -36,7 +36,10 @@ if ( '0' === $comment->comment_approved ) { ?>
echo '(' . esc_attr__( 'verified owner', 'woocommerce' ) . ') ';
}
- ?>–
+ ?>–
+
Date: Mon, 26 Mar 2018 13:51:24 -0400
Subject: [PATCH 21/34] Fixes stray space in tabbing
---
templates/single-product/up-sells.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/templates/single-product/up-sells.php b/templates/single-product/up-sells.php
index 75ca4e40c22..baaa90e753e 100644
--- a/templates/single-product/up-sells.php
+++ b/templates/single-product/up-sells.php
@@ -31,7 +31,7 @@ if ( $upsells ) : ?>
get_id() );
+ $post_object = get_post( $upsell->get_id() );
setup_postdata( $GLOBALS['post'] =& $post_object );
From dd3b99885139c23144de889daeb1881066ec1c46 Mon Sep 17 00:00:00 2001
From: Mike Jolley
Date: Tue, 27 Mar 2018 13:00:19 +0100
Subject: [PATCH 22/34] Tweak wording for opt-out
---
.../admin/class-wc-admin-setup-wizard.php | 19 ++++---------------
1 file changed, 4 insertions(+), 15 deletions(-)
diff --git a/includes/admin/class-wc-admin-setup-wizard.php b/includes/admin/class-wc-admin-setup-wizard.php
index 77af416eac3..b067a2c18a6 100644
--- a/includes/admin/class-wc-admin-setup-wizard.php
+++ b/includes/admin/class-wc-admin-setup-wizard.php
@@ -489,26 +489,15 @@ class WC_Admin_Setup_Wizard {
countries->get_european_union_countries(), true ) ) {
- $tracking_opt_out = false;
- }
-
- // Respect the DNT header.
- if ( ! empty( $_SERVER['HTTP_DNT'] ) ) { // WPCS: input var ok.
- $tracking_opt_out = false;
- }
?>
- />
-
+
+
' . esc_html__( 'Read more about what we collect.', 'woocommerce' ) . '';
?>
@@ -537,7 +526,7 @@ class WC_Admin_Setup_Wizard {
$currency_code = sanitize_text_field( $_POST['currency_code'] );
$product_type = sanitize_text_field( $_POST['product_type'] );
$sell_in_person = isset( $_POST['sell_in_person'] ) && ( 'yes' === sanitize_text_field( $_POST['sell_in_person'] ) );
- $tracking = isset( $_POST['wc_tracker_optin'] ) && ( 'yes' === sanitize_text_field( $_POST['wc_tracker_optin'] ) );
+ $tracking = isset( $_POST['wc_tracker_checkbox'] ) && ( 'yes' === sanitize_text_field( $_POST['wc_tracker_checkbox'] ) );
// @codingStandardsIgnoreEnd
update_option( 'woocommerce_store_address', $address );
update_option( 'woocommerce_store_address_2', $address_2 );
From 0599c06b20a6fd38547588d25f2e3c43a6d4503a Mon Sep 17 00:00:00 2001
From: Mike Jolley
Date: Tue, 27 Mar 2018 13:28:03 +0100
Subject: [PATCH 23/34] Disable Gutenberg for products.
---
includes/class-wc-post-types.php | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/includes/class-wc-post-types.php b/includes/class-wc-post-types.php
index 2849a253d93..09d810292bd 100644
--- a/includes/class-wc-post-types.php
+++ b/includes/class-wc-post-types.php
@@ -26,6 +26,7 @@ class WC_Post_Types {
add_filter( 'rest_api_allowed_post_types', array( __CLASS__, 'rest_api_allowed_post_types' ) );
add_action( 'woocommerce_after_register_post_type', array( __CLASS__, 'maybe_flush_rewrite_rules' ) );
add_action( 'woocommerce_flush_rewrite_rules', array( __CLASS__, 'flush_rewrite_rules' ) );
+ add_filter( 'gutenberg_can_edit_post_type', array( __CLASS__, 'gutenberg_can_edit_post_type' ), 10, 2 );
}
/**
@@ -567,6 +568,17 @@ class WC_Post_Types {
flush_rewrite_rules();
}
+ /**
+ * Disable Gutenberg for products.
+ *
+ * @param bool $can_edit Whether the post type can be edited or not.
+ * @param string $post_type The post type being checked.
+ * @return bool
+ */
+ public static function gutenberg_can_edit_post_type( $can_edit, $post_type ) {
+ return 'product' === $post_type ? false : $can_edit;
+ }
+
/**
* Add Product Support to Jetpack Omnisearch.
*/
From 5eda49f98a8dbe7bad3073eb3a366d29fc84c4f0 Mon Sep 17 00:00:00 2001
From: Peter Fabian
Date: Tue, 27 Mar 2018 15:55:03 +0200
Subject: [PATCH 24/34] Line item logic refactored
Renamed function get_non_line_item_args
Documentation updates
...all part of code review fixes
---
.../class-wc-gateway-paypal-request.php | 52 +++---
tests/unit-tests/gateways/paypal/request.php | 152 ++++++++++++++----
2 files changed, 149 insertions(+), 55 deletions(-)
diff --git a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
index c887b497505..0e2b5b1f683 100644
--- a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
+++ b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
@@ -92,13 +92,12 @@ class WC_Gateway_Paypal_Request {
}
/**
- * Get args for paypal request, except for line item args.
+ * Get transaction args for paypal request, except for line item args.
*
* @param WC_Order $order Order object.
- *
* @return array
*/
- protected function get_non_line_item_args( $order ) {
+ protected function get_transaction_args( $order ) {
return array_merge(
array(
'cmd' => '_cart',
@@ -140,25 +139,26 @@ class WC_Gateway_Paypal_Request {
/**
* If the default request with line items is too long, generate a new one with only one line item.
*
+ * If URL is longer than 2,083 chars, ignore line items and send cart to Paypal as a single item.
+ * One item's name can only be 127 characters long, so the URL should not be longer than limit.
+ * URL character limit via:
+ * https://support.microsoft.com/en-us/help/208427/maximum-url-length-is-2-083-characters-in-internet-explorer.
+ *
* @param WC_Order $order Order to be sent to Paypal.
* @param array $paypal_args Arguments sent to Paypal in the request.
- *
* @return array
*/
protected function fix_request_length( $order, $paypal_args ) {
$max_paypal_length = 2083;
$query_candidate = http_build_query( $paypal_args, '', '&' );
- // If URL is longer than 2,083 chars, ignore line items and send cart to Paypal as a single item.
- // One item's name can only be 127 characters long, so the URL should not be longer than limit.
- // URL character limit via:
- // https://support.microsoft.com/en-us/help/208427/maximum-url-length-is-2-083-characters-in-internet-explorer.
+
if ( strlen( $this->endpoint . $query_candidate ) <= $max_paypal_length ) {
return $paypal_args;
}
return apply_filters(
'woocommerce_paypal_args', array_merge(
- $this->get_non_line_item_args( $order ),
+ $this->get_transaction_args( $order ),
$this->get_line_item_args( $order, true )
), $order
);
@@ -176,7 +176,7 @@ class WC_Gateway_Paypal_Request {
$paypal_args = apply_filters(
'woocommerce_paypal_args', array_merge(
- $this->get_non_line_item_args( $order ),
+ $this->get_transaction_args( $order ),
$this->get_line_item_args( $order )
), $order
);
@@ -293,29 +293,31 @@ class WC_Gateway_Paypal_Request {
* Try passing a line item per product if supported.
*/
if ( ( ! wc_tax_enabled() || ! wc_prices_include_tax() ) && $this->prepare_line_items( $order ) ) {
- $line_item_args = array();
$include_shipping_tax = false;
- if ( $force_one_line_item ) {
- $line_item_args = $this->get_line_item_args_single_item( $order, $include_shipping_tax );
- } else {
- $line_item_args['tax_cart'] = $this->number_format( $order->get_total_tax(), $order );
-
- if ( $order->get_total_discount() > 0 ) {
- $line_item_args['discount_amount_cart'] = $this->number_format( $this->round( $order->get_total_discount(), $order ), $order );
- }
-
- $line_item_args = array_merge( $line_item_args, $this->get_shipping_cost_line_item( $order, $include_shipping_tax ) );
- $line_item_args = array_merge( $line_item_args, $this->get_line_items() );
-
- }
} else {
+ $include_shipping_tax = true;
+ }
+
+ $line_item_args = array();
+ if ( $force_one_line_item || $include_shipping_tax ) {
/**
* Send order as a single item.
*
* For shipping, we longer use shipping_1 because paypal ignores it if *any* shipping rules are within paypal, and paypal ignores anything over 5 digits (999.99 is the max).
*/
- $include_shipping_tax = true;
$line_item_args = $this->get_line_item_args_single_item( $order, $include_shipping_tax );
+ } else {
+ /**
+ * Passing a line item per product if supported.
+ */
+ $line_item_args['tax_cart'] = $this->number_format( $order->get_total_tax(), $order );
+
+ if ( $order->get_total_discount() > 0 ) {
+ $line_item_args['discount_amount_cart'] = $this->number_format( $this->round( $order->get_total_discount(), $order ), $order );
+ }
+
+ $line_item_args = array_merge( $line_item_args, $this->get_shipping_cost_line_item( $order, $include_shipping_tax ) );
+ $line_item_args = array_merge( $line_item_args, $this->get_line_items() );
}
diff --git a/tests/unit-tests/gateways/paypal/request.php b/tests/unit-tests/gateways/paypal/request.php
index 0ba20e10f16..8f576be8bde 100644
--- a/tests/unit-tests/gateways/paypal/request.php
+++ b/tests/unit-tests/gateways/paypal/request.php
@@ -4,11 +4,22 @@
*
* @package WooCommerce\Tests\Gateways\Paypal
*/
-
class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
+ /**
+ * Products to use in order.
+ *
+ * @var array
+ */
protected $products;
+ /**
+ * Order to submit to PayPal.
+ *
+ * @var WC_Order
+ */
+ protected $order;
+
/**
* Create $product_count simple products and store them in $this->products.
*
@@ -34,26 +45,30 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
/**
* Add products from $this->products to $order as items, clearing existing order items.
*
- * @param WC_Order $order Order to which the products should be added.
+ * @param WC_Order $order Order to which the products should be added.
+ * @param array $prices Array of prices to use for created products. Leave empty for default prices.
*/
- protected function add_products_to_order( $order ) {
+ protected function add_products_to_order( $order, $prices = array() ) {
// Remove previous items.
foreach ( $order->get_items() as $item ) {
$order->remove_item( $item->get_id() );
}
// Add new products.
+ $prod_count = 0;
foreach ( $this->products as $product ) {
$item = new WC_Order_Item_Product();
$item->set_props( array(
'product' => $product,
'quantity' => 3,
- 'subtotal' => wc_get_price_excluding_tax( $product, array( 'qty' => 3 ) ),
- 'total' => wc_get_price_excluding_tax( $product, array( 'qty' => 3 ) ),
+ 'subtotal' => $prices ? $prices[ $prod_count ] : wc_get_price_excluding_tax( $product, array( 'qty' => 3 ) ),
+ 'total' => $prices ? $prices[ $prod_count ] : wc_get_price_excluding_tax( $product, array( 'qty' => 3 ) ),
) );
$item->save();
$order->add_item( $item );
+
+ $prod_count++;
}
}
@@ -75,33 +90,65 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
/**
* Create Paypal request URL for $product_count number of products.
*
- * @param int $product_count Number of products to include in the order.
- * @param bool $testmode Whether to test using sandbox or not.
- *
+ * @param int $product_count Number of products to include in the order.
+ * @param bool $testmode Whether to test using sandbox or not.
+ * @param array $product_prices Array of prices to use for created products. Leave empty for default prices.
+ * @param bool $calc_order_totals Whether the WC_Order::calculate_totals() should be triggered when creating order.
* @return string
* @throws WC_Data_Exception
*/
- protected function get_request_url( $product_count, $testmode ) {
+ protected function get_request_url( $product_count, $testmode, $product_prices = array(), $calc_order_totals = true ) {
// Create products.
$this->create_products( $product_count );
$this->order = WC_Helper_Order::create_order( $this->user );
- $this->add_products_to_order( $this->order );
+ $this->add_products_to_order( $this->order, $product_prices );
// Set payment method to Paypal.
$payment_gateways = WC()->payment_gateways->payment_gateways();
$this->order->set_payment_method( $payment_gateways['paypal'] );
- $this->order->calculate_totals();
+
+ // Add tax.
+ if ( wc_tax_enabled() ) {
+ $tax_rate = array(
+ 'tax_rate_country' => '',
+ 'tax_rate_state' => '',
+ 'tax_rate' => '11.0000',
+ 'tax_rate_name' => 'TAX',
+ 'tax_rate_priority' => '1',
+ 'tax_rate_compound' => '0',
+ 'tax_rate_shipping' => '1',
+ 'tax_rate_order' => '1',
+ 'tax_rate_class' => '',
+ );
+ WC_Tax::_insert_tax_rate( $tax_rate );
+
+ $tax_item = new WC_Order_Item_Tax();
+ $tax_item->set_rate( 100 );
+ $tax_item->set_tax_total( 100 );
+ $tax_item->set_shipping_tax_total( 100 );
+ $this->order->add_item( $tax_item );
+ $this->order->save();
+ }
+
$this->order->calculate_shipping();
+ if ( $calc_order_totals ) {
+ $this->order->calculate_totals();
+ }
return $this->paypal_request->get_request_url( $this->order, $testmode );
}
/**
- * Clean up order, deletes all products in order, too.
+ * Clean up order, tax, deletes all products in order, too.
*/
protected function clean_up() {
+ global $wpdb;
+ $wpdb->query( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rates" );
+ $wpdb->query( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations" );
+
WC_Helper_Order::delete_order( $this->order->get_id() );
+
}
/**
@@ -116,7 +163,8 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
$shipping_total += $this->order->get_shipping_tax();
}
$epsilon = 0.01;
- $this->assertTrue( abs( $shipping_total - floatval( $query_array['shipping_1'] ) ) < $epsilon );
+ $this->assertTrue( abs( $shipping_total - floatval( $query_array['shipping_1'] ) ) < $epsilon,
+ 'Shipping tax mismatch: shipping total=' . $shipping_total . ' vs request shipping=' . $query_array['shipping_1'] );
}
@@ -140,12 +188,10 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
*
* @param bool $shipping_tax_included Whether the shipping tax should be included or not.
* @param bool $testmode Whether to use Paypal sandbox.
- *
* @throws WC_Data_Exception
*/
protected function check_large_order( $shipping_tax_included, $testmode ) {
$request_url = $this->get_request_url( 30, $testmode );
-
$this->check_order_common_props( $request_url, $testmode );
// Check fields limited to 127 characters for length.
@@ -178,18 +224,29 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
}
+
+ /**
+ * Return true if value is < 0, false otherwise.
+ *
+ * @param int|float $value Tested value.
+ * @return bool
+ */
+ protected function is_negative( $value ) {
+ return $value < 0;
+ }
+
/**
* Test small order with fewer items, URL length should be < 2083 characters.
*
- * @param int $product_count Number of products to include in the order.
- * @param bool $shipping_tax_included Whether the shipping tax should be included or not.
- * @param bool $testmode Whether to use Paypal sandbox.
- *
+ * @param int $product_count Number of products to include in the order.
+ * @param bool $shipping_tax_included Whether the shipping tax should be included or not.
+ * @param bool $testmode Whether to use Paypal sandbox.
+ * @param array $product_prices Array of prices to use for created products. Leave empty for default prices.
+ * @param bool $calc_order_totals Whether the WC_Order::calculate_totals() should be triggered when creating order.
* @throws WC_Data_Exception
*/
- protected function check_small_order( $product_count, $shipping_tax_included, $testmode ) {
- $request_url = $this->get_request_url( $product_count, $testmode );
-
+ protected function check_small_order( $product_count, $shipping_tax_included, $testmode, $product_prices = array(), $calc_order_totals = true ) {
+ $request_url = $this->get_request_url( $product_count, $testmode, $product_prices, $calc_order_totals );
$this->check_order_common_props( $request_url, $testmode );
$query_string = wp_parse_url( $request_url, PHP_URL_QUERY )
@@ -200,7 +257,7 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
// Check that there are $product_count line items in the request URL.
// However, if shipping tax is included, there is only one item.
- if ( $shipping_tax_included ) {
+ if ( $shipping_tax_included || array_filter( $product_prices, array( $this, 'is_negative' ) ) || ! $calc_order_totals ) {
$product_count = 1;
}
@@ -226,6 +283,36 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
}
/**
+ * Test order with one product having negative amount.
+ * Amount < 0 forces tax inclusion and single line item, since WC_Gateway_Paypal_Request::prepare_line_items()
+ * will return false.
+ *
+ * @param bool $testmode Whether PayPal request should point to sandbox or live production.
+ * @throws WC_Data_Exception
+ */
+ protected function check_negative_amount( $testmode ) {
+ $shipping_tax_included = true;
+ $product_prices = array( 6, 6, 6, 6, -3 );
+ $this->check_small_order( count( $product_prices ), $shipping_tax_included, $testmode, $product_prices );
+ }
+
+ /**
+ * Test order with totals mismatched.
+ * This forces tax inclusion and single line item, since WC_Gateway_Paypal_Request::prepare_line_items()
+ * will return false.
+ *
+ * @param bool $testmode Whether PayPal request should point to sandbox or live production.
+ * @throws WC_Data_Exception
+ */
+ protected function check_totals_mismatch( $testmode ) {
+ // totals mismatch forces tax inclusion and single line item.
+ $shipping_tax_included = true;
+ $this->check_small_order( 5, $shipping_tax_included, $testmode, array(), false );
+ }
+
+ /**
+ * Test for request_url() method.
+ *
* @throws WC_Data_Exception
*/
public function test_request_url() {
@@ -235,17 +322,16 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
) );
wp_set_current_user( $this->user );
- // Paths through code changed by:
- // - $sandbox (true/false)
- // - wc_tax_enabled()
- // - wc_prices_include_tax().
- // wc_tax_enabled() and wc_prices_include_tax() determine if shipping tax should be included,
- // these are the correct options.
+ // wc_tax_enabled(), wc_prices_include_tax() and WC_Gateway_Paypal_Request::prepare_line_items() determine if
+ // shipping tax should be included, these are the correct options.
+ // Note that prepare_line_items() can return false in 2 cases, tested separately below:
+ // - order totals mismatch and
+ // - item amount < 0.
$correct_options = array(
// woocommerce_calc_taxes, woocommerce_prices_include_tax, $shipping_tax_included values.
array( 'no', 'no', false ),
array( 'yes', 'no', false ),
- // array( 'no', 'yes', false ), // this is not a valid option due to definition of wc_prices_include_tax()
+ // array( 'no', 'yes', false ), // this is not a valid option due to definition of wc_prices_include_tax().
array( 'yes', 'yes', true ),
);
@@ -272,6 +358,12 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
// Test order with URL longer than limit.
$this->check_large_order( $shipping_tax_included, $testmode );
+ // Test amount < 0.
+ $this->check_negative_amount( $testmode );
+
+ // Check order totals mismatch.
+ $this->check_totals_mismatch( $testmode );
+
}
}
From f39e8e39002b2c7bfbac2e24b8d4ece0c5f0eb16 Mon Sep 17 00:00:00 2001
From: Peter Fabian
Date: Tue, 27 Mar 2018 16:28:25 +0200
Subject: [PATCH 25/34] Removed incorrect comment
---
.../paypal/includes/class-wc-gateway-paypal-request.php | 3 ---
1 file changed, 3 deletions(-)
diff --git a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
index 0e2b5b1f683..4afd4cdf7e7 100644
--- a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
+++ b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
@@ -289,9 +289,6 @@ class WC_Gateway_Paypal_Request {
*/
protected function get_line_item_args( $order, $force_one_line_item = false ) {
- /**
- * Try passing a line item per product if supported.
- */
if ( ( ! wc_tax_enabled() || ! wc_prices_include_tax() ) && $this->prepare_line_items( $order ) ) {
$include_shipping_tax = false;
} else {
From 86f1b3701fd8486eb9a41b4eb8cb0e4bacddda98 Mon Sep 17 00:00:00 2001
From: Peter Fabian
Date: Tue, 27 Mar 2018 17:19:49 +0200
Subject: [PATCH 26/34] Tag stripped outside template
Stripping only affects aria-label attribute now.
---
includes/wc-template-functions.php | 4 ++++
templates/loop/add-to-cart.php | 7 ++++---
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/includes/wc-template-functions.php b/includes/wc-template-functions.php
index 617499ab525..febfcf4d870 100644
--- a/includes/wc-template-functions.php
+++ b/includes/wc-template-functions.php
@@ -893,6 +893,10 @@ if ( ! function_exists( 'woocommerce_template_loop_add_to_cart' ) ) {
$args = apply_filters( 'woocommerce_loop_add_to_cart_args', wp_parse_args( $args, $defaults ), $product );
+ if ( array_key_exists( 'attributes', $args ) && array_key_exists( 'aria-label', $args['attributes'] ) ) {
+ $args['attributes']['aria-label'] = strip_tags( $args['attributes']['aria-label'] );
+ }
+
wc_get_template( 'loop/add-to-cart.php', $args );
}
}
diff --git a/templates/loop/add-to-cart.php b/templates/loop/add-to-cart.php
index edb46e36116..67182c69576 100644
--- a/templates/loop/add-to-cart.php
+++ b/templates/loop/add-to-cart.php
@@ -10,8 +10,9 @@
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
- * @see https://docs.woocommerce.com/document/template-structure/
- * @package WooCommerce/Templates
+ * @see https://docs.woocommerce.com/document/template-structure/
+ * @author WooThemes
+ * @package WooCommerce/Templates
* @version 3.3.0
*/
@@ -26,7 +27,7 @@ echo apply_filters( 'woocommerce_loop_add_to_cart_link', // WPCS: XSS ok.
esc_url( $product->add_to_cart_url() ),
esc_attr( isset( $args['quantity'] ) ? $args['quantity'] : 1 ),
esc_attr( isset( $args['class'] ) ? $args['class'] : 'button' ),
- isset( $args['attributes'] ) ? wc_implode_html_attributes( array_map( 'strip_tags', $args['attributes'] ) ) : '',
+ isset( $args['attributes'] ) ? wc_implode_html_attributes( $args['attributes'] ) : '',
esc_html( $product->add_to_cart_text() )
),
$product, $args );
From 435337c3e0353ecfdf6c28756a0e1aba2cf72844 Mon Sep 17 00:00:00 2001
From: Jonathan Belcher
Date: Tue, 27 Mar 2018 11:51:47 -0400
Subject: [PATCH 27/34] Bump version Number
---
templates/single-product/review-meta.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/templates/single-product/review-meta.php b/templates/single-product/review-meta.php
index ab7ab0db9cb..e84269bd8be 100644
--- a/templates/single-product/review-meta.php
+++ b/templates/single-product/review-meta.php
@@ -13,7 +13,7 @@
* @see https://docs.woocommerce.com/document/template-structure/
* @author WooThemes
* @package WooCommerce/Templates
- * @version 3.0.0
+ * @version 3.4.0
*/
if ( ! defined( 'ABSPATH' ) ) {
From 80ec10fc21e0ff18a199a51178d0cdf8d8c3dae0 Mon Sep 17 00:00:00 2001
From: Gerhard Potgieter
Date: Wed, 28 Mar 2018 08:28:13 +0200
Subject: [PATCH 28/34] Fix unit test for import, the way the test is set up it
expects a no for backorders and not an empty string
---
tests/unit-tests/importer/product.php | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/tests/unit-tests/importer/product.php b/tests/unit-tests/importer/product.php
index 28f4fe9d5ac..01633f00408 100644
--- a/tests/unit-tests/importer/product.php
+++ b/tests/unit-tests/importer/product.php
@@ -306,7 +306,7 @@ class WC_Tests_Product_CSV_Importer extends WC_Unit_Test_Case {
'tax_class' => 'standard',
'stock_status' => 'instock',
'stock_quantity' => '',
- 'backorders' => '',
+ 'backorders' => 'no',
'sold_individually' => '',
'weight' => '',
'length' => '',
@@ -358,7 +358,7 @@ class WC_Tests_Product_CSV_Importer extends WC_Unit_Test_Case {
'tax_class' => 'standard',
'stock_status' => 'instock',
'stock_quantity' => '',
- 'backorders' => '',
+ 'backorders' => 'no',
'sold_individually' => '',
'weight' => '',
'length' => '',
@@ -394,7 +394,7 @@ class WC_Tests_Product_CSV_Importer extends WC_Unit_Test_Case {
'tax_class' => '',
'stock_status' => 'outofstock',
'stock_quantity' => '',
- 'backorders' => '',
+ 'backorders' => 'no',
'sold_individually' => '',
'weight' => '',
'length' => '',
@@ -446,7 +446,7 @@ class WC_Tests_Product_CSV_Importer extends WC_Unit_Test_Case {
'tax_class' => 'standard',
'stock_status' => 'instock',
'stock_quantity' => 6,
- 'backorders' => '',
+ 'backorders' => 'no',
'sold_individually' => '',
'weight' => 1.0,
'length' => 2.0,
@@ -536,7 +536,7 @@ class WC_Tests_Product_CSV_Importer extends WC_Unit_Test_Case {
'tax_class' => '',
'stock_status' => 'instock',
'stock_quantity' => '',
- 'backorders' => '',
+ 'backorders' => 'no',
'sold_individually' => '',
'weight' => '',
'length' => '',
From 1f2468ca3e23372b98986351adf27791b6630f97 Mon Sep 17 00:00:00 2001
From: Gerhard Potgieter
Date: Wed, 28 Mar 2018 09:47:15 +0200
Subject: [PATCH 29/34] When no per_page is defined for list wp-cli command
default to displaying all items as per the wp-cli standard.
---
includes/cli/class-wc-cli-rest-command.php | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/includes/cli/class-wc-cli-rest-command.php b/includes/cli/class-wc-cli-rest-command.php
index be2a050835d..9a5adca6fb9 100644
--- a/includes/cli/class-wc-cli-rest-command.php
+++ b/includes/cli/class-wc-cli-rest-command.php
@@ -223,6 +223,10 @@ class WC_CLI_REST_Command {
$assoc_args['format'] = 'table';
}
+ if ( empty( $assoc_args['per_page'] ) ) {
+ $assoc_args['per_page'] = '-1';
+ }
+
if ( ! empty( $assoc_args['format'] ) && 'count' === $assoc_args['format'] ) {
echo (int) $headers['X-WP-Total'];
} elseif ( 'headers' === $assoc_args['format'] ) {
From 9c67760bc07efb2daec275a3ca26a48f9eed696a Mon Sep 17 00:00:00 2001
From: Gerhard Potgieter
Date: Wed, 28 Mar 2018 10:18:10 +0200
Subject: [PATCH 30/34] per_page must be between 1 and 100, default to 100.
---
includes/cli/class-wc-cli-rest-command.php | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/includes/cli/class-wc-cli-rest-command.php b/includes/cli/class-wc-cli-rest-command.php
index 9a5adca6fb9..2b0a218739e 100644
--- a/includes/cli/class-wc-cli-rest-command.php
+++ b/includes/cli/class-wc-cli-rest-command.php
@@ -206,6 +206,10 @@ class WC_CLI_REST_Command {
$method = 'GET';
}
+ if ( ! isset( $assoc_args['per_page'] ) || empty( $assoc_args['per_page'] ) ) {
+ $assoc_args['per_page'] = '100';
+ }
+
list( $status, $body, $headers ) = $this->do_request( $method, $this->get_filled_route( $args ), $assoc_args );
if ( ! empty( $assoc_args['format'] ) && 'ids' === $assoc_args['format'] ) {
$items = array_column( $body, 'id' );
@@ -223,10 +227,6 @@ class WC_CLI_REST_Command {
$assoc_args['format'] = 'table';
}
- if ( empty( $assoc_args['per_page'] ) ) {
- $assoc_args['per_page'] = '-1';
- }
-
if ( ! empty( $assoc_args['format'] ) && 'count' === $assoc_args['format'] ) {
echo (int) $headers['X-WP-Total'];
} elseif ( 'headers' === $assoc_args['format'] ) {
From 59c47c440790009c963ac72634c7de0576f986c6 Mon Sep 17 00:00:00 2001
From: Peter Fabian
Date: Wed, 28 Mar 2018 11:04:34 +0200
Subject: [PATCH 31/34] Refactored line item logic
- prepare_line_items is not used as a test anymore, it only updates line items
- add_line_item is not used as a test anymore, only adds line items
- added method line_items_valid to test for valid line items
- shipping tax inclusion test moved to get_shipping_cost_line_item to encapsulate shipping tax-related logic
---
.../class-wc-gateway-paypal-request.php | 84 ++++++++++---------
1 file changed, 44 insertions(+), 40 deletions(-)
diff --git a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
index 4afd4cdf7e7..bd4a0dc09ec 100644
--- a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
+++ b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
@@ -240,13 +240,12 @@ class WC_Gateway_Paypal_Request {
* Get shipping cost line item args for paypal request.
*
* @param WC_Order $order Order object.
- * @param bool $include_shipping_tax Whether to include shipping tax or not.
* @return array
*/
- protected function get_shipping_cost_line_item( $order, $include_shipping_tax ) {
+ protected function get_shipping_cost_line_item( $order ) {
$line_item_args = array();
$shipping_total = $order->get_shipping_total();
- if ( $include_shipping_tax ) {
+ if ( wc_tax_enabled() && wc_prices_include_tax() || ! $this->line_items_valid( $order ) ) {
$shipping_total += $order->get_shipping_tax();
}
@@ -267,15 +266,14 @@ class WC_Gateway_Paypal_Request {
* Get line item args for paypal request as a single line item.
*
* @param WC_Order $order Order object.
- * @param bool $include_shipping_tax Whether to include shipping tax or not.
* @return array
*/
- protected function get_line_item_args_single_item( $order, $include_shipping_tax ) {
+ protected function get_line_item_args_single_item( $order ) {
$this->delete_line_items();
$all_items_name = $this->get_order_item_names( $order );
$this->add_line_item( $all_items_name ? $all_items_name : __( 'Order', 'woocommerce' ), 1, $this->number_format( $order->get_total() - $this->round( $order->get_shipping_total() + $order->get_shipping_tax(), $order ), $order ), $order->get_order_number() );
- $line_item_args = $this->get_shipping_cost_line_item( $order, $include_shipping_tax );
+ $line_item_args = $this->get_shipping_cost_line_item( $order );
return array_merge( $line_item_args, $this->get_line_items() );
}
@@ -288,32 +286,30 @@ class WC_Gateway_Paypal_Request {
* @return array
*/
protected function get_line_item_args( $order, $force_one_line_item = false ) {
-
- if ( ( ! wc_tax_enabled() || ! wc_prices_include_tax() ) && $this->prepare_line_items( $order ) ) {
- $include_shipping_tax = false;
- } else {
- $include_shipping_tax = true;
+ if ( wc_tax_enabled() && wc_prices_include_tax() || ! $this->line_items_valid( $order ) ) {
+ $force_one_line_item = true;
}
$line_item_args = array();
- if ( $force_one_line_item || $include_shipping_tax ) {
+ if ( $force_one_line_item ) {
/**
* Send order as a single item.
*
* For shipping, we longer use shipping_1 because paypal ignores it if *any* shipping rules are within paypal, and paypal ignores anything over 5 digits (999.99 is the max).
*/
- $line_item_args = $this->get_line_item_args_single_item( $order, $include_shipping_tax );
+ $line_item_args = $this->get_line_item_args_single_item( $order );
} else {
/**
* Passing a line item per product if supported.
*/
+ $this->prepare_line_items( $order );
$line_item_args['tax_cart'] = $this->number_format( $order->get_total_tax(), $order );
if ( $order->get_total_discount() > 0 ) {
$line_item_args['discount_amount_cart'] = $this->number_format( $this->round( $order->get_total_discount(), $order ), $order );
}
- $line_item_args = array_merge( $line_item_args, $this->get_shipping_cost_line_item( $order, $include_shipping_tax ) );
+ $line_item_args = array_merge( $line_item_args, $this->get_shipping_cost_line_item( $order ) );
$line_item_args = array_merge( $line_item_args, $this->get_line_items() );
}
@@ -397,40 +393,55 @@ class WC_Gateway_Paypal_Request {
}
/**
- * Get line items to send to paypal.
+ * Check if the order has valid line items to use for PayPal request.
*
- * @param WC_Order $order Order object.
+ * The line items are invalid in case of mismatch in totals or if any amount < 0.
+ *
+ * @param WC_Order $order Order to be examined.
* @return bool
*/
- protected function prepare_line_items( $order ) {
- $this->delete_line_items();
- $calculated_total = 0;
+ protected function line_items_valid( $order ) {
+ $negative_item_amount = false;
+ $calculated_total = 0;
// Products.
foreach ( $order->get_items( array( 'line_item', 'fee' ) ) as $item ) {
if ( 'fee' === $item['type'] ) {
$item_line_total = $this->number_format( $item['line_total'], $order );
- $line_item = $this->add_line_item( $item->get_name(), 1, $item_line_total );
$calculated_total += $item_line_total;
+ } else {
+ $item_line_total = $this->number_format( $order->get_item_subtotal( $item, false ), $order );
+ $calculated_total += $item_line_total * $item->get_quantity();
+ }
+
+ if ( $item_line_total < 0 ) {
+ $negative_item_amount = true;
+ }
+ }
+ $mismatched_totals = $this->number_format( $calculated_total + $order->get_total_tax() + $this->round( $order->get_shipping_total(), $order ) - $this->round( $order->get_total_discount(), $order ), $order ) !== $this->number_format( $order->get_total(), $order );
+ return ! $negative_item_amount && ! $mismatched_totals;
+ }
+
+ /**
+ * Get line items to send to paypal.
+ *
+ * @param WC_Order $order Order object.
+ */
+ protected function prepare_line_items( $order ) {
+ $this->delete_line_items();
+
+ // Products.
+ foreach ( $order->get_items( array( 'line_item', 'fee' ) ) as $item ) {
+ if ( 'fee' === $item['type'] ) {
+ $item_line_total = $this->number_format( $item['line_total'], $order );
+ $this->add_line_item( $item->get_name(), 1, $item_line_total );
} else {
$product = $item->get_product();
$sku = $product ? $product->get_sku() : '';
$item_line_total = $this->number_format( $order->get_item_subtotal( $item, false ), $order );
- $line_item = $this->add_line_item( $this->get_order_item_name( $order, $item ), $item->get_quantity(), $item_line_total, $sku );
- $calculated_total += $item_line_total * $item->get_quantity();
- }
-
- if ( ! $line_item ) {
- return false;
+ $this->add_line_item( $this->get_order_item_name( $order, $item ), $item->get_quantity(), $item_line_total, $sku );
}
}
-
- // Check for mismatched totals.
- if ( $this->number_format( $calculated_total + $order->get_total_tax() + $this->round( $order->get_shipping_total(), $order ) - $this->round( $order->get_total_discount(), $order ), $order ) !== $this->number_format( $order->get_total(), $order ) ) {
- return false;
- }
-
- return true;
}
/**
@@ -440,15 +451,10 @@ class WC_Gateway_Paypal_Request {
* @param int $quantity Item quantity.
* @param float $amount Amount.
* @param string $item_number Item number.
- * @return bool successfully added or not
*/
protected function add_line_item( $item_name, $quantity = 1, $amount = 0.0, $item_number = '' ) {
$index = ( count( $this->line_items ) / 4 ) + 1;
- if ( $amount < 0 ) {
- return false;
- }
-
$item = apply_filters(
'woocommerce_paypal_line_item', array(
'item_name' => html_entity_decode( wc_trim_string( $item_name ? $item_name : __( 'Item', 'woocommerce' ), 127 ), ENT_NOQUOTES, 'UTF-8' ),
@@ -462,8 +468,6 @@ class WC_Gateway_Paypal_Request {
$this->line_items[ 'quantity_' . $index ] = $item['quantity'];
$this->line_items[ 'amount_' . $index ] = $item['amount'];
$this->line_items[ 'item_number_' . $index ] = $this->limit_length( $item['item_number'], 127 );
-
- return true;
}
/**
From c2e27919cea0458bb4863472c2333760877bb27c Mon Sep 17 00:00:00 2001
From: Peter Fabian
Date: Wed, 28 Mar 2018 11:19:03 +0200
Subject: [PATCH 32/34] Replaced array_key_exists with isset test
---
includes/wc-template-functions.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/includes/wc-template-functions.php b/includes/wc-template-functions.php
index febfcf4d870..d68b1e65466 100644
--- a/includes/wc-template-functions.php
+++ b/includes/wc-template-functions.php
@@ -893,7 +893,7 @@ if ( ! function_exists( 'woocommerce_template_loop_add_to_cart' ) ) {
$args = apply_filters( 'woocommerce_loop_add_to_cart_args', wp_parse_args( $args, $defaults ), $product );
- if ( array_key_exists( 'attributes', $args ) && array_key_exists( 'aria-label', $args['attributes'] ) ) {
+ if ( isset( $args['attributes']['aria-label'] ) ) {
$args['attributes']['aria-label'] = strip_tags( $args['attributes']['aria-label'] );
}
From 8d3c76d980db2962b86070120a354d17bc780c18 Mon Sep 17 00:00:00 2001
From: michakrapp
Date: Wed, 28 Mar 2018 12:18:14 +0200
Subject: [PATCH 33/34] account edit form disble autocomplete for password
fields
---
templates/myaccount/form-edit-account.php | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/templates/myaccount/form-edit-account.php b/templates/myaccount/form-edit-account.php
index c181257952c..e76bcf60b32 100644
--- a/templates/myaccount/form-edit-account.php
+++ b/templates/myaccount/form-edit-account.php
@@ -52,15 +52,15 @@ do_action( 'woocommerce_before_edit_account_form' ); ?>
-
+
-
+
-
+
From 3809ab3f4c0ad15bdcb0ce14491e10ab96b9090f Mon Sep 17 00:00:00 2001
From: Peter Fabian
Date: Wed, 28 Mar 2018 13:08:05 +0200
Subject: [PATCH 34/34] Fixed shipping tax logic to behave the same as
originally
---
.../paypal/includes/class-wc-gateway-paypal-request.php | 9 +++++----
tests/unit-tests/gateways/paypal/request.php | 3 ++-
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
index bd4a0dc09ec..588d15eea10 100644
--- a/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
+++ b/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php
@@ -240,12 +240,13 @@ class WC_Gateway_Paypal_Request {
* Get shipping cost line item args for paypal request.
*
* @param WC_Order $order Order object.
+ * @param bool $force_one_line_item Whether one line item was forced by validation or URL length.
* @return array
*/
- protected function get_shipping_cost_line_item( $order ) {
+ protected function get_shipping_cost_line_item( $order, $force_one_line_item ) {
$line_item_args = array();
$shipping_total = $order->get_shipping_total();
- if ( wc_tax_enabled() && wc_prices_include_tax() || ! $this->line_items_valid( $order ) ) {
+ if ( $force_one_line_item ) {
$shipping_total += $order->get_shipping_tax();
}
@@ -273,7 +274,7 @@ class WC_Gateway_Paypal_Request {
$all_items_name = $this->get_order_item_names( $order );
$this->add_line_item( $all_items_name ? $all_items_name : __( 'Order', 'woocommerce' ), 1, $this->number_format( $order->get_total() - $this->round( $order->get_shipping_total() + $order->get_shipping_tax(), $order ), $order ), $order->get_order_number() );
- $line_item_args = $this->get_shipping_cost_line_item( $order );
+ $line_item_args = $this->get_shipping_cost_line_item( $order, true );
return array_merge( $line_item_args, $this->get_line_items() );
}
@@ -309,7 +310,7 @@ class WC_Gateway_Paypal_Request {
$line_item_args['discount_amount_cart'] = $this->number_format( $this->round( $order->get_total_discount(), $order ), $order );
}
- $line_item_args = array_merge( $line_item_args, $this->get_shipping_cost_line_item( $order ) );
+ $line_item_args = array_merge( $line_item_args, $this->get_shipping_cost_line_item( $order, false ) );
$line_item_args = array_merge( $line_item_args, $this->get_line_items() );
}
diff --git a/tests/unit-tests/gateways/paypal/request.php b/tests/unit-tests/gateways/paypal/request.php
index 8f576be8bde..3c98f1a8f60 100644
--- a/tests/unit-tests/gateways/paypal/request.php
+++ b/tests/unit-tests/gateways/paypal/request.php
@@ -356,7 +356,8 @@ class WC_Tests_Paypal_Gateway_Request extends WC_Unit_Test_Case {
$this->check_small_order( 11, $shipping_tax_included, $testmode );
// Test order with URL longer than limit.
- $this->check_large_order( $shipping_tax_included, $testmode );
+ // Many items in order -> forced to use one line item -> shipping tax included.
+ $this->check_large_order( true, $testmode );
// Test amount < 0.
$this->check_negative_amount( $testmode );