From 876863b065fcf0a5af051071e67e1105aa9bf767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rey=20L=C3=B3pez?= Date: Thu, 20 Dec 2018 10:13:09 +0100 Subject: [PATCH] Fix using the PayPal smart button on a variable product page, or a product with Addons (#507) * Disable the PayPal button in the product page if there are invalid fields in the form * Send the fields added by Product Addons in the PayPal "add to cart" request * Simplify the logic for serializing the form before sending it to the AJAX "add to cart" endpoint * Update changelog --- assets/js/wc-gateway-ppec-generate-cart.js | 72 +++++++++++-------- .../class-wc-gateway-ppec-cart-handler.php | 11 +-- readme.txt | 2 + 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/assets/js/wc-gateway-ppec-generate-cart.js b/assets/js/wc-gateway-ppec-generate-cart.js index d98397e1..f442db04 100644 --- a/assets/js/wc-gateway-ppec-generate-cart.js +++ b/assets/js/wc-gateway-ppec-generate-cart.js @@ -30,52 +30,62 @@ $( '#woo_pp_ec_button_product > *' ).css( 'pointer-events', 'none' ); } ); + // True if the product is simple or the user selected a valid variation. False on variable product without a valid variation selected + var variation_valid = true; + + // True if all the fields of the product form are valid (such as required fields configured by Product Add-Ons). False otherwise + var fields_valid = true; + + var form = $( 'form.cart' ); + + var update_button = function() { + $( '#woo_pp_ec_button_product' ).trigger( ( variation_valid && fields_valid ) ? 'enable' : 'disable' ); + }; + + var validate_form = function() { + fields_valid = form.get( 0 ).checkValidity(); + update_button(); + }; + // It's a variations form, button availability should depend on its events if ( $( '.variations_form' ).length ) { - $( '#woo_pp_ec_button_product' ).trigger( 'disable' ); + variation_valid = false; $( '.variations_form' ) .on( 'show_variation', function( event, form, purchasable ) { - $( '#woo_pp_ec_button_product' ).trigger( purchasable ? 'enable' : 'disable' ); + variation_valid = purchasable; + update_button(); } ) .on( 'hide_variation', function() { - $( '#woo_pp_ec_button_product' ).trigger( 'disable' ); + variation_valid = false; + update_button(); } ); } - var get_attributes = function() { - var select = $( '.variations_form' ).find( '.variations select' ), - data = {}, - count = 0, - chosen = 0; - - select.each( function() { - var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' ); - var value = $( this ).val() || ''; - - if ( value.length > 0 ) { - chosen++; - } - - count++; - data[ attribute_name ] = value; - } ); - - return { - 'count' : count, - 'chosenCount': chosen, - 'data' : data - }; - }; + // Disable the button if there are invalid fields in the product page (like required fields from Product Addons) + form.on( 'change', 'select, input, textarea', function() { + // Hack: IE11 uses the previous field value for the checkValidity() check if it's called in the onChange handler + setTimeout( validate_form, 0 ); + } ); + validate_form(); var generate_cart = function( callback ) { var data = { - 'nonce': wc_ppec_generate_cart_context.generate_cart_nonce, - 'qty': $( '.quantity .qty' ).val(), - 'attributes': $( '.variations_form' ).length ? get_attributes().data : [], - 'add-to-cart': $( '[name=add-to-cart]' ).val(), + 'nonce': wc_ppec_generate_cart_context.generate_cart_nonce, }; + var field_pairs = form.serializeArray(); + for ( var i = 0; i < field_pairs.length; i++ ) { + // Prevent the default WooCommerce PHP form handler from recognizing this as an "add to cart" call + if ( 'add-to-cart' === field_pairs[ i ].name ) { + field_pairs[ i ].name = 'ppec-add-to-cart'; + } + data[ field_pairs[ i ].name ] = field_pairs[ i ].value; + } + + // If this is a simple product, the "Submit" button has the product ID as "value", we need to include it explicitly + data[ 'ppec-add-to-cart' ] = $( '[name=add-to-cart]' ).val(); + $.ajax( { type: 'POST', data: data, diff --git a/includes/class-wc-gateway-ppec-cart-handler.php b/includes/class-wc-gateway-ppec-cart-handler.php index 98199cbc..1a63a6f5 100644 --- a/includes/class-wc-gateway-ppec-cart-handler.php +++ b/includes/class-wc-gateway-ppec-cart-handler.php @@ -53,6 +53,7 @@ public function before_cart_totals() { /** * Generates the cart for PayPal Checkout on a product level. + * TODO: Why not let the default "add-to-cart" PHP form handler insert the product into the cart? Investigate. * * @since 1.4.0 */ @@ -70,8 +71,8 @@ public function wc_ajax_generate_cart() { WC()->shipping->reset_shipping(); $product = wc_get_product( $post->ID ); - if ( ! empty( $_POST['add-to-cart'] ) ) { - $product = wc_get_product( absint( $_POST['add-to-cart'] ) ); + if ( ! empty( $_POST['ppec-add-to-cart'] ) ) { + $product = wc_get_product( absint( $_POST['ppec-add-to-cart'] ) ); } /** @@ -80,11 +81,11 @@ public function wc_ajax_generate_cart() { * simple or variable product. */ if ( $product ) { - $qty = ! isset( $_POST['qty'] ) ? 1 : absint( $_POST['qty'] ); + $qty = ! isset( $_POST['quantity'] ) ? 1 : absint( $_POST['quantity'] ); wc_empty_cart(); if ( $product->is_type( 'variable' ) ) { - $attributes = array_map( 'wc_clean', $_POST['attributes'] ); + $attributes = array_map( 'wc_clean', $_POST ); if ( version_compare( WC_VERSION, '3.0', '<' ) ) { $variation_id = $product->get_matching_variation( $attributes ); @@ -93,7 +94,7 @@ public function wc_ajax_generate_cart() { $variation_id = $data_store->find_matching_product_variation( $product, $attributes ); } - WC()->cart->add_to_cart( $product->get_id(), $qty, $variation_id, $attributes ); + WC()->cart->add_to_cart( $product->get_id(), $qty, $variation_id ); } else { WC()->cart->add_to_cart( $product->get_id(), $qty ); } diff --git a/readme.txt b/readme.txt index 2f73c408..2f2a5ef2 100644 --- a/readme.txt +++ b/readme.txt @@ -102,6 +102,8 @@ Please use this to inform us about bugs, or make contributions via PRs. == Changelog == = 1.6.6 - 201x-xx-xx = +* Fix - Unable to buy variation from product page +* Fix - can use PayPal from product page without inputting required fields * Add - display PayPal fees under the totals on the order admin page = 1.6.5 - 2018-10-31 =