From c277af084d79cd44a99227e31f15dd71a3c31a62 Mon Sep 17 00:00:00 2001 From: Mike Letellier Date: Thu, 11 Jun 2026 12:46:41 -0300 Subject: [PATCH 1/7] Update paypal apple pay elgibility checks --- paypal/js/frontend.js | 57 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/paypal/js/frontend.js b/paypal/js/frontend.js index 46459ddef1..98e8e31d7f 100644 --- a/paypal/js/frontend.js +++ b/paypal/js/frontend.js @@ -350,33 +350,62 @@ * @return {Promise} Whether Apple Pay is eligible. */ async function resolveApplePayEligibility() { - const sdkReady = await waitFor( () => 'function' === typeof paypal.Applepay ); + // First ensure the PayPal SDK itself is loaded. + + // Wait for the Apple Pay function to be available. + const sdkReady = await waitFor( () => 'function' === typeof paypal.Applepay, 3000 ); if ( ! sdkReady ) { return false; } - return '' === await checkApplePayEligibility(); + // Wait for the config call to actually succeed, not just the function to exist. + // This handles the race condition where the function exists but SDK isn't fully initialized. + const configReady = await waitFor( async () => { + try { + const instance = paypal.Applepay(); + const config = await instance.config(); + return config && config.isEligible; + } catch ( e ) { + return false; + } + }, 3000 ); + + if ( ! configReady ) { + return false; + } + + // Config succeeded, cache it and return true. + applePayInstance = paypal.Applepay(); + applePayConfig = await applePayInstance.config(); + return true; } /** * Poll for a condition until it is true or a timeout elapses. * - * @param {Function} predicate Returns true when the awaited dependency is ready. + * @param {Function} predicate Returns true (or a Promise resolving to true) when the awaited dependency is ready. * @param {number} [timeout] Maximum time to wait, in milliseconds. * @param {number} [interval] Poll interval, in milliseconds. * * @return {Promise} Whether the predicate became true before the timeout. */ - function waitFor( predicate, timeout = 3000, interval = 50 ) { - return new Promise( resolve => { - if ( predicate() ) { - resolve( true ); - return; + async function waitFor( predicate, timeout = 3000, interval = 50 ) { + const checkPredicate = async () => { + const result = predicate(); + if ( result instanceof Promise ) { + return await result; } + return result; + }; + + if ( await checkPredicate() ) { + return true; + } - const start = Date.now(); - const timer = setInterval( () => { - if ( predicate() ) { + const start = Date.now(); + return new Promise( resolve => { + const timer = setInterval( async () => { + if ( await checkPredicate() ) { clearInterval( timer ); resolve( true ); } else if ( Date.now() - start >= timeout ) { @@ -1090,6 +1119,12 @@ const container = method.containerEl; container.innerHTML = ''; + // Check if Apple Pay is available on the device. + if ( 'undefined' === typeof ApplePaySession ) { + container.innerHTML = 'Apple Pay is not available on this device.'; + return; + } + const applePayStyle = getApplePayButtonStyle(); const btn = document.createElement( 'apple-pay-button' ); From d019a357a5621628f50c66656e7c9b8cca5febee Mon Sep 17 00:00:00 2001 From: Mike Letellier Date: Thu, 11 Jun 2026 12:48:20 -0300 Subject: [PATCH 2/7] Drop defaults from calls --- paypal/js/frontend.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/paypal/js/frontend.js b/paypal/js/frontend.js index 98e8e31d7f..435f7c1852 100644 --- a/paypal/js/frontend.js +++ b/paypal/js/frontend.js @@ -353,7 +353,7 @@ // First ensure the PayPal SDK itself is loaded. // Wait for the Apple Pay function to be available. - const sdkReady = await waitFor( () => 'function' === typeof paypal.Applepay, 3000 ); + const sdkReady = await waitFor( () => 'function' === typeof paypal.Applepay ); if ( ! sdkReady ) { return false; } @@ -368,7 +368,7 @@ } catch ( e ) { return false; } - }, 3000 ); + } ); if ( ! configReady ) { return false; From 961c383b809a40890f293685a5412c155e353a6b Mon Sep 17 00:00:00 2001 From: Mike Letellier Date: Thu, 11 Jun 2026 12:51:20 -0300 Subject: [PATCH 3/7] Put back the check for paypal --- paypal/js/frontend.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/paypal/js/frontend.js b/paypal/js/frontend.js index 435f7c1852..e361eee44d 100644 --- a/paypal/js/frontend.js +++ b/paypal/js/frontend.js @@ -351,6 +351,10 @@ */ async function resolveApplePayEligibility() { // First ensure the PayPal SDK itself is loaded. + const paypalReady = await waitFor( () => 'object' === typeof window.paypal ); + if ( ! paypalReady ) { + return false; + } // Wait for the Apple Pay function to be available. const sdkReady = await waitFor( () => 'function' === typeof paypal.Applepay ); From ed6090151a896d76a549a17d98204ec96043bbbf Mon Sep 17 00:00:00 2001 From: Mike Letellier Date: Thu, 11 Jun 2026 12:52:00 -0300 Subject: [PATCH 4/7] Use optional chaining --- paypal/js/frontend.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paypal/js/frontend.js b/paypal/js/frontend.js index e361eee44d..368fdf6ced 100644 --- a/paypal/js/frontend.js +++ b/paypal/js/frontend.js @@ -368,7 +368,7 @@ try { const instance = paypal.Applepay(); const config = await instance.config(); - return config && config.isEligible; + return config?.isEligible; } catch ( e ) { return false; } From e6e77b8b4d7844b0f423cb620aaf527164ce5bae Mon Sep 17 00:00:00 2001 From: Mike Letellier Date: Thu, 11 Jun 2026 13:09:15 -0300 Subject: [PATCH 5/7] Fix Chrome card field size issue, remove previous apple pay eligibility function, add extra checks for apple pay session --- paypal/js/frontend.js | 54 ++++++++++++------------------------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/paypal/js/frontend.js b/paypal/js/frontend.js index 368fdf6ced..beb27a47e7 100644 --- a/paypal/js/frontend.js +++ b/paypal/js/frontend.js @@ -350,6 +350,18 @@ * @return {Promise} Whether Apple Pay is eligible. */ async function resolveApplePayEligibility() { + // Wait for Apple Pay session to be available (requires Apple Pay SDK to load). + const sessionReady = await waitFor( () => 'undefined' !== typeof window.ApplePaySession ); + if ( ! sessionReady ) { + return false; + } + + // Wait for canMakePayments to return true. + const canMakePaymentsReady = await waitFor( () => ApplePaySession.canMakePayments() ); + if ( ! canMakePaymentsReady ) { + return false; + } + // First ensure the PayPal SDK itself is loaded. const paypalReady = await waitFor( () => 'object' === typeof window.paypal ); if ( ! paypalReady ) { @@ -782,21 +794,18 @@ const observerOptions = { attributes: true, attributeFilter: [ 'style' ] }; - const observerCallback = ( mutationsList, observer ) => { - observer.disconnect(); - + const observerCallback = ( mutationsList ) => { for ( const mutation of mutationsList ) { if ( mutation.type !== 'attributes' || mutation.attributeName !== 'style' ) { continue; } const currentHeight = mutation.target.offsetHeight; - if ( currentHeight > 0 ) { + // Only adjust if height is reasonable and not already adjusted. + if ( currentHeight > 40 && currentHeight < 100 ) { mutation.target.style.height = `${ currentHeight + 1 }px`; } } - - wrappers.forEach( w => observer.observe( w, observerOptions ) ); }; const observer = new MutationObserver( observerCallback ); @@ -1075,39 +1084,6 @@ return options; } - /** - * Check if Apple Pay is eligible (without rendering). - * - * @return {Promise} An empty string if Apple Pay is supported and ready to accept payments in the current environment, or a string with the reason for ineligibility. - */ - async function checkApplePayEligibility() { - if ( 'function' !== typeof paypal.Applepay ) { - return 'PayPal Apple Pay SDK not loaded'; - } - - if ( ! window.ApplePaySession ) { - return 'Not on Apple device'; - } - - if ( ! ApplePaySession.canMakePayments() ) { - return 'Apple Pay not configured on device'; - } - - // Use paypal.Applepay().config() as the definitive eligibility check (per PayPal multiparty docs). - try { - applePayInstance = paypal.Applepay(); - applePayConfig = await applePayInstance.config(); - - if ( ! applePayConfig || ! applePayConfig.isEligible ) { - return 'PayPal reports Apple Pay is not eligible for this merchant/domain'; - } - } catch ( err ) { - return `Apple Pay config check failed: ${ err.message }`; - } - - return ''; - } - /** * Render the Apple Pay button into its method container. * From 0ee43923c636ea4deb91e449a328b06ef13b7191 Mon Sep 17 00:00:00 2001 From: Mike Letellier Date: Thu, 11 Jun 2026 13:20:06 -0300 Subject: [PATCH 6/7] Eslint cleanup --- paypal/js/frontend.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/paypal/js/frontend.js b/paypal/js/frontend.js index beb27a47e7..572056638f 100644 --- a/paypal/js/frontend.js +++ b/paypal/js/frontend.js @@ -351,7 +351,7 @@ */ async function resolveApplePayEligibility() { // Wait for Apple Pay session to be available (requires Apple Pay SDK to load). - const sessionReady = await waitFor( () => 'undefined' !== typeof window.ApplePaySession ); + const sessionReady = await waitFor( () => undefined !== window.ApplePaySession ); if ( ! sessionReady ) { return false; } @@ -794,7 +794,7 @@ const observerOptions = { attributes: true, attributeFilter: [ 'style' ] }; - const observerCallback = ( mutationsList ) => { + const observerCallback = mutationsList => { for ( const mutation of mutationsList ) { if ( mutation.type !== 'attributes' || mutation.attributeName !== 'style' ) { continue; From 9692d2d6e9592c0a31cdb144cd4a34439b92110b Mon Sep 17 00:00:00 2001 From: Mike Letellier Date: Thu, 11 Jun 2026 13:23:35 -0300 Subject: [PATCH 7/7] Stop adding to page html --- paypal/js/frontend.js | 1 - 1 file changed, 1 deletion(-) diff --git a/paypal/js/frontend.js b/paypal/js/frontend.js index 572056638f..0f36ebf770 100644 --- a/paypal/js/frontend.js +++ b/paypal/js/frontend.js @@ -1101,7 +1101,6 @@ // Check if Apple Pay is available on the device. if ( 'undefined' === typeof ApplePaySession ) { - container.innerHTML = 'Apple Pay is not available on this device.'; return; }