diff --git a/includes/class-modal-checkout.php b/includes/class-modal-checkout.php index 6d62b13bf..047941796 100644 --- a/includes/class-modal-checkout.php +++ b/includes/class-modal-checkout.php @@ -1590,7 +1590,7 @@ public static function is_express_checkout() { // Get express_payment_type in a way that works for both Stripe and WooPayments. $express_payment_info = isset( $_POST['express_payment_type'] ) ? sanitize_text_field( wp_unslash( $_POST['express_payment_type'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification - $is_express_checkout = ! empty( $express_payment_info ) && in_array( $express_payment_info, [ 'apple_pay', 'google_pay', 'payment_request_api' ], true ); // Validate payment request types: https://github.com/woocommerce/woocommerce-gateway-stripe/blob/develop/includes/payment-methods/class-wc-stripe-payment-request.php#L557-L586. + $is_express_checkout = ! empty( $express_payment_info ) && in_array( $express_payment_info, [ 'apple_pay', 'google_pay', 'payment_request_api', 'link' ], true ); // Validate payment request types: https://github.com/woocommerce/woocommerce-gateway-stripe/blob/develop/includes/payment-methods/class-wc-stripe-payment-request.php#L557-L586. if ( $is_express_checkout ) { $referrer = isset( $_SERVER['HTTP_REFERER'] ) ? \esc_url_raw( \wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : false; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized diff --git a/languages/newspack-blocks-de_DE.po b/languages/newspack-blocks-de_DE.po index 273ab3ebc..a2f8c7062 100644 --- a/languages/newspack-blocks-de_DE.po +++ b/languages/newspack-blocks-de_DE.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Newspack Blocks\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/project\n" -"POT-Creation-Date: 2025-12-03T17:31:19+00:00\n" +"POT-Creation-Date: 2026-01-07T21:28:53+00:00\n" "PO-Revision-Date: 2024-08-30 08:45-0700\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/languages/newspack-blocks-es_ES.po b/languages/newspack-blocks-es_ES.po index 28fdf9d36..307a28815 100644 --- a/languages/newspack-blocks-es_ES.po +++ b/languages/newspack-blocks-es_ES.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Newspack Blocks 1.0.0-alpha.20\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/project\n" -"POT-Creation-Date: 2025-12-03T17:31:19+00:00\n" +"POT-Creation-Date: 2026-01-07T21:28:53+00:00\n" "PO-Revision-Date: 2025-08-12T14:56:45+00:00\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/languages/newspack-blocks-fr_BE.po b/languages/newspack-blocks-fr_BE.po index 779817270..8a06f076b 100644 --- a/languages/newspack-blocks-fr_BE.po +++ b/languages/newspack-blocks-fr_BE.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Newspack Blocks 1.0.0-alpha.25\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/project\n" -"POT-Creation-Date: 2025-12-03T17:31:19+00:00\n" +"POT-Creation-Date: 2026-01-07T21:28:53+00:00\n" "PO-Revision-Date: 2024-08-30 08:46-0700\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/languages/newspack-blocks-nb_NO.po b/languages/newspack-blocks-nb_NO.po index aac1d1bc6..0618c021c 100644 --- a/languages/newspack-blocks-nb_NO.po +++ b/languages/newspack-blocks-nb_NO.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Newspack Blocks 1.0.0-alpha.20\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/project\n" -"POT-Creation-Date: 2025-12-03T17:31:19+00:00\n" +"POT-Creation-Date: 2026-01-07T21:28:53+00:00\n" "PO-Revision-Date: 2024-08-30 08:46-0700\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/languages/newspack-blocks-pt_PT.po b/languages/newspack-blocks-pt_PT.po index 3be593e44..ca8e23902 100644 --- a/languages/newspack-blocks-pt_PT.po +++ b/languages/newspack-blocks-pt_PT.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Newspack Blocks 1.0.0-alpha.25\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/project\n" -"POT-Creation-Date: 2025-12-03T17:31:19+00:00\n" +"POT-Creation-Date: 2026-01-07T21:28:53+00:00\n" "PO-Revision-Date: 2024-08-30 08:46-0700\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/languages/newspack-blocks.pot b/languages/newspack-blocks.pot index a9782ab9d..3f80b2f6c 100644 --- a/languages/newspack-blocks.pot +++ b/languages/newspack-blocks.pot @@ -1,15 +1,15 @@ -# Copyright (C) 2025 Automattic +# Copyright (C) 2026 Automattic # This file is distributed under the same license as the Newspack Blocks plugin. msgid "" msgstr "" -"Project-Id-Version: Newspack Blocks 4.18.0\n" +"Project-Id-Version: Newspack Blocks 4.20.1\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/project\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2025-12-03T17:31:19+00:00\n" +"POT-Creation-Date: 2026-01-07T21:28:53+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: newspack-blocks\n" diff --git a/src/blocks/donate/utils.ts b/src/blocks/donate/utils.ts index e70bf149d..0e913cd70 100644 --- a/src/blocks/donate/utils.ts +++ b/src/blocks/donate/utils.ts @@ -49,11 +49,12 @@ export const getFrequencyLabel = ( frequencySlug: DonationFrequencySlug, hideOnc ? hideOnceLabel ? '' : __( 'once', 'newspack-blocks' ) - : sprintf( - // Translators: %s is the frequency (e.g. per month, per year). - _x( 'per %s', 'per `Frequency`', 'newspack-blocks' ), - frequencySlug - ); + : ' ' + + sprintf( + // Translators: %s is the frequency (e.g. per month, per year). + _x( 'per %s', 'per `Frequency`', 'newspack-blocks' ), + frequencySlug + ); }; export const getFormattedAmount = ( amount: number, withCurrency = false ) => { diff --git a/src/modal-checkout/checkout.scss b/src/modal-checkout/checkout.scss index 01b88255b..53090590e 100644 --- a/src/modal-checkout/checkout.scss +++ b/src/modal-checkout/checkout.scss @@ -985,6 +985,10 @@ margin-top: 0; } + .woocommerce .woocommerce-notices-wrapper .woocommerce-error.newspack-ui__notice--error { + padding: var(--newspack-ui-spacer-2, 12px); + } + .modal-processing { opacity: 0.5; } diff --git a/src/modal-checkout/index.js b/src/modal-checkout/index.js index 5238186d5..a327c90ba 100644 --- a/src/modal-checkout/index.js +++ b/src/modal-checkout/index.js @@ -40,8 +40,9 @@ import { domReady, onCheckoutPlaceOrderProcessing } from './utils'; } function clearNotices() { + $( '.woocommerce-notices-wrapper' ).empty(); $( - `.woocommerce-NoticeGroup-checkout, .${ CLASS_PREFIX }__inline-error, .woocommerce-error, .woocommerce-message, .wc-block-components-notice-banner, .woocommerce-notices-wrapper` + `.woocommerce-NoticeGroup-checkout, .${ CLASS_PREFIX }__inline-error, .woocommerce-error, .woocommerce-message, .wc-block-components-notice-banner` ).remove(); } @@ -786,6 +787,70 @@ import { domReady, onCheckoutPlaceOrderProcessing } from './utils'; form.removeClass( 'modal-processing' ); return true; } + + /** + * Watch for Express Checkout errors added to the checkout container. + * Express Checkout (GPay/Apple Pay) uses the Store API which doesn't trigger + * the standard WooCommerce checkout_error event. + */ + function observeExpressCheckoutErrors() { + if ( ! container ) { + return; + } + + const ERROR_HANDLED_ATTR = 'data-newspack-error-handled'; + + const handleExpressCheckoutError = errorNode => { + if ( errorNode.hasAttribute( ERROR_HANDLED_ATTR ) ) { + return; + } + errorNode.setAttribute( ERROR_HANDLED_ATTR, 'true' ); + + $( errorNode ).addClass( `${ CLASS_PREFIX }__notice ${ CLASS_PREFIX }__notice--error` ); + container.dispatchEvent( placeOrderErrorEvent ); + errorNode.scrollIntoView( { behavior: 'smooth', block: 'center' } ); + }; + + const isErrorNode = node => { + if ( node.classList?.contains( 'woocommerce-error' ) ) { + return true; + } + if ( node.classList?.contains( 'wc-block-components-notice-banner' ) && node.classList?.contains( 'is-error' ) ) { + return true; + } + return false; + }; + + const observer = new MutationObserver( mutations => { + for ( const mutation of mutations ) { + for ( const node of mutation.addedNodes ) { + if ( node.nodeType !== Node.ELEMENT_NODE ) { + continue; + } + if ( isErrorNode( node ) ) { + handleExpressCheckoutError( node ); + return; + } + const nestedError = node.querySelector?.( '.woocommerce-error, .wc-block-components-notice-banner.is-error' ); + if ( nestedError ) { + handleExpressCheckoutError( nestedError ); + return; + } + } + } + } ); + + observer.observe( container, { childList: true, subtree: true } ); + return observer; + } + + const expressCheckoutErrorObserver = observeExpressCheckoutErrors(); + if ( expressCheckoutErrorObserver ) { + const disconnect = () => expressCheckoutErrorObserver.disconnect(); + container.addEventListener( 'checkout-complete', disconnect ); + container.addEventListener( 'checkout-cancel', disconnect ); + window.addEventListener( 'beforeunload', disconnect ); + } } init(); }