Commit a2e870bd0bf for woocommerce
commit a2e870bd0bfb5b568f226081581c35fafdf8f815
Author: Justin P <228780+layoutd@users.noreply.github.com>
Date: Fri Sep 25 09:18:16 2026 +0200
Fix Analytics reset defaults ignoring filtered order status defaults (#68688)
* Preload resolved wc_admin setting defaults for the client
* Use preloaded defaults for Analytics order status reset
* Copy preloaded status defaults and skip settings without a default
* Guard against a null preloaded settings defaults object
diff --git a/plugins/woocommerce/changelog/fix-analytics-reset-defaults-filtered-statuses b/plugins/woocommerce/changelog/fix-analytics-reset-defaults-filtered-statuses
new file mode 100644
index 00000000000..c50dd5ed9d0
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-analytics-reset-defaults-filtered-statuses
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Make the Analytics settings "Reset defaults" button restore the filtered default order statuses instead of a hardcoded list.
diff --git a/plugins/woocommerce/client/admin/client/analytics/settings/config.js b/plugins/woocommerce/client/admin/client/analytics/settings/config.js
index 1c4a65c0713..b6ed263b9a3 100644
--- a/plugins/woocommerce/client/admin/client/analytics/settings/config.js
+++ b/plugins/woocommerce/client/admin/client/analytics/settings/config.js
@@ -12,7 +12,25 @@ import DefaultDate from './default-date';
import { getAdminSetting, ORDER_STATUSES } from '~/utils/admin-settings';
const SETTINGS_FILTER = 'woocommerce_admin_analytics_settings';
-export const DEFAULT_ACTIONABLE_STATUSES = [ 'processing', 'on-hold' ];
+
+// Defaults resolved by the server for the wc_admin settings group, including the
+// `woocommerce_analytics_settings_default_*_order_statuses` filters. Missing when the
+// page did not preload them, so every consumer keeps a built-in fallback.
+const settingsDefaults = getAdminSetting( 'wcAdminSettingsDefaults', {} ) || {};
+
+const getDefaultStatuses = ( setting, fallback ) => {
+ const statuses = settingsDefaults[ setting ];
+ return Array.isArray( statuses ) ? [ ...statuses ] : fallback;
+};
+
+export const DEFAULT_EXCLUDED_STATUSES = getDefaultStatuses(
+ 'woocommerce_excluded_report_order_statuses',
+ [ 'pending', 'cancelled', 'failed' ]
+);
+export const DEFAULT_ACTIONABLE_STATUSES = getDefaultStatuses(
+ 'woocommerce_actionable_order_statuses',
+ [ 'processing', 'on-hold' ]
+);
export const DEFAULT_ORDER_STATUSES = [
'completed',
'processing',
@@ -98,7 +116,7 @@ const baseConfig = {
strong: <strong />,
},
} ),
- defaultValue: [ 'pending', 'cancelled', 'failed' ],
+ defaultValue: DEFAULT_EXCLUDED_STATUSES,
},
woocommerce_actionable_order_statuses: {
label: __( 'Actionable statuses:', 'woocommerce' ),
diff --git a/plugins/woocommerce/client/admin/client/analytics/settings/test/config.test.js b/plugins/woocommerce/client/admin/client/analytics/settings/test/config.test.js
new file mode 100644
index 00000000000..e1f0bd8ff55
--- /dev/null
+++ b/plugins/woocommerce/client/admin/client/analytics/settings/test/config.test.js
@@ -0,0 +1,70 @@
+let mockPreloadedDefaults = {};
+
+jest.mock( '~/utils/admin-settings', () => ( {
+ ...jest.requireActual( '~/utils/admin-settings' ),
+ getAdminSetting: ( name, fallback ) =>
+ name === 'wcAdminSettingsDefaults' ? mockPreloadedDefaults : fallback,
+} ) );
+
+// config.js reads the preloaded defaults at module load, so each case needs a fresh import.
+const loadConfig = ( preloadedDefaults ) => {
+ mockPreloadedDefaults = preloadedDefaults;
+ jest.resetModules();
+ return import( '../config' );
+};
+
+describe( 'Analytics settings config - order status defaults', () => {
+ it( 'uses the preloaded (filtered) defaults for the order status settings', async () => {
+ const config = await loadConfig( {
+ woocommerce_excluded_report_order_statuses: [ 'pending', 'failed' ],
+ woocommerce_actionable_order_statuses: [
+ 'processing',
+ 'on-hold',
+ 'my-status',
+ ],
+ } );
+
+ expect(
+ config.config.woocommerce_excluded_report_order_statuses
+ .defaultValue
+ ).toEqual( [ 'pending', 'failed' ] );
+ expect(
+ config.config.woocommerce_actionable_order_statuses.defaultValue
+ ).toEqual( [ 'processing', 'on-hold', 'my-status' ] );
+ expect( config.DEFAULT_ACTIONABLE_STATUSES ).toEqual( [
+ 'processing',
+ 'on-hold',
+ 'my-status',
+ ] );
+ } );
+
+ it( 'falls back to the built-in defaults when nothing was preloaded', async () => {
+ const config = await loadConfig( {} );
+
+ expect(
+ config.config.woocommerce_excluded_report_order_statuses
+ .defaultValue
+ ).toEqual( [ 'pending', 'cancelled', 'failed' ] );
+ expect(
+ config.config.woocommerce_actionable_order_statuses.defaultValue
+ ).toEqual( [ 'processing', 'on-hold' ] );
+ } );
+
+ it( 'falls back to the built-in defaults when the preload is null', async () => {
+ const config = await loadConfig( null );
+
+ expect(
+ config.config.woocommerce_actionable_order_statuses.defaultValue
+ ).toEqual( [ 'processing', 'on-hold' ] );
+ } );
+
+ it( 'ignores a malformed preloaded default', async () => {
+ const config = await loadConfig( {
+ woocommerce_actionable_order_statuses: 'processing',
+ } );
+
+ expect(
+ config.config.woocommerce_actionable_order_statuses.defaultValue
+ ).toEqual( [ 'processing', 'on-hold' ] );
+ } );
+} );
diff --git a/plugins/woocommerce/src/Internal/Admin/Settings.php b/plugins/woocommerce/src/Internal/Admin/Settings.php
index 188022dfd23..5b8cfb81b82 100644
--- a/plugins/woocommerce/src/Internal/Admin/Settings.php
+++ b/plugins/woocommerce/src/Internal/Admin/Settings.php
@@ -522,6 +522,10 @@ class Settings {
/**
* Gets custom settings used for WC Admin.
*
+ * Exposes the current values as `wcAdminSettings` and the resolved defaults as
+ * `wcAdminSettingsDefaults`, so the client can reset to the same (possibly filtered)
+ * defaults the REST endpoint reports instead of a hardcoded copy.
+ *
* @param array $settings Array of settings to merge into.
* @return array
*/
@@ -529,10 +533,15 @@ class Settings {
$wc_rest_settings_options_controller = new \WC_REST_Setting_Options_Controller();
$wc_admin_group_settings = $wc_rest_settings_options_controller->get_group_settings( 'wc_admin' );
$settings['wcAdminSettings'] = array();
+ $settings['wcAdminSettingsDefaults'] = array();
foreach ( $wc_admin_group_settings as $setting ) {
- if ( ! empty( $setting['id'] ) ) {
- $settings['wcAdminSettings'][ $setting['id'] ] = $setting['value'];
+ if ( empty( $setting['id'] ) ) {
+ continue;
+ }
+ $settings['wcAdminSettings'][ $setting['id'] ] = $setting['value'];
+ if ( array_key_exists( 'default', $setting ) ) {
+ $settings['wcAdminSettingsDefaults'][ $setting['id'] ] = $setting['default'];
}
}
return $settings;
diff --git a/plugins/woocommerce/tests/php/src/Internal/Admin/SettingsTest.php b/plugins/woocommerce/tests/php/src/Internal/Admin/SettingsTest.php
index 7869126a13e..40abcae32cd 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Admin/SettingsTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Admin/SettingsTest.php
@@ -289,6 +289,25 @@ class SettingsTest extends WC_Unit_Test_Case {
$this->assertSame( array(), Settings::get_default_excluded_order_statuses(), 'The UI and runtime consumers should agree.' );
}
+ /**
+ * @testdox The preloaded component settings expose the filtered defaults so "Reset defaults" can restore them.
+ */
+ public function test_component_settings_expose_filtered_defaults(): void {
+ $this->add_default_status_filter( 'woocommerce_analytics_settings_default_actionable_order_statuses' );
+ // The settings are only injected in admin; the base tearDown unsets the current screen.
+ set_current_screen( 'dashboard' );
+
+ $settings = $this->sut->add_component_settings( array() );
+
+ $this->assertArrayHasKey( 'wcAdminSettingsDefaults', $settings, 'Defaults should be preloaded alongside wcAdminSettings.' );
+ $this->assertContains( 'refunded', $settings['wcAdminSettingsDefaults']['woocommerce_actionable_order_statuses'], 'The filtered default should reach the client.' );
+ $this->assertSame(
+ array( 'pending', 'cancelled', 'failed' ),
+ $settings['wcAdminSettingsDefaults']['woocommerce_excluded_report_order_statuses'],
+ 'An unfiltered setting should keep its built-in default.'
+ );
+ }
+
/**
* @testdox The preloaded component settings expose coupon discount types, including ones added by extensions.
*/