Add filter allowing to disable the basic client-side validation

In case some conflicts occur.
This commit is contained in:
Alex P 2022-06-28 12:09:18 +03:00
parent 2215bed31e
commit be9c624264
3 changed files with 82 additions and 60 deletions

View file

@ -31,17 +31,19 @@ const bootstrap = () => {
const onSmartButtonClick = (data, actions) => { const onSmartButtonClick = (data, actions) => {
window.ppcpFundingSource = data.fundingSource; window.ppcpFundingSource = data.fundingSource;
// TODO: quick fix to get the error about empty form before attempting PayPal order if (PayPalCommerceGateway.basic_checkout_validation_enabled) {
// it should solve #513 for most of the users, but proper solution should be implemented later. // TODO: quick fix to get the error about empty form before attempting PayPal order
const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input'); // it should solve #513 for most of the users, but proper solution should be implemented later.
requiredFields.each((i, input) => { const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input');
jQuery(input).trigger('validate'); requiredFields.each((i, input) => {
}); jQuery(input).trigger('validate');
if (jQuery('form.woocommerce-checkout .woocommerce-invalid:visible').length) { });
errorHandler.clear(); if (jQuery('form.woocommerce-checkout .woocommerce-invalid:visible').length) {
errorHandler.message(PayPalCommerceGateway.labels.error.js_validation); errorHandler.clear();
errorHandler.message(PayPalCommerceGateway.labels.error.js_validation);
return actions.reject(); return actions.reject();
}
} }
const form = document.querySelector('form.woocommerce-checkout'); const form = document.querySelector('form.woocommerce-checkout');

View file

@ -27,7 +27,7 @@ use WooCommerce\PayPalCommerce\Onboarding\Environment;
use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\Onboarding\State;
return array( return array(
'button.client_id' => static function ( ContainerInterface $container ): string { 'button.client_id' => static function ( ContainerInterface $container ): string {
$settings = $container->get( 'wcgateway.settings' ); $settings = $container->get( 'wcgateway.settings' );
$client_id = $settings->has( 'client_id' ) ? $settings->get( 'client_id' ) : ''; $client_id = $settings->has( 'client_id' ) ? $settings->get( 'client_id' ) : '';
@ -45,7 +45,7 @@ return array(
return $env->current_environment_is( Environment::SANDBOX ) ? return $env->current_environment_is( Environment::SANDBOX ) ?
CONNECT_WOO_SANDBOX_CLIENT_ID : CONNECT_WOO_CLIENT_ID; CONNECT_WOO_SANDBOX_CLIENT_ID : CONNECT_WOO_CLIENT_ID;
}, },
'button.smart-button' => static function ( ContainerInterface $container ): SmartButtonInterface { 'button.smart-button' => static function ( ContainerInterface $container ): SmartButtonInterface {
$state = $container->get( 'onboarding.state' ); $state = $container->get( 'onboarding.state' );
/** /**
@ -88,19 +88,20 @@ return array(
$settings_status, $settings_status,
$currency, $currency,
$container->get( 'wcgateway.all-funding-sources' ), $container->get( 'wcgateway.all-funding-sources' ),
$container->get( 'button.basic-checkout-validation-enabled' ),
$container->get( 'woocommerce.logger.woocommerce' ) $container->get( 'woocommerce.logger.woocommerce' )
); );
}, },
'button.url' => static function ( ContainerInterface $container ): string { 'button.url' => static function ( ContainerInterface $container ): string {
return plugins_url( return plugins_url(
'/modules/ppcp-button/', '/modules/ppcp-button/',
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php' dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
); );
}, },
'button.request-data' => static function ( ContainerInterface $container ): RequestData { 'button.request-data' => static function ( ContainerInterface $container ): RequestData {
return new RequestData(); return new RequestData();
}, },
'button.endpoint.change-cart' => static function ( ContainerInterface $container ): ChangeCartEndpoint { 'button.endpoint.change-cart' => static function ( ContainerInterface $container ): ChangeCartEndpoint {
if ( ! \WC()->cart ) { if ( ! \WC()->cart ) {
throw new RuntimeException( 'cant initialize endpoint at this moment' ); throw new RuntimeException( 'cant initialize endpoint at this moment' );
} }
@ -112,7 +113,7 @@ return array(
$logger = $container->get( 'woocommerce.logger.woocommerce' ); $logger = $container->get( 'woocommerce.logger.woocommerce' );
return new ChangeCartEndpoint( $cart, $shipping, $request_data, $repository, $data_store, $logger ); return new ChangeCartEndpoint( $cart, $shipping, $request_data, $repository, $data_store, $logger );
}, },
'button.endpoint.create-order' => static function ( ContainerInterface $container ): CreateOrderEndpoint { 'button.endpoint.create-order' => static function ( ContainerInterface $container ): CreateOrderEndpoint {
$request_data = $container->get( 'button.request-data' ); $request_data = $container->get( 'button.request-data' );
$cart_repository = $container->get( 'api.repository.cart' ); $cart_repository = $container->get( 'api.repository.cart' );
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' ); $purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
@ -136,7 +137,7 @@ return array(
$logger $logger
); );
}, },
'button.helper.early-order-handler' => static function ( ContainerInterface $container ) : EarlyOrderHandler { 'button.helper.early-order-handler' => static function ( ContainerInterface $container ) : EarlyOrderHandler {
$state = $container->get( 'onboarding.state' ); $state = $container->get( 'onboarding.state' );
$order_processor = $container->get( 'wcgateway.order-processor' ); $order_processor = $container->get( 'wcgateway.order-processor' );
@ -144,7 +145,7 @@ return array(
$prefix = $container->get( 'api.prefix' ); $prefix = $container->get( 'api.prefix' );
return new EarlyOrderHandler( $state, $order_processor, $session_handler, $prefix ); return new EarlyOrderHandler( $state, $order_processor, $session_handler, $prefix );
}, },
'button.endpoint.approve-order' => static function ( ContainerInterface $container ): ApproveOrderEndpoint { 'button.endpoint.approve-order' => static function ( ContainerInterface $container ): ApproveOrderEndpoint {
$request_data = $container->get( 'button.request-data' ); $request_data = $container->get( 'button.request-data' );
$order_endpoint = $container->get( 'api.endpoint.order' ); $order_endpoint = $container->get( 'api.endpoint.order' );
$session_handler = $container->get( 'session.handler' ); $session_handler = $container->get( 'session.handler' );
@ -164,7 +165,7 @@ return array(
$logger $logger
); );
}, },
'button.endpoint.data-client-id' => static function( ContainerInterface $container ) : DataClientIdEndpoint { 'button.endpoint.data-client-id' => static function( ContainerInterface $container ) : DataClientIdEndpoint {
$request_data = $container->get( 'button.request-data' ); $request_data = $container->get( 'button.request-data' );
$identity_token = $container->get( 'api.endpoint.identity-token' ); $identity_token = $container->get( 'api.endpoint.identity-token' );
$logger = $container->get( 'woocommerce.logger.woocommerce' ); $logger = $container->get( 'woocommerce.logger.woocommerce' );
@ -174,31 +175,39 @@ return array(
$logger $logger
); );
}, },
'button.endpoint.vault-paypal' => static function( ContainerInterface $container ) : StartPayPalVaultingEndpoint { 'button.endpoint.vault-paypal' => static function( ContainerInterface $container ) : StartPayPalVaultingEndpoint {
return new StartPayPalVaultingEndpoint( return new StartPayPalVaultingEndpoint(
$container->get( 'button.request-data' ), $container->get( 'button.request-data' ),
$container->get( 'api.endpoint.payment-token' ), $container->get( 'api.endpoint.payment-token' ),
$container->get( 'woocommerce.logger.woocommerce' ) $container->get( 'woocommerce.logger.woocommerce' )
); );
}, },
'button.helper.three-d-secure' => static function ( ContainerInterface $container ): ThreeDSecure { 'button.helper.three-d-secure' => static function ( ContainerInterface $container ): ThreeDSecure {
$logger = $container->get( 'woocommerce.logger.woocommerce' ); $logger = $container->get( 'woocommerce.logger.woocommerce' );
return new ThreeDSecure( $logger ); return new ThreeDSecure( $logger );
}, },
'button.helper.messages-apply' => static function ( ContainerInterface $container ): MessagesApply { 'button.helper.messages-apply' => static function ( ContainerInterface $container ): MessagesApply {
return new MessagesApply( return new MessagesApply(
$container->get( 'api.shop.country' ) $container->get( 'api.shop.country' )
); );
}, },
'button.is-logged-in' => static function ( ContainerInterface $container ): bool { 'button.is-logged-in' => static function ( ContainerInterface $container ): bool {
return is_user_logged_in(); return is_user_logged_in();
}, },
'button.registration-required' => static function ( ContainerInterface $container ): bool { 'button.registration-required' => static function ( ContainerInterface $container ): bool {
return WC()->checkout()->is_registration_required(); return WC()->checkout()->is_registration_required();
}, },
'button.current-user-must-register' => static function ( ContainerInterface $container ): bool { 'button.current-user-must-register' => static function ( ContainerInterface $container ): bool {
return ! $container->get( 'button.is-logged-in' ) && return ! $container->get( 'button.is-logged-in' ) &&
$container->get( 'button.registration-required' ); $container->get( 'button.registration-required' );
}, },
'button.basic-checkout-validation-enabled' => static function ( ContainerInterface $container ): bool {
/**
* The filter allowing to disable the basic client-side validation of the checkout form
* when the PayPal button is clicked.
*/
return (bool) apply_filters( 'woocommerce_paypal_payments_basic_checkout_validation_enabled', true );
},
); );

View file

@ -144,6 +144,13 @@ class SmartButton implements SmartButtonInterface {
*/ */
private $all_funding_sources; private $all_funding_sources;
/**
* Whether the basic JS validation of the form iss enabled.
*
* @var bool
*/
private $basic_checkout_validation_enabled;
/** /**
* The logger. * The logger.
* *
@ -176,6 +183,7 @@ class SmartButton implements SmartButtonInterface {
* @param SettingsStatus $settings_status The Settings status helper. * @param SettingsStatus $settings_status The Settings status helper.
* @param string $currency 3-letter currency code of the shop. * @param string $currency 3-letter currency code of the shop.
* @param array $all_funding_sources All existing funding sources. * @param array $all_funding_sources All existing funding sources.
* @param bool $basic_checkout_validation_enabled Whether the basic JS validation of the form iss enabled.
* @param LoggerInterface $logger The logger. * @param LoggerInterface $logger The logger.
*/ */
public function __construct( public function __construct(
@ -194,25 +202,27 @@ class SmartButton implements SmartButtonInterface {
SettingsStatus $settings_status, SettingsStatus $settings_status,
string $currency, string $currency,
array $all_funding_sources, array $all_funding_sources,
bool $basic_checkout_validation_enabled,
LoggerInterface $logger LoggerInterface $logger
) { ) {
$this->module_url = $module_url; $this->module_url = $module_url;
$this->version = $version; $this->version = $version;
$this->session_handler = $session_handler; $this->session_handler = $session_handler;
$this->settings = $settings; $this->settings = $settings;
$this->payer_factory = $payer_factory; $this->payer_factory = $payer_factory;
$this->client_id = $client_id; $this->client_id = $client_id;
$this->request_data = $request_data; $this->request_data = $request_data;
$this->dcc_applies = $dcc_applies; $this->dcc_applies = $dcc_applies;
$this->subscription_helper = $subscription_helper; $this->subscription_helper = $subscription_helper;
$this->messages_apply = $messages_apply; $this->messages_apply = $messages_apply;
$this->environment = $environment; $this->environment = $environment;
$this->payment_token_repository = $payment_token_repository; $this->payment_token_repository = $payment_token_repository;
$this->settings_status = $settings_status; $this->settings_status = $settings_status;
$this->currency = $currency; $this->currency = $currency;
$this->all_funding_sources = $all_funding_sources; $this->all_funding_sources = $all_funding_sources;
$this->logger = $logger; $this->basic_checkout_validation_enabled = $basic_checkout_validation_enabled;
$this->logger = $logger;
} }
/** /**
@ -765,17 +775,17 @@ class SmartButton implements SmartButtonInterface {
$this->request_data->enqueue_nonce_fix(); $this->request_data->enqueue_nonce_fix();
$localize = array( $localize = array(
'script_attributes' => $this->attributes(), 'script_attributes' => $this->attributes(),
'data_client_id' => array( 'data_client_id' => array(
'set_attribute' => ( is_checkout() && $this->dcc_is_enabled() ) || $this->can_save_vault_token(), 'set_attribute' => ( is_checkout() && $this->dcc_is_enabled() ) || $this->can_save_vault_token(),
'endpoint' => \WC_AJAX::get_endpoint( DataClientIdEndpoint::ENDPOINT ), 'endpoint' => \WC_AJAX::get_endpoint( DataClientIdEndpoint::ENDPOINT ),
'nonce' => wp_create_nonce( DataClientIdEndpoint::nonce() ), 'nonce' => wp_create_nonce( DataClientIdEndpoint::nonce() ),
'user' => get_current_user_id(), 'user' => get_current_user_id(),
'has_subscriptions' => $this->has_subscriptions(), 'has_subscriptions' => $this->has_subscriptions(),
), ),
'redirect' => wc_get_checkout_url(), 'redirect' => wc_get_checkout_url(),
'context' => $this->context(), 'context' => $this->context(),
'ajax' => array( 'ajax' => array(
'change_cart' => array( 'change_cart' => array(
'endpoint' => \WC_AJAX::get_endpoint( ChangeCartEndpoint::ENDPOINT ), 'endpoint' => \WC_AJAX::get_endpoint( ChangeCartEndpoint::ENDPOINT ),
'nonce' => wp_create_nonce( ChangeCartEndpoint::nonce() ), 'nonce' => wp_create_nonce( ChangeCartEndpoint::nonce() ),
@ -793,13 +803,13 @@ class SmartButton implements SmartButtonInterface {
'nonce' => wp_create_nonce( StartPayPalVaultingEndpoint::nonce() ), 'nonce' => wp_create_nonce( StartPayPalVaultingEndpoint::nonce() ),
), ),
), ),
'enforce_vault' => $this->has_subscriptions(), 'enforce_vault' => $this->has_subscriptions(),
'can_save_vault_token' => $this->can_save_vault_token(), 'can_save_vault_token' => $this->can_save_vault_token(),
'is_free_trial_cart' => $is_free_trial_cart, 'is_free_trial_cart' => $is_free_trial_cart,
'vaulted_paypal_email' => ( is_checkout() && $is_free_trial_cart ) ? $this->get_vaulted_paypal_email() : '', 'vaulted_paypal_email' => ( is_checkout() && $is_free_trial_cart ) ? $this->get_vaulted_paypal_email() : '',
'bn_codes' => $this->bn_codes(), 'bn_codes' => $this->bn_codes(),
'payer' => $this->payerData(), 'payer' => $this->payerData(),
'button' => array( 'button' => array(
'wrapper' => '#ppc-button', 'wrapper' => '#ppc-button',
'mini_cart_wrapper' => '#ppc-button-minicart', 'mini_cart_wrapper' => '#ppc-button-minicart',
'cancel_wrapper' => '#ppcp-cancel', 'cancel_wrapper' => '#ppcp-cancel',
@ -820,7 +830,7 @@ class SmartButton implements SmartButtonInterface {
'tagline' => $this->style_for_context( 'tagline', $this->context() ), 'tagline' => $this->style_for_context( 'tagline', $this->context() ),
), ),
), ),
'hosted_fields' => array( 'hosted_fields' => array(
'wrapper' => '#ppcp-hosted-fields', 'wrapper' => '#ppcp-hosted-fields',
'mini_cart_wrapper' => '#ppcp-hosted-fields-mini-cart', 'mini_cart_wrapper' => '#ppcp-hosted-fields-mini-cart',
'labels' => array( 'labels' => array(
@ -840,10 +850,10 @@ class SmartButton implements SmartButtonInterface {
'valid_cards' => $this->dcc_applies->valid_cards(), 'valid_cards' => $this->dcc_applies->valid_cards(),
'contingency' => $this->get_3ds_contingency(), 'contingency' => $this->get_3ds_contingency(),
), ),
'messages' => $this->message_values(), 'messages' => $this->message_values(),
'labels' => array( 'labels' => array(
'error' => array( 'error' => array(
'generic' => __( 'generic' => __(
'Something went wrong. Please try again or choose another payment source.', 'Something went wrong. Please try again or choose another payment source.',
'woocommerce-paypal-payments' 'woocommerce-paypal-payments'
), ),
@ -853,9 +863,10 @@ class SmartButton implements SmartButtonInterface {
), ),
), ),
), ),
'order_id' => 'pay-now' === $this->context() ? absint( $wp->query_vars['order-pay'] ) : 0, 'order_id' => 'pay-now' === $this->context() ? absint( $wp->query_vars['order-pay'] ) : 0,
'single_product_buttons_enabled' => $this->settings->has( 'button_product_enabled' ) && $this->settings->get( 'button_product_enabled' ), 'single_product_buttons_enabled' => $this->settings->has( 'button_product_enabled' ) && $this->settings->get( 'button_product_enabled' ),
'mini_cart_buttons_enabled' => $this->settings->has( 'button_mini-cart_enabled' ) && $this->settings->get( 'button_mini-cart_enabled' ), 'mini_cart_buttons_enabled' => $this->settings->has( 'button_mini-cart_enabled' ) && $this->settings->get( 'button_mini-cart_enabled' ),
'basic_checkout_validation_enabled' => $this->basic_checkout_validation_enabled,
); );
if ( $this->style_for_context( 'layout', 'mini-cart' ) !== 'horizontal' ) { if ( $this->style_for_context( 'layout', 'mini-cart' ) !== 'horizontal' ) {