@automattic/newspack-blocks 4.27.0 → 4.27.1-hotfix-remove-hidden-checkout-fields.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## @automattic/newspack-blocks [4.27.1-hotfix-remove-hidden-checkout-fields.2](https://github.com/Automattic/newspack-workspace/compare/newspack-blocks@4.27.1-hotfix-remove-hidden-checkout-fields.1...newspack-blocks@4.27.1-hotfix-remove-hidden-checkout-fields.2) (2026-07-10)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **blocks:** limit store api scrub to billing on non-shipping carts ([afb599d](https://github.com/Automattic/newspack-workspace/commit/afb599dac7461c20371e59f5e39dc722ee1dfed2))
7
+ * **blocks:** scrub invalid wallet address values on store api checkout ([10b8db6](https://github.com/Automattic/newspack-workspace/commit/10b8db65920f66197be0a1628bd9aa551dffa97c))
8
+
1
9
  # @automattic/newspack-blocks [4.27.0](https://github.com/Automattic/newspack-workspace/compare/newspack-blocks@4.26.8...newspack-blocks@4.27.0) (2026-07-08)
2
10
 
3
11
 
@@ -29,6 +29,17 @@ final class Modal_Checkout {
29
29
  */
30
30
  const CHECKOUT_REGISTRATION_ORDER_META_KEY = '_newspack_checkout_registration_meta';
31
31
 
32
+ /**
33
+ * Billing fields with server-side format validation in the Store API,
34
+ * mapped from their classic checkout keys to Store API address keys.
35
+ *
36
+ * @var string[]
37
+ */
38
+ const STORE_API_VALIDATED_ADDRESS_FIELDS = [
39
+ 'billing_state' => 'state',
40
+ 'billing_postcode' => 'postcode',
41
+ ];
42
+
32
43
  /**
33
44
  * Whether the modal checkout has been enqueued.
34
45
  *
@@ -157,6 +168,8 @@ final class Modal_Checkout {
157
168
  add_filter( 'woocommerce_get_checkout_order_received_url', [ __CLASS__, 'woocommerce_get_return_url' ], 10, 2 );
158
169
  add_filter( 'wc_get_template', [ __CLASS__, 'wc_get_template' ], 10, 2 );
159
170
  add_filter( 'woocommerce_checkout_fields', [ __CLASS__, 'woocommerce_checkout_fields' ] );
171
+ add_filter( 'rest_pre_dispatch', [ __CLASS__, 'scrub_store_api_checkout_address' ], 10, 3 );
172
+ add_filter( 'woocommerce_get_country_locale', [ __CLASS__, 'relax_configured_off_locale_fields' ] );
160
173
  add_filter( 'woocommerce_update_order_review_fragments', [ __CLASS__, 'order_review_fragments' ] );
161
174
  add_filter( 'woocommerce_cart_needs_payment', [ __CLASS__, 'cart_needs_payment' ] );
162
175
  add_filter( 'newspack_recaptcha_verify_captcha', [ __CLASS__, 'recaptcha_verify_captcha' ], 10, 3 );
@@ -1332,19 +1345,26 @@ final class Modal_Checkout {
1332
1345
  }
1333
1346
 
1334
1347
  /**
1335
- * Modify fields for modal checkout.
1348
+ * Remove the configured-off billing fields from checkout.
1349
+ *
1350
+ * Not limited to modal checkout requests (NPPM-2937): the fields must be
1351
+ * unregistered wherever WooCommerce renders or validates them. When they were
1352
+ * only removed from the modal render, they stayed registered on the standard
1353
+ * checkout page, and express checkout wallets (e.g. Apple Pay) would populate
1354
+ * and fail validation on fields the buyer could not see or edit.
1336
1355
  *
1337
1356
  * @param array $fields Checkout fields.
1338
1357
  *
1339
1358
  * @return array
1340
1359
  */
1341
1360
  public static function woocommerce_checkout_fields( $fields ) {
1342
- if ( ! self::is_modal_checkout() ) {
1361
+ // My Account checkouts relax required flags instead of removing fields.
1362
+ if ( method_exists( 'Newspack\WooCommerce_My_Account', 'is_from_my_account' ) && \Newspack\WooCommerce_My_Account::is_from_my_account() ) {
1343
1363
  return $fields;
1344
1364
  }
1345
1365
  $cart = \WC()->cart;
1346
- // Don't modify fields if shipping is required.
1347
- if ( $cart->needs_shipping_address() ) {
1366
+ // Don't modify fields if there is no cart or shipping is required.
1367
+ if ( ! $cart || $cart->needs_shipping_address() ) {
1348
1368
  return $fields;
1349
1369
  }
1350
1370
  /**
@@ -1375,6 +1395,153 @@ final class Modal_Checkout {
1375
1395
  return $fields;
1376
1396
  }
1377
1397
 
1398
+ /**
1399
+ * Scrub invalid address values from Store API checkout requests when the
1400
+ * corresponding billing fields are configured off (NPPM-2937).
1401
+ *
1402
+ * Express checkout wallets submit to wc/store/v1/checkout and can supply
1403
+ * values the buyer never sees or corrects (e.g. Apple Pay sending a suburb
1404
+ * as the state), which hard-fails Store API address validation. Values the
1405
+ * validation would accept are left untouched, and only the billing address
1406
+ * is scrubbed. Runs on rest_pre_dispatch because the validation happens
1407
+ * during dispatch.
1408
+ *
1409
+ * @param mixed $result Response to replace the requested version with.
1410
+ * @param \WP_REST_Server $server Server instance.
1411
+ * @param \WP_REST_Request $request Request used to generate the response.
1412
+ *
1413
+ * @return mixed
1414
+ */
1415
+ public static function scrub_store_api_checkout_address( $result, $server, $request ) {
1416
+ if ( null !== $result ) {
1417
+ return $result;
1418
+ }
1419
+
1420
+ if (
1421
+ ! $request instanceof \WP_REST_Request ||
1422
+ 'POST' !== $request->get_method() ||
1423
+ 0 !== strpos( $request->get_route(), '/wc/store/v1/checkout' )
1424
+ ) {
1425
+ return $result;
1426
+ }
1427
+
1428
+ if ( ! function_exists( 'WC' ) || ! class_exists( 'WC_Validation' ) ) {
1429
+ return $result;
1430
+ }
1431
+
1432
+ $billing_fields = apply_filters( 'newspack_blocks_donate_billing_fields_keys', [] );
1433
+
1434
+ if ( empty( $billing_fields ) ) {
1435
+ return $result;
1436
+ }
1437
+
1438
+ // Physical-goods flows are never modified. The cart is not always
1439
+ // initialized this early in Store API requests; when it is, bail for
1440
+ // carts that need a shipping address. Only the billing address is
1441
+ // scrubbed, so shipping data is never touched either way.
1442
+ if ( \WC()->cart && \WC()->cart->needs_shipping_address() ) {
1443
+ return $result;
1444
+ }
1445
+
1446
+ $address = $request->get_param( 'billing_address' );
1447
+
1448
+ if ( is_array( $address ) ) {
1449
+ $scrubbed = self::scrub_invalid_address_values( $address, $billing_fields );
1450
+
1451
+ if ( $scrubbed !== $address ) {
1452
+ $request->set_param( 'billing_address', $scrubbed );
1453
+ }
1454
+ }
1455
+
1456
+ return $result;
1457
+ }
1458
+
1459
+ /**
1460
+ * Drop configured-off address values that would fail Store API validation.
1461
+ *
1462
+ * @param array $address Store API address (billing or shipping).
1463
+ * @param string[] $billing_fields Configured billing field keys.
1464
+ *
1465
+ * @return array Scrubbed address.
1466
+ */
1467
+ private static function scrub_invalid_address_values( $address, $billing_fields ) {
1468
+ $country = isset( $address['country'] ) ? $address['country'] : '';
1469
+
1470
+ if (
1471
+ ! in_array( 'billing_state', $billing_fields, true ) &&
1472
+ ! empty( $address['state'] ) &&
1473
+ $country
1474
+ ) {
1475
+ $states = \WC()->countries->get_states( $country );
1476
+
1477
+ if ( is_array( $states ) && ! empty( $states ) ) {
1478
+ $code_match = array_key_exists( strtoupper( $address['state'] ), array_change_key_case( $states, CASE_UPPER ) );
1479
+ $name_match = in_array( strtolower( $address['state'] ), array_map( 'strtolower', $states ), true );
1480
+
1481
+ if ( ! $code_match && ! $name_match ) {
1482
+ $address['state'] = '';
1483
+ }
1484
+ }
1485
+ }
1486
+
1487
+ if (
1488
+ ! in_array( 'billing_postcode', $billing_fields, true ) &&
1489
+ ! empty( $address['postcode'] ) &&
1490
+ ! \WC_Validation::is_postcode( $address['postcode'], $country )
1491
+ ) {
1492
+ $address['postcode'] = '';
1493
+ }
1494
+
1495
+ return $address;
1496
+ }
1497
+
1498
+ /**
1499
+ * Relax locale-required flags for configured-off billing fields (NPPM-2937).
1500
+ *
1501
+ * After an invalid wallet value is scrubbed (see
1502
+ * scrub_store_api_checkout_address), the Store API order validation would
1503
+ * still reject the checkout when the country locale marks the field as
1504
+ * required. A field the site is configured not to collect cannot be
1505
+ * required.
1506
+ *
1507
+ * @param array $locale Country locale field settings.
1508
+ *
1509
+ * @return array
1510
+ */
1511
+ public static function relax_configured_off_locale_fields( $locale ) {
1512
+ $billing_fields = apply_filters( 'newspack_blocks_donate_billing_fields_keys', [] );
1513
+
1514
+ if ( empty( $billing_fields ) ) {
1515
+ return $locale;
1516
+ }
1517
+
1518
+ // Never relax requirements when the cart needs a shipping address:
1519
+ // physical-goods flows keep the full locale rules.
1520
+ if ( function_exists( 'WC' ) && \WC()->cart && \WC()->cart->needs_shipping_address() ) {
1521
+ return $locale;
1522
+ }
1523
+
1524
+ $off = [];
1525
+
1526
+ foreach ( self::STORE_API_VALIDATED_ADDRESS_FIELDS as $config_key => $address_key ) {
1527
+ if ( ! in_array( $config_key, $billing_fields, true ) ) {
1528
+ $off[] = $address_key;
1529
+ }
1530
+ }
1531
+
1532
+ if ( empty( $off ) ) {
1533
+ return $locale;
1534
+ }
1535
+
1536
+ foreach ( array_keys( $locale ) as $country ) {
1537
+ foreach ( $off as $address_key ) {
1538
+ $locale[ $country ][ $address_key ]['required'] = false;
1539
+ }
1540
+ }
1541
+
1542
+ return $locale;
1543
+ }
1544
+
1378
1545
  /**
1379
1546
  * If WooCommerce Subscriptions Gifting extension is available, render its fields.
1380
1547
  *
@@ -7,7 +7,7 @@
7
7
  * Author URI: https://newspack.com/
8
8
  * Text Domain: newspack-blocks
9
9
  * Domain Path: /languages
10
- * Version: 4.27.0
10
+ * Version: 4.27.1-hotfix-remove-hidden-checkout-fields.2
11
11
  *
12
12
  * @package Newspack_Blocks
13
13
  */
@@ -15,7 +15,7 @@
15
15
  define( 'NEWSPACK_BLOCKS__PLUGIN_FILE', __FILE__ );
16
16
  define( 'NEWSPACK_BLOCKS__BLOCKS_DIRECTORY', 'dist/' );
17
17
  define( 'NEWSPACK_BLOCKS__PLUGIN_DIR', plugin_dir_path( NEWSPACK_BLOCKS__PLUGIN_FILE ) );
18
- define( 'NEWSPACK_BLOCKS__VERSION', '4.27.0' );
18
+ define( 'NEWSPACK_BLOCKS__VERSION', '4.27.1-hotfix-remove-hidden-checkout-fields.2' );
19
19
 
20
20
  require_once NEWSPACK_BLOCKS__PLUGIN_DIR . 'includes/class-newspack-blocks.php';
21
21
  require_once NEWSPACK_BLOCKS__PLUGIN_DIR . 'includes/class-newspack-blocks-api.php';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/newspack-blocks",
3
- "version": "4.27.0",
3
+ "version": "4.27.1-hotfix-remove-hidden-checkout-fields.2",
4
4
  "author": "Automattic",
5
5
  "description": "=== Newspack Blocks === Contributors: (this should be a list of wordpress.org userid's) Donate link: https://example.com/ Tags: comments, spam Requires at least: 4.5 Tested up to: 5.1.1 Stable tag: 0.1.0 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html",
6
6
  "repository": {
@@ -3,7 +3,7 @@
3
3
  'name' => 'automattic/newspack-blocks',
4
4
  'pretty_version' => 'dev-main',
5
5
  'version' => 'dev-main',
6
- 'reference' => '20e84f87dc1be96b5575548593fd0f7e77da52e6',
6
+ 'reference' => 'c0f3ca4fc2525868774d4840b63c76d66c0b8f0a',
7
7
  'type' => 'wordpress-plugin',
8
8
  'install_path' => __DIR__ . '/../../',
9
9
  'aliases' => array(),
@@ -13,7 +13,7 @@
13
13
  'automattic/newspack-blocks' => array(
14
14
  'pretty_version' => 'dev-main',
15
15
  'version' => 'dev-main',
16
- 'reference' => '20e84f87dc1be96b5575548593fd0f7e77da52e6',
16
+ 'reference' => 'c0f3ca4fc2525868774d4840b63c76d66c0b8f0a',
17
17
  'type' => 'wordpress-plugin',
18
18
  'install_path' => __DIR__ . '/../../',
19
19
  'aliases' => array(),