Skip to content

Commit 618a4a7

Browse files
committed
Merge remote-tracking branch 'origin/release/9.7.1' into trunk
2 parents faea428 + 2359d74 commit 618a4a7

File tree

15 files changed

+102
-19
lines changed

15 files changed

+102
-19
lines changed

.github/actions/get-wordpress-plugin-versions/action.yml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,20 @@ runs:
3838
id: get-versions-json
3939
shell: bash
4040
# jq does the following:
41-
# - filters the versions to only include x.y.z versions, i.e. ignoring beta, rc, and dev versions etc
42-
# - groups the versions by the first two parts of the version number, i.e. major.minor
43-
# - reverses the order of the versions, so the highest major.minor versions are first
44-
# - limits the number of major.versions to the number specified in the version-count input
41+
# - filters the versions to only include semantic releases (x.y.z), ignoring beta, rc, trunk, etc.
42+
# - maps each version into a structure with:
43+
# - major_minor: the major.minor part (e.g. "9.6")
44+
# - full: the full version string (e.g. "9.6.2")
45+
# - parts: a numeric array of the version (e.g. [9, 6, 2])
46+
# - groups the versions by major.minor
47+
# - selects the highest patch version (i.e. max patch) within each group
48+
# - sorts all selected versions by semantic version order, descending
49+
# - limits the result to the latest N major.minor groups, where N is from version-count input
4550
# - returns the last version for each major.minor version
4651
run: |
4752
echo 'versions-json<<EOF' >> $GITHUB_OUTPUT
48-
cat ${{ inputs.plugin-slug }}.json | jq '.versions | keys | map( select( test("^\\d+\\.\\d+\\.\\d+$"; "s") ) ) | group_by( split( "." ) | .[0:2] | join( "." ) ) | reverse | .[0:${{ inputs.version-count }}] | [.[][-1]]' >> $GITHUB_OUTPUT
53+
cat ${{ inputs.plugin-slug }}.json | jq --argjson count "${{ inputs.version-count }}" '.versions | keys | map(select(test("^\\d+\\.\\d+\\.\\d+$"))) | map({ major_minor: (split(".")[0:2] | join(".")), full: ., parts: (split(".") | map(tonumber)) })
54+
| group_by(.major_minor) | map(max_by(.parts[2])) | sort_by(.parts[0], .parts[1], .parts[2]) | reverse | .[0:$count] | map(.full) ' >> $GITHUB_OUTPUT
4955
echo 'EOF' >> $GITHUB_OUTPUT
5056
5157
- name: Get versions in text format

.github/workflows/php-tests.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ jobs:
7171
exclude: # incompatible versions of PHP, WordPress, and WooCommerce
7272
- woocommerce_support_policy: L
7373
wordpress_support_policy: L-2
74+
- woocommerce_support_policy: L-1
75+
wordpress_support_policy: L-2
7476

7577
name: Stable (PHP=${{ matrix.php_support_policy }}, WP=${{ matrix.wordpress_support_policy }}, WC=${{ matrix.woocommerce_support_policy }})
7678
env:

changelog.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
*** Changelog ***
22

3+
= 9.7.1 - 2025-07-28 =
4+
* Add - Add state mapping for Lithuania in express checkout
5+
* Tweak - Check for checkout validation error before creating a payment method in Stripe
6+
* Fix - Prevent multiple save appearance AJAX calls on Block Checkout
7+
* Fix - Fix required field error message and PHP warning for custom checkout fields that don't have a label
8+
* Fix - Fix fatal when processing setup intents for free subscriptions via webhooks
9+
* Dev - Fix WooCommerce version fetching in GitHub workflows
10+
* Dev - Fix failing test cases associated with WooCommerce 10.0.x
11+
312
= 9.7.0 - 2025-07-21 =
413
* Update - Removes BNPL payment methods (Klarna and Affirm) when other official plugins are active
514
* Fix - Moves the existing order lock functionality earlier in the order processing flow to prevent duplicate processing requests

client/blocks/upe/upe-deferred-intent-creation/payment-processor.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44
import { getPaymentMethods } from '@woocommerce/blocks-registry';
55
import { __ } from '@wordpress/i18n';
6+
import { select } from '@wordpress/data';
67
import {
78
PaymentElement,
89
useElements,
@@ -194,6 +195,16 @@ const PaymentProcessor = ( {
194195
};
195196
}
196197

198+
const { validationStore } = window.wc?.wcBlocksData ?? {};
199+
if ( validationStore ) {
200+
const store = select( validationStore );
201+
const hasValidationErrors = store.hasValidationErrors();
202+
// Return if there is a validation error on the checkout fields.
203+
if ( hasValidationErrors ) {
204+
return;
205+
}
206+
}
207+
197208
// BLIK is a special case which is not handled through the Stripe element.
198209
if ( ! ( isPaymentElementComplete || isBlikSelected ) ) {
199210
return {

client/classic/upe/deferred-intent.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,22 @@ jQuery( function ( $ ) {
4141
} );
4242

4343
$( 'form.checkout' ).on( generateCheckoutEventNames(), function () {
44+
const $form = $( 'form.checkout' );
45+
// Lose focus for all fields to trigger validation
46+
$form
47+
.find( '.input-text, select, input:checkbox' )
48+
.trigger( 'validate' )
49+
.trigger( 'blur' );
50+
51+
const hasValidationErrors =
52+
$form.find( '.woocommerce-invalid' ).length > 0 &&
53+
$form.find( '.woocommerce-invalid' ).is( ':visible' );
54+
55+
// Return if there is a validation error on the checkout fields
56+
if ( hasValidationErrors ) {
57+
return;
58+
}
59+
4460
return processPaymentIfNotUsingSavedMethod( $( this ) );
4561
} );
4662

client/stripe-utils/utils.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,10 @@ export const showErrorPaymentMethod = ( errorMessage, containerSelector ) => {
613613
*
614614
* @return {Object} The appearance object for the UPE.
615615
*/
616+
617+
// Track if save appearance is already in progress to prevent multiple calls
618+
let isSavingAppearance = false;
619+
616620
export const initializeUPEAppearance = ( api, isBlockCheckout = 'false' ) => {
617621
let appearance =
618622
isBlockCheckout === 'true'
@@ -631,8 +635,21 @@ export const initializeUPEAppearance = ( api, isBlockCheckout = 'false' ) => {
631635
! data.isChangingPayment );
632636

633637
// If we have re-built the appearance, only update the settings in the checkout context
634-
if ( isValidUpdateContext ) {
635-
api.saveAppearance( appearance, isBlockCheckout );
638+
if ( isValidUpdateContext && ! isSavingAppearance ) {
639+
// Set flag to prevent concurrent saves
640+
isSavingAppearance = true;
641+
642+
// Update the global variable immediately to prevent multiple AJAX calls
643+
if ( isBlockCheckout === 'true' ) {
644+
data.blocksAppearance = appearance;
645+
} else {
646+
data.appearance = appearance;
647+
}
648+
649+
api.saveAppearance( appearance, isBlockCheckout ).finally( () => {
650+
// Reset flag when save completes (success or failure)
651+
isSavingAppearance = false;
652+
} );
636653
}
637654
}
638655

includes/class-wc-stripe-webhook-handler.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,10 +1169,12 @@ public function process_setup_intent( $notification ) {
11691169
* @since 9.7.0
11701170
*
11711171
* @param array $allowed_payment_processing_statuses The allowed payment processing statuses.
1172+
* @param WC_Order $order The order object.
11721173
*/
11731174
$allowed_payment_processing_statuses = apply_filters(
11741175
'wc_stripe_allowed_payment_processing_statuses',
11751176
$allowed_payment_processing_statuses,
1177+
$order
11761178
);
11771179

11781180
if ( ! $order->has_status( $allowed_payment_processing_statuses ) ) {

includes/constants/class-wc-stripe-payment-request-button-states.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* 1. WC provides a dropdown list of states, but there's no state field in Chrome for the following countries:
1919
* AO (Angola), BD (Bangladesh), BG (Bulgaria), BJ (Benin), BO (Bolivia), DO (Dominican Republic),
2020
* DZ (Algeria), GH (Ghana), GT (Guatemala), HU (Hungary), KE (Kenya), LA (Laos),
21-
* LR (Liberia), MD (Moldova), NA (Namibia), NP (Nepal), PK (Pakistan),
21+
* LR (Liberia), LT (Lithuania), MD (Moldova), NA (Namibia), NP (Nepal), PK (Pakistan),
2222
* PY (Paraguay), RO (Romania), TZ (Tanzania), UG (Uganda), UM (United States Minor Outlying Islands),
2323
* ZA (South Africa), ZM (Zambia).
2424
* 2. Chrome does not provide a dropdown list of states for 161 countries in total, out of the 249 countries WC supports,
@@ -648,6 +648,8 @@ class WC_Stripe_Payment_Request_Button_States {
648648
'LK' => [],
649649
// Liberia.
650650
'LR' => [],
651+
// Lithuania.
652+
'LT' => [],
651653
// Luxembourg.
652654
'LU' => [],
653655
// Moldova.

includes/payment-methods/class-wc-stripe-express-checkout-custom-fields.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function process_custom_checkout_data( $order, $request ) {
5959
$required_field_errors[] = sprintf(
6060
/* translators: %s: field name */
6161
__( '%s is a required field.', 'woocommerce-gateway-stripe' ),
62-
$field['label']
62+
empty( $field['label'] ) ? $key : $field['label']
6363
);
6464
}
6565
}
@@ -197,7 +197,7 @@ public function get_custom_checkout_fields( $context = '' ) {
197197
$additional_fields = $checkout_fields->get_additional_fields();
198198
foreach ( $additional_fields as $field_key => $field ) {
199199
$block_custom_checkout_fields[ $field_key ] = [
200-
'label' => $field['label'],
200+
'label' => $field['label'] ?? '',
201201
'type' => $field['type'] ?? 'text',
202202
'location' => $checkout_fields->get_field_location( $field_key ),
203203
'required' => $field['required'] ?? false,
@@ -222,7 +222,7 @@ public function get_custom_checkout_fields( $context = '' ) {
222222
}
223223

224224
$classic_custom_checkout_fields[ $field_key ] = [
225-
'label' => $field['label'],
225+
'label' => $field['label'] ?? '',
226226
'type' => $field['type'] ?? 'text',
227227
'location' => $fieldset,
228228
'required' => $field['required'] ?? false,

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)