From e94316aecd784abe33f7ea84d3aca1a2845018e0 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Mon, 3 Jul 2023 08:25:35 +0100 Subject: [PATCH 1/6] Add filter woocommerce_paypal_payments_product_button_disabled to disable PayPal buttons on single product page. --- .../ContextBootstrap/SingleProductBootstap.js | 3 ++- .../js/modules/Helper/ButtonDisabler.js | 5 ++++- modules/ppcp-button/src/Assets/SmartButton.php | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js index 540b085c1..8e88d0a2b 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js @@ -96,7 +96,8 @@ class SingleProductBootstap { return this.shouldRender() && !this.priceAmountIsZero() - && ((null === addToCartButton) || !addToCartButton.classList.contains('disabled')); + && ((null === addToCartButton) || !addToCartButton.classList.contains('disabled')) + && this.gateway.button.is_disabled !== true; } priceAmount() { diff --git a/modules/ppcp-button/resources/js/modules/Helper/ButtonDisabler.js b/modules/ppcp-button/resources/js/modules/Helper/ButtonDisabler.js index 9e4bf51ee..ae7f3665c 100644 --- a/modules/ppcp-button/resources/js/modules/Helper/ButtonDisabler.js +++ b/modules/ppcp-button/resources/js/modules/Helper/ButtonDisabler.js @@ -36,7 +36,10 @@ export const setEnabled = (selectorOrElement, enable, form = null) => { if (form) { // Trigger form submit to show the error message - jQuery(form).find(':submit').trigger('click'); + let $form = jQuery(form); + if ($form.find('.single_add_to_cart_button').hasClass('disabled')) { + $form.find(':submit').trigger('click'); + } } }) .find('> *') diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index 4625fab5a..4ba295547 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -860,6 +860,7 @@ class SmartButton implements SmartButtonInterface { 'wrapper' => '#ppc-button-' . PayPalGateway::ID, 'mini_cart_wrapper' => '#ppc-button-minicart', 'cancel_wrapper' => '#ppcp-cancel', + 'is_disabled' => $this->is_button_disabled(), 'mini_cart_style' => array( 'layout' => $this->style_for_context( 'layout', 'mini-cart' ), 'color' => $this->style_for_context( 'color', 'mini-cart' ), @@ -1350,6 +1351,23 @@ class SmartButton implements SmartButtonInterface { ); } + protected function is_button_disabled(): bool { + if ( 'product' !== $this->context() ) { + return false; + } + + $product = wc_get_product(); + + /** + * Allows to decide if the button should be disabled for a given product + */ + return apply_filters( + 'woocommerce_paypal_payments_product_button_disabled', + false, + $product + ); + } + /** * Retrieves all payment tokens for the user, via API or cached if already queried. * From cdd4a69bf572e0e290133e7fa27e41725f0cdccb Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Mon, 3 Jul 2023 08:31:27 +0100 Subject: [PATCH 2/6] Fix lint --- modules/ppcp-button/src/Assets/SmartButton.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index 4ba295547..68583f793 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -860,7 +860,7 @@ class SmartButton implements SmartButtonInterface { 'wrapper' => '#ppc-button-' . PayPalGateway::ID, 'mini_cart_wrapper' => '#ppc-button-minicart', 'cancel_wrapper' => '#ppcp-cancel', - 'is_disabled' => $this->is_button_disabled(), + 'is_disabled' => $this->is_button_disabled(), 'mini_cart_style' => array( 'layout' => $this->style_for_context( 'layout', 'mini-cart' ), 'color' => $this->style_for_context( 'color', 'mini-cart' ), @@ -1351,6 +1351,11 @@ class SmartButton implements SmartButtonInterface { ); } + /** + * Checks if PayPal buttons/messages should be rendered for the current page. + * + * @return bool + */ protected function is_button_disabled(): bool { if ( 'product' !== $this->context() ) { return false; From 74f28ca921a39e36d65c6fbf543693ebb7751370 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Mon, 3 Jul 2023 11:40:37 +0100 Subject: [PATCH 3/6] Add filter woocommerce_paypal_payments__button_disabled to disable PayPal buttons on a given context. --- .../modules/ContextBootstrap/CartBootstap.js | 13 ++++++ .../ContextBootstrap/CheckoutBootstap.js | 13 ++++++ .../ContextBootstrap/MiniCartBootstap.js | 13 ++++++ .../ppcp-button/src/Assets/SmartButton.php | 45 ++++++++++++++----- 4 files changed, 73 insertions(+), 11 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js index 72d28932b..cc613da83 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js @@ -1,5 +1,6 @@ import CartActionHandler from '../ActionHandler/CartActionHandler'; import {setVisible} from "../Helper/Hiding"; +import {disable} from "../Helper/ButtonDisabler"; class CartBootstrap { constructor(gateway, renderer, errorHandler) { @@ -15,6 +16,13 @@ class CartBootstrap { this.render(); + if (!this.shouldEnable()) { + this.renderer.disableSmartButtons(); + disable(this.gateway.button.wrapper); + disable(this.gateway.messages.wrapper); + return; + } + jQuery(document.body).on('updated_cart_totals updated_checkout', () => { this.render(); @@ -44,6 +52,11 @@ class CartBootstrap { return document.querySelector(this.gateway.button.wrapper) !== null; } + shouldEnable() { + return this.shouldRender() + && this.gateway.button.is_disabled !== true; + } + render() { const actionHandler = new CartActionHandler( PayPalCommerceGateway, diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js index 59c6197a3..a42902d9b 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js @@ -5,6 +5,7 @@ import { isSavedCardSelected, ORDER_BUTTON_SELECTOR, PaymentMethods } from "../Helper/CheckoutMethodState"; +import {disable} from "../Helper/ButtonDisabler"; class CheckoutBootstap { constructor(gateway, renderer, messages, spinner, errorHandler) { @@ -20,6 +21,13 @@ class CheckoutBootstap { init() { this.render(); + if (!this.shouldEnable()) { + this.renderer.disableSmartButtons(); + disable(this.gateway.button.wrapper); + disable(this.gateway.messages.wrapper); + return; + } + // Unselect saved card. // WC saves form values, so with our current UI it would be a bit weird // if the user paid with saved, then after some time tries to pay again, @@ -51,6 +59,11 @@ class CheckoutBootstap { return document.querySelector(this.gateway.button.wrapper) !== null || document.querySelector(this.gateway.hosted_fields.wrapper) !== null; } + shouldEnable() { + return this.shouldRender() + && this.gateway.button.is_disabled !== true; + } + render() { if (!this.shouldRender()) { return; diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js index 443c9afe4..a391ee7cd 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js @@ -1,4 +1,5 @@ import CartActionHandler from '../ActionHandler/CartActionHandler'; +import {disable} from "../Helper/ButtonDisabler"; class MiniCartBootstap { constructor(gateway, renderer, errorHandler) { @@ -16,6 +17,13 @@ class MiniCartBootstap { ); this.render(); + if (!this.shouldEnable()) { + this.renderer.disableSmartButtons(); + disable(this.gateway.button.wrapper); + disable(this.gateway.messages.wrapper); + return; + } + jQuery(document.body).on('wc_fragments_loaded wc_fragments_refreshed', () => { this.render(); }); @@ -26,6 +34,11 @@ class MiniCartBootstap { || document.querySelector(this.gateway.hosted_fields.mini_cart_wrapper) !== null; } + shouldEnable() { + return this.shouldRender() + && this.gateway.button.is_disabled !== true; + } + render() { if (!this.shouldRender()) { return; diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index 68583f793..5a7341e77 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -1357,20 +1357,43 @@ class SmartButton implements SmartButtonInterface { * @return bool */ protected function is_button_disabled(): bool { - if ( 'product' !== $this->context() ) { - return false; + $context = $this->context(); + + if ( 'product' === $context ) { + $product = wc_get_product(); + + /** + * Allows to decide if the button should be disabled for a given product + */ + if ( ( $isDisabled = apply_filters( + 'woocommerce_paypal_payments_product_button_disabled', + null, + $product ) + ) !== null) { + return $isDisabled; + } + } else { + $filterName = 'woocommerce_paypal_payments_' + . str_replace('-', '_', $context) + . '_button_disabled'; + + /** + * Allows to decide if the button should be disabled in a given context + */ + if ( ( $isDisabled = apply_filters( $filterName, null ) ) !== null ) { + return $isDisabled; + } } - $product = wc_get_product(); + if ( ( $isDisabled = apply_filters( + 'woocommerce_paypal_payments_button_disabled', + null, + $context + ) ) !== null ) { + return $isDisabled; + } - /** - * Allows to decide if the button should be disabled for a given product - */ - return apply_filters( - 'woocommerce_paypal_payments_product_button_disabled', - false, - $product - ); + return false; } /** From 6b03960de78e257723091e0ca96e79a8eacf5080 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Mon, 3 Jul 2023 17:35:01 +0100 Subject: [PATCH 4/6] Refactor button renderer and filter woocommerce_paypal_payments__button_disabled --- modules/ppcp-button/resources/js/button.js | 15 +----- .../modules/ContextBootstrap/CartBootstap.js | 27 +++++++--- .../ContextBootstrap/CheckoutBootstap.js | 27 +++++++--- .../ContextBootstrap/MiniCartBootstap.js | 27 ++++++---- .../ContextBootstrap/SingleProductBootstap.js | 16 +++--- .../resources/js/modules/Renderer/Renderer.js | 51 +++++++++++++++---- .../ppcp-button/src/Assets/SmartButton.php | 51 ++++++++++--------- 7 files changed, 131 insertions(+), 83 deletions(-) diff --git a/modules/ppcp-button/resources/js/button.js b/modules/ppcp-button/resources/js/button.js index 0fbccd095..17fcf1bfd 100644 --- a/modules/ppcp-button/resources/js/button.js +++ b/modules/ppcp-button/resources/js/button.js @@ -122,21 +122,10 @@ const bootstrap = () => { } }; - let smartButtonsOptions = { - onInit: null, - init: function (actions) { - this.actions = actions; - if (typeof this.onInit === 'function') { - this.onInit(); - } - } - }; - - const onSmartButtonsInit = (data, actions) => { + const onSmartButtonsInit = () => { buttonsSpinner.unblock(); - smartButtonsOptions.init(actions); }; - const renderer = new Renderer(creditCardRenderer, PayPalCommerceGateway, onSmartButtonClick, onSmartButtonsInit, smartButtonsOptions); + const renderer = new Renderer(creditCardRenderer, PayPalCommerceGateway, onSmartButtonClick, onSmartButtonsInit); const messageRenderer = new MessageRenderer(PayPalCommerceGateway.messages); const context = PayPalCommerceGateway.context; if (context === 'mini-cart' || context === 'product') { diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js index cc613da83..978ee2578 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js @@ -1,12 +1,16 @@ import CartActionHandler from '../ActionHandler/CartActionHandler'; import {setVisible} from "../Helper/Hiding"; -import {disable} from "../Helper/ButtonDisabler"; +import {disable, enable} from "../Helper/ButtonDisabler"; class CartBootstrap { constructor(gateway, renderer, errorHandler) { this.gateway = gateway; this.renderer = renderer; this.errorHandler = errorHandler; + + this.renderer.onButtonsInit(this.gateway.button.wrapper, () => { + this.handleButtonStatus(); + }, true); } init() { @@ -15,16 +19,11 @@ class CartBootstrap { } this.render(); - - if (!this.shouldEnable()) { - this.renderer.disableSmartButtons(); - disable(this.gateway.button.wrapper); - disable(this.gateway.messages.wrapper); - return; - } + this.handleButtonStatus(); jQuery(document.body).on('updated_cart_totals updated_checkout', () => { this.render(); + this.handleButtonStatus(); fetch( this.gateway.ajax.cart_script_params.endpoint, @@ -48,6 +47,18 @@ class CartBootstrap { }); } + handleButtonStatus() { + if (!this.shouldEnable()) { + this.renderer.disableSmartButtons(this.gateway.button.wrapper); + disable(this.gateway.button.wrapper); + disable(this.gateway.messages.wrapper); + return; + } + this.renderer.enableSmartButtons(this.gateway.button.wrapper); + enable(this.gateway.button.wrapper); + enable(this.gateway.messages.wrapper); + } + shouldRender() { return document.querySelector(this.gateway.button.wrapper) !== null; } diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js index a42902d9b..551baa75b 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js @@ -5,7 +5,7 @@ import { isSavedCardSelected, ORDER_BUTTON_SELECTOR, PaymentMethods } from "../Helper/CheckoutMethodState"; -import {disable} from "../Helper/ButtonDisabler"; +import {disable, enable} from "../Helper/ButtonDisabler"; class CheckoutBootstap { constructor(gateway, renderer, messages, spinner, errorHandler) { @@ -16,17 +16,15 @@ class CheckoutBootstap { this.errorHandler = errorHandler; this.standardOrderButtonSelector = ORDER_BUTTON_SELECTOR; + + this.renderer.onButtonsInit(this.gateway.button.wrapper, () => { + this.handleButtonStatus(); + }, true); } init() { this.render(); - - if (!this.shouldEnable()) { - this.renderer.disableSmartButtons(); - disable(this.gateway.button.wrapper); - disable(this.gateway.messages.wrapper); - return; - } + this.handleButtonStatus(); // Unselect saved card. // WC saves form values, so with our current UI it would be a bit weird @@ -36,6 +34,7 @@ class CheckoutBootstap { jQuery(document.body).on('updated_checkout', () => { this.render() + this.handleButtonStatus(); }); jQuery(document.body).on('updated_checkout payment_method_selected', () => { @@ -51,6 +50,18 @@ class CheckoutBootstap { this.updateUi(); } + handleButtonStatus() { + if (!this.shouldEnable()) { + this.renderer.disableSmartButtons(this.gateway.button.wrapper); + disable(this.gateway.button.wrapper); + disable(this.gateway.messages.wrapper); + return; + } + this.renderer.enableSmartButtons(this.gateway.button.wrapper); + enable(this.gateway.button.wrapper); + enable(this.gateway.messages.wrapper); + } + shouldRender() { if (document.querySelector(this.gateway.button.cancel_wrapper)) { return false; diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js index a391ee7cd..c993f3be0 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js @@ -1,5 +1,5 @@ import CartActionHandler from '../ActionHandler/CartActionHandler'; -import {disable} from "../Helper/ButtonDisabler"; +import {disable, enable} from "../Helper/ButtonDisabler"; class MiniCartBootstap { constructor(gateway, renderer, errorHandler) { @@ -16,17 +16,26 @@ class MiniCartBootstap { this.errorHandler, ); this.render(); - - if (!this.shouldEnable()) { - this.renderer.disableSmartButtons(); - disable(this.gateway.button.wrapper); - disable(this.gateway.messages.wrapper); - return; - } + this.handleButtonStatus(); jQuery(document.body).on('wc_fragments_loaded wc_fragments_refreshed', () => { this.render(); + this.handleButtonStatus(); }); + + this.renderer.onButtonsInit(this.gateway.button.mini_cart_wrapper, () => { + this.handleButtonStatus(); + }, true); + } + + handleButtonStatus() { + if (!this.shouldEnable()) { + this.renderer.disableSmartButtons(this.gateway.button.mini_cart_wrapper); + disable(this.gateway.button.mini_cart_wrapper); + return; + } + this.renderer.enableSmartButtons(this.gateway.button.mini_cart_wrapper); + enable(this.gateway.button.mini_cart_wrapper); } shouldRender() { @@ -36,7 +45,7 @@ class MiniCartBootstap { shouldEnable() { return this.shouldRender() - && this.gateway.button.is_disabled !== true; + && this.gateway.button.is_mini_cart_disabled !== true; } render() { diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js index 8e88d0a2b..b7addb4a5 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js @@ -12,11 +12,9 @@ class SingleProductBootstap { this.mutationObserver = new MutationObserver(this.handleChange.bind(this)); this.formSelector = 'form.cart'; - if (this.renderer && this.renderer.smartButtonsOptions) { - this.renderer.smartButtonsOptions.onInit = () => { - this.handleChange(); - }; - } + this.renderer.onButtonsInit(this.gateway.button.wrapper, () => { + this.handleChange(); + }, true); } form() { @@ -25,7 +23,7 @@ class SingleProductBootstap { handleChange() { if (!this.shouldRender()) { - this.renderer.disableSmartButtons(); + this.renderer.disableSmartButtons(this.gateway.button.wrapper); hide(this.gateway.button.wrapper, this.formSelector); hide(this.gateway.messages.wrapper); return; @@ -33,7 +31,7 @@ class SingleProductBootstap { this.render(); - this.renderer.enableSmartButtons(); + this.renderer.enableSmartButtons(this.gateway.button.wrapper); show(this.gateway.button.wrapper); show(this.gateway.messages.wrapper); @@ -42,12 +40,12 @@ class SingleProductBootstap { handleButtonStatus() { if (!this.shouldEnable()) { - this.renderer.disableSmartButtons(); + this.renderer.disableSmartButtons(this.gateway.button.wrapper); disable(this.gateway.button.wrapper, this.formSelector); disable(this.gateway.messages.wrapper); return; } - this.renderer.enableSmartButtons(); + this.renderer.enableSmartButtons(this.gateway.button.wrapper); enable(this.gateway.button.wrapper); enable(this.gateway.messages.wrapper); } diff --git a/modules/ppcp-button/resources/js/modules/Renderer/Renderer.js b/modules/ppcp-button/resources/js/modules/Renderer/Renderer.js index efd3c0bfa..1f0e3d31a 100644 --- a/modules/ppcp-button/resources/js/modules/Renderer/Renderer.js +++ b/modules/ppcp-button/resources/js/modules/Renderer/Renderer.js @@ -1,12 +1,14 @@ import merge from "deepmerge"; class Renderer { - constructor(creditCardRenderer, defaultSettings, onSmartButtonClick, onSmartButtonsInit, smartButtonsOptions) { + constructor(creditCardRenderer, defaultSettings, onSmartButtonClick, onSmartButtonsInit) { this.defaultSettings = defaultSettings; this.creditCardRenderer = creditCardRenderer; this.onSmartButtonClick = onSmartButtonClick; this.onSmartButtonsInit = onSmartButtonsInit; - this.smartButtonsOptions = smartButtonsOptions; + + this.buttonsOptions = {}; + this.onButtonsInitListeners = {}; this.renderedSources = new Set(); } @@ -78,7 +80,10 @@ class Renderer { style, ...contextConfig, onClick: this.onSmartButtonClick, - onInit: this.onSmartButtonsInit, + onInit: (data, actions) => { + this.onSmartButtonsInit(data, actions); + this.handleOnButtonsInit(wrapper, data, actions); + }, }); if (!btn.isEligible()) { return; @@ -108,18 +113,42 @@ class Renderer { this.creditCardRenderer.enableFields(); } - disableSmartButtons() { - if (!this.smartButtonsOptions || !this.smartButtonsOptions.actions) { - return; - } - this.smartButtonsOptions.actions.disable(); + onButtonsInit(wrapper, handler, reset) { + this.onButtonsInitListeners[wrapper] = reset ? [] : (this.onButtonsInitListeners[wrapper] || []); + this.onButtonsInitListeners[wrapper].push(handler); } - enableSmartButtons() { - if (!this.smartButtonsOptions || !this.smartButtonsOptions.actions) { + handleOnButtonsInit(wrapper, data, actions) { + + this.buttonsOptions[wrapper] = { + data: data, + actions: actions + } + + if (this.onButtonsInitListeners[wrapper]) { + for (let handler of this.onButtonsInitListeners[wrapper]) { + if (typeof handler === 'function') { + handler({ + wrapper: wrapper, + ...this.buttonsOptions[wrapper] + }); + } + } + } + } + + disableSmartButtons(wrapper) { + if (!this.buttonsOptions[wrapper]) { return; } - this.smartButtonsOptions.actions.enable(); + this.buttonsOptions[wrapper].actions.disable(); + } + + enableSmartButtons(wrapper) { + if (!this.buttonsOptions[wrapper]) { + return; + } + this.buttonsOptions[wrapper].actions.enable(); } } diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index 5a7341e77..e64633d1f 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -857,11 +857,12 @@ class SmartButton implements SmartButtonInterface { 'bn_codes' => $this->bn_codes(), 'payer' => $this->payerData(), 'button' => array( - 'wrapper' => '#ppc-button-' . PayPalGateway::ID, - 'mini_cart_wrapper' => '#ppc-button-minicart', - 'cancel_wrapper' => '#ppcp-cancel', - 'is_disabled' => $this->is_button_disabled(), - 'mini_cart_style' => array( + 'wrapper' => '#ppc-button-' . PayPalGateway::ID, + 'is_disabled' => $this->is_button_disabled(), + 'mini_cart_wrapper' => '#ppc-button-minicart', + 'is_mini_cart_disabled' => $this->is_button_disabled( 'mini-cart' ), + 'cancel_wrapper' => '#ppcp-cancel', + 'mini_cart_style' => array( 'layout' => $this->style_for_context( 'layout', 'mini-cart' ), 'color' => $this->style_for_context( 'color', 'mini-cart' ), 'shape' => $this->style_for_context( 'shape', 'mini-cart' ), @@ -869,7 +870,7 @@ class SmartButton implements SmartButtonInterface { 'tagline' => $this->style_for_context( 'tagline', 'mini-cart' ), 'height' => $this->settings->has( 'button_mini-cart_height' ) && $this->settings->get( 'button_mini-cart_height' ) ? $this->normalize_height( (int) $this->settings->get( 'button_mini-cart_height' ) ) : 35, ), - 'style' => array( + 'style' => array( 'layout' => $this->style_for_context( 'layout', $this->context() ), 'color' => $this->style_for_context( 'color', $this->context() ), 'shape' => $this->style_for_context( 'shape', $this->context() ), @@ -1354,10 +1355,14 @@ class SmartButton implements SmartButtonInterface { /** * Checks if PayPal buttons/messages should be rendered for the current page. * + * @param string|null $context The context that should be checked, use default otherwise. + * * @return bool */ - protected function is_button_disabled(): bool { - $context = $this->context(); + protected function is_button_disabled( string $context = null ): bool { + if ( null === $context ) { + $context = $this->context(); + } if ( 'product' === $context ) { $product = wc_get_product(); @@ -1365,32 +1370,28 @@ class SmartButton implements SmartButtonInterface { /** * Allows to decide if the button should be disabled for a given product */ - if ( ( $isDisabled = apply_filters( + $is_disabled = apply_filters( 'woocommerce_paypal_payments_product_button_disabled', null, - $product ) - ) !== null) { - return $isDisabled; - } - } else { - $filterName = 'woocommerce_paypal_payments_' - . str_replace('-', '_', $context) - . '_button_disabled'; + $product + ); - /** - * Allows to decide if the button should be disabled in a given context - */ - if ( ( $isDisabled = apply_filters( $filterName, null ) ) !== null ) { - return $isDisabled; + if ( $is_disabled !== null ) { + return $is_disabled; } } - if ( ( $isDisabled = apply_filters( + /** + * Allows to decide if the button should be disabled globally or on a given context + */ + $is_disabled = apply_filters( 'woocommerce_paypal_payments_button_disabled', null, $context - ) ) !== null ) { - return $isDisabled; + ); + + if ( $is_disabled !== null ) { + return $is_disabled; } return false; From 87665401e5ea83213b3160dfcb205bcd2b50ba38 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Tue, 4 Jul 2023 08:29:48 +0100 Subject: [PATCH 5/6] Change filter names to plural woocommerce_paypal_payments_buttons_disabled and woocommerce_paypal_payments_product_buttons_disabled --- modules/ppcp-button/src/Assets/SmartButton.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index e64633d1f..1516843b5 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -1371,7 +1371,7 @@ class SmartButton implements SmartButtonInterface { * Allows to decide if the button should be disabled for a given product */ $is_disabled = apply_filters( - 'woocommerce_paypal_payments_product_button_disabled', + 'woocommerce_paypal_payments_product_buttons_disabled', null, $product ); @@ -1385,7 +1385,7 @@ class SmartButton implements SmartButtonInterface { * Allows to decide if the button should be disabled globally or on a given context */ $is_disabled = apply_filters( - 'woocommerce_paypal_payments_button_disabled', + 'woocommerce_paypal_payments_buttons_disabled', null, $context ); From f6e625718ea2de64096f2953557171d4bde704e0 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Tue, 4 Jul 2023 14:43:55 +0100 Subject: [PATCH 6/6] Refactor handleButtonStatus and shouldEnable methods in buttons bootstraps --- .../modules/ContextBootstrap/CartBootstap.js | 15 ++----- .../ContextBootstrap/CheckoutBootstap.js | 14 ++----- .../ContextBootstrap/MiniCartBootstap.js | 18 ++++----- .../ContextBootstrap/SingleProductBootstap.js | 19 +++------ .../js/modules/Helper/BootstrapHelper.js | 40 +++++++++++++++++++ 5 files changed, 60 insertions(+), 46 deletions(-) create mode 100644 modules/ppcp-button/resources/js/modules/Helper/BootstrapHelper.js diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js index 978ee2578..504fc4c42 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js @@ -1,6 +1,6 @@ import CartActionHandler from '../ActionHandler/CartActionHandler'; +import BootstrapHelper from "../Helper/BootstrapHelper"; import {setVisible} from "../Helper/Hiding"; -import {disable, enable} from "../Helper/ButtonDisabler"; class CartBootstrap { constructor(gateway, renderer, errorHandler) { @@ -48,15 +48,7 @@ class CartBootstrap { } handleButtonStatus() { - if (!this.shouldEnable()) { - this.renderer.disableSmartButtons(this.gateway.button.wrapper); - disable(this.gateway.button.wrapper); - disable(this.gateway.messages.wrapper); - return; - } - this.renderer.enableSmartButtons(this.gateway.button.wrapper); - enable(this.gateway.button.wrapper); - enable(this.gateway.messages.wrapper); + BootstrapHelper.handleButtonStatus(this); } shouldRender() { @@ -64,8 +56,7 @@ class CartBootstrap { } shouldEnable() { - return this.shouldRender() - && this.gateway.button.is_disabled !== true; + return BootstrapHelper.shouldEnable(this); } render() { diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js index 551baa75b..b426ac3ee 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js @@ -5,6 +5,7 @@ import { isSavedCardSelected, ORDER_BUTTON_SELECTOR, PaymentMethods } from "../Helper/CheckoutMethodState"; +import BootstrapHelper from "../Helper/BootstrapHelper"; import {disable, enable} from "../Helper/ButtonDisabler"; class CheckoutBootstap { @@ -51,15 +52,7 @@ class CheckoutBootstap { } handleButtonStatus() { - if (!this.shouldEnable()) { - this.renderer.disableSmartButtons(this.gateway.button.wrapper); - disable(this.gateway.button.wrapper); - disable(this.gateway.messages.wrapper); - return; - } - this.renderer.enableSmartButtons(this.gateway.button.wrapper); - enable(this.gateway.button.wrapper); - enable(this.gateway.messages.wrapper); + BootstrapHelper.handleButtonStatus(this); } shouldRender() { @@ -71,8 +64,7 @@ class CheckoutBootstap { } shouldEnable() { - return this.shouldRender() - && this.gateway.button.is_disabled !== true; + return BootstrapHelper.shouldEnable(this); } render() { diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js index c993f3be0..4b4e3efd6 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/MiniCartBootstap.js @@ -1,5 +1,5 @@ import CartActionHandler from '../ActionHandler/CartActionHandler'; -import {disable, enable} from "../Helper/ButtonDisabler"; +import BootstrapHelper from "../Helper/BootstrapHelper"; class MiniCartBootstap { constructor(gateway, renderer, errorHandler) { @@ -29,13 +29,10 @@ class MiniCartBootstap { } handleButtonStatus() { - if (!this.shouldEnable()) { - this.renderer.disableSmartButtons(this.gateway.button.mini_cart_wrapper); - disable(this.gateway.button.mini_cart_wrapper); - return; - } - this.renderer.enableSmartButtons(this.gateway.button.mini_cart_wrapper); - enable(this.gateway.button.mini_cart_wrapper); + BootstrapHelper.handleButtonStatus(this, { + wrapper: this.gateway.button.mini_cart_wrapper, + skipMessages: true + }); } shouldRender() { @@ -44,8 +41,9 @@ class MiniCartBootstap { } shouldEnable() { - return this.shouldRender() - && this.gateway.button.is_mini_cart_disabled !== true; + return BootstrapHelper.shouldEnable(this, { + isDisabled: !!this.gateway.button.is_mini_cart_disabled + }); } render() { diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js index b7addb4a5..231460642 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js @@ -1,7 +1,7 @@ import UpdateCart from "../Helper/UpdateCart"; import SingleProductActionHandler from "../ActionHandler/SingleProductActionHandler"; import {hide, show} from "../Helper/Hiding"; -import {disable, enable} from "../Helper/ButtonDisabler"; +import BootstrapHelper from "../Helper/BootstrapHelper"; class SingleProductBootstap { constructor(gateway, renderer, messages, errorHandler) { @@ -39,15 +39,9 @@ class SingleProductBootstap { } handleButtonStatus() { - if (!this.shouldEnable()) { - this.renderer.disableSmartButtons(this.gateway.button.wrapper); - disable(this.gateway.button.wrapper, this.formSelector); - disable(this.gateway.messages.wrapper); - return; - } - this.renderer.enableSmartButtons(this.gateway.button.wrapper); - enable(this.gateway.button.wrapper); - enable(this.gateway.messages.wrapper); + BootstrapHelper.handleButtonStatus(this, { + formSelector: this.formSelector + }); } init() { @@ -92,10 +86,9 @@ class SingleProductBootstap { const form = this.form(); const addToCartButton = form ? form.querySelector('.single_add_to_cart_button') : null; - return this.shouldRender() + return BootstrapHelper.shouldEnable(this) && !this.priceAmountIsZero() - && ((null === addToCartButton) || !addToCartButton.classList.contains('disabled')) - && this.gateway.button.is_disabled !== true; + && ((null === addToCartButton) || !addToCartButton.classList.contains('disabled')); } priceAmount() { diff --git a/modules/ppcp-button/resources/js/modules/Helper/BootstrapHelper.js b/modules/ppcp-button/resources/js/modules/Helper/BootstrapHelper.js new file mode 100644 index 000000000..ba00e2c76 --- /dev/null +++ b/modules/ppcp-button/resources/js/modules/Helper/BootstrapHelper.js @@ -0,0 +1,40 @@ +import {disable, enable} from "./ButtonDisabler"; + +/** + * Common Bootstrap methods to avoid code repetition. + */ +export default class BootstrapHelper { + + static handleButtonStatus(bs, options) { + options = options || {}; + options.wrapper = options.wrapper || bs.gateway.button.wrapper; + options.messagesWrapper = options.messagesWrapper || bs.gateway.messages.wrapper; + options.skipMessages = options.skipMessages || false; + + if (!bs.shouldEnable()) { + bs.renderer.disableSmartButtons(options.wrapper); + disable(options.wrapper, options.formSelector || null); + + if (!options.skipMessages) { + disable(options.messagesWrapper); + } + return; + } + bs.renderer.enableSmartButtons(options.wrapper); + enable(options.wrapper); + + if (!options.skipMessages) { + enable(options.messagesWrapper); + } + } + + static shouldEnable(bs, options) { + options = options || {}; + if (typeof options.isDisabled === 'undefined') { + options.isDisabled = bs.gateway.button.is_disabled; + } + + return bs.shouldRender() + && options.isDisabled !== true; + } +}