Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add supported gateways check #2009

Open
wants to merge 23 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
caf328b
fix: add supported gateways check
laurelfulford Dec 18, 2024
0449ee7
fix: remove unneeded code changes
laurelfulford Dec 18, 2024
1890b93
fix: refactor method names
chickenn00dle Dec 18, 2024
b6b8f26
fix: redirect modal checkout when pm unsupported
chickenn00dle Dec 18, 2024
e5a00ae
Merge branch 'trunk' into feat/payment-gateway-fallback
laurelfulford Dec 19, 2024
1e44b97
feat: add check to trigger registration if on
laurelfulford Dec 19, 2024
9296a0a
feat: add simple button spinner when checkout page is loading
laurelfulford Dec 19, 2024
df5f044
feat: fix registration prompt location
laurelfulford Dec 19, 2024
4326dd8
feat: only close variation picker if modal checkout
laurelfulford Dec 19, 2024
cd83199
fix: getting rid of some redundancies
laurelfulford Dec 19, 2024
ec61d30
feat: change close on success behaviour for sign in
laurelfulford Dec 27, 2024
ff4b92c
Merge branch 'trunk' into feat/payment-gateway-fallback
laurelfulford Dec 27, 2024
ede61ea
Merge branch 'trunk' into feat/payment-gateway-fallback
laurelfulford Jan 3, 2025
5e4aa98
feat: remove unneeded URL params for non-modal checkout
laurelfulford Jan 3, 2025
e3233da
fix: rename const, add comments
laurelfulford Jan 3, 2025
0fe8861
fix: make sure variation picker closes for modal checkout or reg
laurelfulford Jan 6, 2025
0f2a807
feat: limit button animation to buttons with focus
laurelfulford Jan 6, 2025
874b3ae
Merge branch 'trunk' into feat/payment-gateway-fallback
laurelfulford Jan 6, 2025
c173297
Merge branch 'trunk' into feat/payment-gateway-fallback
laurelfulford Jan 15, 2025
82629c3
Merge branch 'trunk' into feat/payment-gateway-fallback
laurelfulford Jan 15, 2025
6ce2da4
fix: improve query string removal approach
laurelfulford Jan 16, 2025
6aa043d
fix: clean up any loading states and modals when Back is clicked
laurelfulford Jan 16, 2025
2e15d61
feat: more query string removal, and improve back button behaviour
laurelfulford Jan 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 53 additions & 6 deletions includes/class-modal-checkout.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,21 @@ final class Modal_Checkout {
'metorik',
];

/**
* Supported Payment Gateways
*
* @var string[]
*/
private static $supported_gateways = [
'bacs', // Direct bank transfer.
'cheque',
'cod', // Cash on delivery.
'ppcp-gateway', // PayPal Payments.
'stripe',
'stripe-link',
'woocommerce_payments',
];

/**
* Initialize hooks.
*/
Expand Down Expand Up @@ -151,7 +166,6 @@ public static function init() {
add_action( 'init', [ __CLASS__, 'unhook_woocommerce_payments_update_billing_fields' ] );
add_action( 'wp_enqueue_scripts', [ __CLASS__, 'update_password_strength_message' ], 9999 );


/** Custom handling for registered users. */
add_filter( 'woocommerce_checkout_customer_id', [ __CLASS__, 'associate_existing_user' ] );
add_action( 'woocommerce_after_checkout_validation', [ __CLASS__, 'maybe_reset_checkout_registration_flag' ], 10, 2 );
Expand Down Expand Up @@ -224,6 +238,38 @@ public static function dequeue_woocommerce_styles( $enqueue_styles ) {
return $enqueue_styles;
}

/**
* Get list of supported payment gateways for Modal Checkout.
*
* @return string[] Supported payment gateways.
*/
public static function get_supported_payment_gateways() {
/**
* Filters the list of supported gateways in modal checkout.
*
* @param array $supported_gateways
*/
return apply_filters( 'newspack_blocks_modal_checkout_supported_gateways', self::$supported_gateways );
}

/**
* Whether any available payment gateways are not suppored in modal checkout.
*
* @return boolean
*/
public static function has_unsupported_payment_gateway() {
$supported_gateways = self::get_supported_payment_gateways();
$available_gateways = \WC()->payment_gateways->get_available_payment_gateways();
$unsupported_payment_gateway = false;
foreach ( $available_gateways as $id => $gateway ) {
if ( ! in_array( $id, $supported_gateways, true ) ) {
$unsupported_payment_gateway = true;
break;
}
}
return $unsupported_payment_gateway;
}

/**
* Process checkout request for modal.
*/
Expand Down Expand Up @@ -933,11 +979,12 @@ public static function enqueue_modal( $product_id = null ) {
'newspack-blocks-modal',
'newspackBlocksModal',
[
'ajax_url' => admin_url( 'admin-ajax.php' ),
'checkout_registration_flag' => self::CHECKOUT_REGISTRATION_FLAG,
'newspack_class_prefix' => self::get_class_prefix(),
'is_registration_required' => self::is_registration_required(),
'labels' => [
'ajax_url' => admin_url( 'admin-ajax.php' ),
'checkout_registration_flag' => self::CHECKOUT_REGISTRATION_FLAG,
'newspack_class_prefix' => self::get_class_prefix(),
'is_registration_required' => self::is_registration_required(),
'has_unsupported_payment_gateway' => self::has_unsupported_payment_gateway(),
'labels' => [
'auth_modal_title' => self::get_modal_checkout_labels( 'auth_modal_title' ),
'checkout_modal_title' => self::get_modal_checkout_labels( 'checkout_modal_title' ),
'register_modal_title' => self::get_modal_checkout_labels( 'register_modal_title' ),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public static function render( $attributes ) {
Newspack_Blocks::enqueue_view_assets( 'donate' );
wp_script_add_data( 'newspack-blocks-donate', 'async', true );

if ( true === $attributes['useModalCheckout'] ) {
if ( true === $attributes['useModalCheckout'] && ! Newspack_Blocks\Modal_Checkout::has_unsupported_payment_gateway() ) {
\Newspack_Blocks\Modal_Checkout::enqueue_modal();
}

Expand Down
57 changes: 45 additions & 12 deletions src/modal-checkout/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,14 @@ domReady( () => {
* @param {Event} ev
*/
const handleCheckoutFormSubmit = ev => {
const isModalCheckout = ! newspackBlocksModal.has_unsupported_payment_gateway;
if ( ! isModalCheckout ) {
ev.preventDefault();
}
const form = ev.target;

form.classList.add( 'modal-processing' );

const productData = form.dataset.product;

if ( productData ) {
const data = JSON.parse( productData );
Object.keys( data ).forEach( key => {
Expand All @@ -213,17 +215,28 @@ domReady( () => {
} );
}
const formData = new FormData( form );

// If we're not going from variation picker to checkout, set the modal trigger:
if ( ! formData.get( 'variation_id' ) ) {
modalTrigger = ev.submitter;
}

const variationModals = document.querySelectorAll( `.${ VARIATON_MODAL_CLASS_PREFIX }` );
// Clear any open variation modal.
const variationModals = document.querySelectorAll( `.${ VARIATON_MODAL_CLASS_PREFIX }` );
variationModals.forEach( variationModal => {
closeModal( variationModal );
// Only close the variation picker if is the modal checkout, or if registration is required.
if ( shouldPromptRegistration() || isModalCheckout ) {
closeModal( variationModal );
}
} );

// Generate URL for non-modal checkout
const generateNonModalCheckoutUrl = ( url ) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: rather than relying on regex and text manipulation of the URL, a cleaner way to do this might be to not append the modal checkout-related hidden fields if there's an unsupported payment gateway.

// Regex for after_success URL params used by the modal checkout.
const successParams = /(after_success|&after_success)[^&]*?(?=&|$)/gi;
// Remove modal_checkout, success params, and any trailing ? from the URL.
const nonModalUrl = url.replace( /&?modal_checkout=1/, '' ).replaceAll(successParams, '').replace( /\?$/, '' ); // remove question mark only if last character.
return nonModalUrl;
}

// Trigger variation modal if variation is not selected.
if ( formData.get( 'is_variable' ) && ! formData.get( 'variation_id' ) ) {
const variationModal = [ ...variationModals ].find(
Expand Down Expand Up @@ -282,12 +295,27 @@ domReady( () => {
return;
}
}

// Populate cart and redirect to checkout if there is an unsupported payment gateway.
if ( ! isModalCheckout && ! shouldPromptRegistration() ) {
generateCart( formData ).then( url => {
window.location.href = generateNonModalCheckoutUrl( url );
} );
// Add some animation to the Checkout Button and Donate block while the non-modal checkout is loading.
// For now, don't do it when any popup opens, just when we go right to the checkout page.
if ( ! ( formData.get( 'is_variable' ) && ! formData.get( 'variation_id' ) ) ) {
// Use :focus to try to limit submit buttons in tiered donate button block.
const buttons = form.querySelectorAll( 'button[type=submit]:focus' );
buttons.forEach( button => {
button.classList.add( 'non-modal-checkout-loading' );
const buttonText = button.innerHTML;
button.innerHTML = '<span>' + buttonText + '</span>';
} );
}
return;
}
form.classList.remove( 'modal-processing' );

const isDonateBlock = formData.get( 'newspack_donate' );
const isCheckoutButtonBlock = formData.get( 'newspack_checkout' );

// Set up some GA4 information.
if ( isCheckoutButtonBlock ) { // this fires on the second in-modal variations screen, too
const formAnalyticsData = form.getAttribute( 'data-product' );
Expand Down Expand Up @@ -416,7 +444,6 @@ domReady( () => {
cartReq.then( url => {
window.newspackReaderActivation?.setPendingCheckout?.( url );
} );

// Initialize auth flow if reader is not authenticated.
window.newspackReaderActivation.openAuthModal( {
title: newspackBlocksModal.labels.auth_modal_title,
Expand All @@ -426,8 +453,13 @@ domReady( () => {
if ( authData?.registered ) {
url += `&${ newspackBlocksModal.checkout_registration_flag }=1`;
}
const checkoutForm = generateCheckoutPageForm( url );
triggerCheckout( checkoutForm );
// Populate cart and redirect to checkout if there is an unsupported payment gateway.
if ( ! isModalCheckout ) {
generateCart( formData ).then( window.location.href = generateNonModalCheckoutUrl( url ) );
} else {
const checkoutForm = generateCheckoutPageForm( url );
triggerCheckout( checkoutForm );
}
} )
.catch( error => {
console.warn( 'Unable to generate cart:', error ); // eslint-disable-line no-console
Expand Down Expand Up @@ -455,6 +487,7 @@ domReady( () => {
},
content,
trigger: ev.submitter,
closeOnSuccess: isModalCheckout,
} );
} else {
// Otherwise initialize checkout.
Expand Down
22 changes: 22 additions & 0 deletions src/modal-checkout/modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,28 @@
}
}

.non-modal-checkout-loading {
position: relative;

span {
visibility: hidden;
}

&::before {
animation: spin 900ms infinite linear;
border: 1.5px solid;
border-color: currentcolor currentcolor transparent transparent;
border-radius: 50%;
content: "";
display: block;
height: 18px;
inset: calc(50% - 9px) calc(50% - 9px) auto auto;
position: absolute;
width: 18px;
}
}


@keyframes spin {
0% {
transform: rotate(0deg);
Expand Down
Loading