Commit 434fe263e3 for woocommerce
commit 434fe263e339dd6e8d712801cd496d2eade6f88b
Author: Chi-Hsuan Huang <chihsuan.tw@gmail.com>
Date: Fri Dec 5 11:44:12 2025 +0900
Add scheduled updates promotion admin notice (#62225)
* Add Scheduled Updates Promotion Notice component and user preference handling
- Introduced a new ScheduledUpdatesPromotionNotice component to inform users about scheduled updates in analytics.
- Updated user preferences to track dismissal of the promotion notice.
- Integrated the notice into the analytics report and dashboard components.
- Added necessary type definitions and updated the analytics PHP backend to support the new feature.
* Update default setting for analytics data import to null for new sites
* Add changelog
* Add changelog
* Fix notice logic
* Use explicit check
* Update plugins/woocommerce/src/Internal/Admin/Settings.php
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Add tests
* Refactor report component wrapping logic in useReports
- Updated the getReports function to create a new array of wrapped reports, preventing mutation of the original reports array.
- Introduced a WrappedComponent function to include the ScheduledUpdatesPromotionNotice, enhancing debugging with a displayName property.
- Ensured the wrapped reports are returned from the getReports function.
* Fix lint
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
diff --git a/packages/js/data/changelog/wooa7s-795-onboarding-scheduled-updates-promotion-notices b/packages/js/data/changelog/wooa7s-795-onboarding-scheduled-updates-promotion-notices
new file mode 100644
index 0000000000..6933cc745d
--- /dev/null
+++ b/packages/js/data/changelog/wooa7s-795-onboarding-scheduled-updates-promotion-notices
@@ -0,0 +1,4 @@
+Significance: patch
+Type: update
+
+Update UserPreferences type to include scheduled_updates_promotion_notice_dismissed field
diff --git a/packages/js/data/src/user/types.ts b/packages/js/data/src/user/types.ts
index 90b5dbb39e..1cc6e5a2b7 100644
--- a/packages/js/data/src/user/types.ts
+++ b/packages/js/data/src/user/types.ts
@@ -34,6 +34,7 @@ export type UserPreferences = {
};
launch_your_store_tour_hidden?: 'yes' | 'no' | '';
coming_soon_banner_dismissed?: 'yes' | 'no' | '';
+ scheduled_updates_promotion_notice_dismissed?: 'yes' | 'no' | '';
};
export type WoocommerceMeta = {
diff --git a/plugins/woocommerce/changelog/wooa7s-795-onboarding-scheduled-updates-promotion-notices b/plugins/woocommerce/changelog/wooa7s-795-onboarding-scheduled-updates-promotion-notices
new file mode 100644
index 0000000000..73701c74c6
--- /dev/null
+++ b/plugins/woocommerce/changelog/wooa7s-795-onboarding-scheduled-updates-promotion-notices
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Add scheduled updates promotion notices
diff --git a/plugins/woocommerce/client/admin/client/analytics/components/index.js b/plugins/woocommerce/client/admin/client/analytics/components/index.js
index 4ee3476b0b..ab4b62ec06 100644
--- a/plugins/woocommerce/client/admin/client/analytics/components/index.js
+++ b/plugins/woocommerce/client/admin/client/analytics/components/index.js
@@ -1,3 +1,4 @@
export { default as ReportChart } from './report-chart';
export { default as ReportSummary } from './report-summary';
export { default as ReportTable } from './report-table';
+export { default as ScheduledUpdatesPromotionNotice } from './scheduled-updates-promotion-notice';
diff --git a/plugins/woocommerce/client/admin/client/analytics/components/scheduled-updates-promotion-notice/index.tsx b/plugins/woocommerce/client/admin/client/analytics/components/scheduled-updates-promotion-notice/index.tsx
new file mode 100644
index 0000000000..22cb447e2a
--- /dev/null
+++ b/plugins/woocommerce/client/admin/client/analytics/components/scheduled-updates-promotion-notice/index.tsx
@@ -0,0 +1,80 @@
+/**
+ * External dependencies
+ */
+import { getAdminLink } from '@woocommerce/settings';
+import { __ } from '@wordpress/i18n';
+import { useSettings, useUserPreferences } from '@woocommerce/data';
+import { createInterpolateElement } from '@wordpress/element';
+import { Button } from '@wordpress/components';
+import { recordEvent } from '@woocommerce/tracks';
+
+const IMMEDIATE_IMPORT_OPTION = 'woocommerce_analytics_immediate_import';
+
+export default function ScheduledUpdatesPromotionNotice() {
+ // Get settings to check option value (hooks must be called before early returns)
+ const settings = useSettings( 'wc_admin', [ 'wcAdminSettings' ] );
+ const wcAdminSettings = (
+ settings as { wcAdminSettings?: Record< string, string > }
+ )?.wcAdminSettings;
+
+ const { updateUserPreferences, ...userData } = useUserPreferences();
+
+ // Check if feature flag is enabled
+ if ( ! window.wcAdminFeatures?.[ 'analytics-scheduled-import' ] ) {
+ return null;
+ }
+
+ const optionValue = wcAdminSettings?.[ IMMEDIATE_IMPORT_OPTION ];
+ // No need to show notice if option is already set.
+ if ( optionValue === 'no' || optionValue === 'yes' ) {
+ return null;
+ }
+
+ const isDismissed =
+ userData?.scheduled_updates_promotion_notice_dismissed === 'yes';
+
+ if ( isDismissed ) {
+ return null;
+ }
+
+ const onDismiss = () => {
+ updateUserPreferences( {
+ scheduled_updates_promotion_notice_dismissed: 'yes',
+ } );
+ recordEvent( 'scheduled_updates_promotion_notice_dismissed' );
+ };
+
+ return (
+ <div className="notice notice-info is-dismissible">
+ <Button
+ variant="tertiary"
+ aria-label={ __( 'Dismiss this notice.', 'woocommerce' ) }
+ className="woocommerce-message-close notice-dismiss"
+ onClick={ onDismiss }
+ />
+
+ <p>
+ { createInterpolateElement(
+ /* translators: <a> is a link to the analytics settings page. */
+ __(
+ 'Analytics now supports scheduled updates, providing improved performance. Enable it in <a>Settings</a>.',
+ 'woocommerce'
+ ),
+ {
+ a: (
+ <a
+ href={ getAdminLink(
+ 'admin.php?page=wc-admin&path=/analytics/settings'
+ ) }
+ aria-label={ __(
+ 'Analytics settings',
+ 'woocommerce'
+ ) }
+ />
+ ),
+ }
+ ) }
+ </p>
+ </div>
+ );
+}
diff --git a/plugins/woocommerce/client/admin/client/analytics/components/scheduled-updates-promotion-notice/test/index.tsx b/plugins/woocommerce/client/admin/client/analytics/components/scheduled-updates-promotion-notice/test/index.tsx
new file mode 100644
index 0000000000..66ce3d6256
--- /dev/null
+++ b/plugins/woocommerce/client/admin/client/analytics/components/scheduled-updates-promotion-notice/test/index.tsx
@@ -0,0 +1,421 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+/**
+ * External dependencies
+ */
+import React from 'react';
+import { createElement } from '@wordpress/element';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { recordEvent } from '@woocommerce/tracks';
+import { useSettings, useUserPreferences } from '@woocommerce/data';
+import { getAdminLink } from '@woocommerce/settings';
+
+/**
+ * Internal dependencies
+ */
+import ScheduledUpdatesPromotionNotice from '../index';
+
+// Mock dependencies
+jest.mock( '@woocommerce/tracks', () => ( {
+ recordEvent: jest.fn(),
+} ) );
+
+jest.mock( '@woocommerce/data', () => {
+ const originalModule = jest.requireActual( '@woocommerce/data' );
+ return {
+ ...originalModule,
+ useSettings: jest.fn(),
+ useUserPreferences: jest.fn(),
+ };
+} );
+
+jest.mock( '@woocommerce/settings', () => ( {
+ getAdminLink: jest.fn( ( path: string ) => `http://example.com/${ path }` ),
+} ) );
+
+const mockUseSettings = useSettings as jest.MockedFunction<
+ typeof useSettings
+>;
+const mockUseUserPreferences = useUserPreferences as jest.MockedFunction<
+ typeof useUserPreferences
+>;
+const mockRecordEvent = recordEvent as jest.MockedFunction<
+ typeof recordEvent
+>;
+const mockGetAdminLink = getAdminLink as jest.MockedFunction<
+ typeof getAdminLink
+>;
+
+describe( 'ScheduledUpdatesPromotionNotice', () => {
+ beforeEach( () => {
+ jest.clearAllMocks();
+
+ // Set up default feature flag
+ ( window as any ).wcAdminFeatures = {
+ 'analytics-scheduled-import': true,
+ };
+
+ // Set up default mocks
+ mockUseSettings.mockReturnValue( {
+ wcAdminSettings: {},
+ } as unknown as ReturnType< typeof useSettings > );
+
+ mockUseUserPreferences.mockReturnValue( {
+ updateUserPreferences: jest.fn(),
+ scheduled_updates_promotion_notice_dismissed: undefined,
+ isRequesting: false,
+ } as unknown as ReturnType< typeof useUserPreferences > );
+
+ mockGetAdminLink.mockReturnValue(
+ 'http://example.com/admin.php?page=wc-admin&path=/analytics/settings'
+ );
+ } );
+
+ describe( 'Feature flag check', () => {
+ test( 'should not render when feature flag is disabled', () => {
+ ( window as any ).wcAdminFeatures = {
+ 'analytics-scheduled-import': false,
+ };
+
+ const { container } = render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect( container.firstChild ).toBeNull();
+ } );
+
+ test( 'should not render when feature flag is undefined', () => {
+ ( window as any ).wcAdminFeatures = {};
+
+ const { container } = render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect( container.firstChild ).toBeNull();
+ } );
+
+ test( 'should render when feature flag is enabled', () => {
+ ( window as any ).wcAdminFeatures = {
+ 'analytics-scheduled-import': true,
+ };
+
+ render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect(
+ screen.getByText( ( content, element ) => {
+ const textContent = element?.textContent || '';
+ return (
+ element?.tagName.toLowerCase() === 'p' &&
+ textContent.includes(
+ 'Analytics now supports scheduled updates, providing improved performance. Enable it in'
+ ) &&
+ textContent.includes( 'Settings' )
+ );
+ } )
+ ).toBeInTheDocument();
+ } );
+ } );
+
+ describe( 'Option value check', () => {
+ test( 'should not render when option is set to "yes"', () => {
+ mockUseSettings.mockReturnValue( {
+ wcAdminSettings: {
+ woocommerce_analytics_immediate_import: 'yes',
+ },
+ } as unknown as ReturnType< typeof useSettings > );
+
+ const { container } = render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect( container.firstChild ).toBeNull();
+ } );
+
+ test( 'should not render when option is set to "no"', () => {
+ mockUseSettings.mockReturnValue( {
+ wcAdminSettings: {
+ woocommerce_analytics_immediate_import: 'no',
+ },
+ } as unknown as ReturnType< typeof useSettings > );
+
+ const { container } = render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect( container.firstChild ).toBeNull();
+ } );
+
+ test( 'should render when option is undefined', () => {
+ mockUseSettings.mockReturnValue( {
+ wcAdminSettings: {},
+ } as unknown as ReturnType< typeof useSettings > );
+
+ render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect(
+ screen.getByText( ( content, element ) => {
+ const textContent = element?.textContent || '';
+ return (
+ element?.tagName.toLowerCase() === 'p' &&
+ textContent.includes(
+ 'Analytics now supports scheduled updates, providing improved performance. Enable it in'
+ ) &&
+ textContent.includes( 'Settings' )
+ );
+ } )
+ ).toBeInTheDocument();
+ } );
+
+ test( 'should render when option is null', () => {
+ mockUseSettings.mockReturnValue( {
+ wcAdminSettings: {
+ woocommerce_analytics_immediate_import: null,
+ },
+ } as unknown as ReturnType< typeof useSettings > );
+
+ render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect(
+ screen.getByText( ( content, element ) => {
+ const textContent = element?.textContent || '';
+ return (
+ element?.tagName.toLowerCase() === 'p' &&
+ textContent.includes(
+ 'Analytics now supports scheduled updates, providing improved performance. Enable it in'
+ ) &&
+ textContent.includes( 'Settings' )
+ );
+ } )
+ ).toBeInTheDocument();
+ } );
+ } );
+
+ describe( 'Dismissal check', () => {
+ test( 'should not render when notice is dismissed', () => {
+ mockUseUserPreferences.mockReturnValue( {
+ updateUserPreferences: jest.fn(),
+ scheduled_updates_promotion_notice_dismissed: 'yes',
+ isRequesting: false,
+ } as unknown as ReturnType< typeof useUserPreferences > );
+
+ const { container } = render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect( container.firstChild ).toBeNull();
+ } );
+
+ test( 'should render when notice is not dismissed', () => {
+ mockUseUserPreferences.mockReturnValue( {
+ updateUserPreferences: jest.fn(),
+ scheduled_updates_promotion_notice_dismissed: undefined,
+ isRequesting: false,
+ } as unknown as ReturnType< typeof useUserPreferences > );
+
+ render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect(
+ screen.getByText( ( content, element ) => {
+ const textContent = element?.textContent || '';
+ return (
+ element?.tagName.toLowerCase() === 'p' &&
+ textContent.includes(
+ 'Analytics now supports scheduled updates, providing improved performance. Enable it in'
+ ) &&
+ textContent.includes( 'Settings' )
+ );
+ } )
+ ).toBeInTheDocument();
+ } );
+ } );
+
+ describe( 'Dismissal functionality', () => {
+ test( 'should call updateUserPreferences when dismiss button is clicked', async () => {
+ const mockUpdateUserPreferences = jest.fn();
+ mockUseUserPreferences.mockReturnValue( {
+ updateUserPreferences: mockUpdateUserPreferences,
+ scheduled_updates_promotion_notice_dismissed: undefined,
+ isRequesting: false,
+ } as unknown as ReturnType< typeof useUserPreferences > );
+
+ render( <ScheduledUpdatesPromotionNotice /> );
+
+ const dismissButton = screen.getByLabelText(
+ 'Dismiss this notice.'
+ );
+ await userEvent.click( dismissButton );
+
+ expect( mockUpdateUserPreferences ).toHaveBeenCalledWith( {
+ scheduled_updates_promotion_notice_dismissed: 'yes',
+ } );
+ } );
+
+ test( 'should fire tracking event when dismiss button is clicked', async () => {
+ mockUseUserPreferences.mockReturnValue( {
+ updateUserPreferences: jest.fn(),
+ scheduled_updates_promotion_notice_dismissed: undefined,
+ isRequesting: false,
+ } as unknown as ReturnType< typeof useUserPreferences > );
+
+ render( <ScheduledUpdatesPromotionNotice /> );
+
+ const dismissButton = screen.getByLabelText(
+ 'Dismiss this notice.'
+ );
+ await userEvent.click( dismissButton );
+
+ expect( mockRecordEvent ).toHaveBeenCalledWith(
+ 'scheduled_updates_promotion_notice_dismissed'
+ );
+ } );
+ } );
+
+ describe( 'Link generation', () => {
+ test( 'should generate correct settings link', () => {
+ render( <ScheduledUpdatesPromotionNotice /> );
+
+ const settingsLink = screen.getByLabelText( 'Analytics settings' );
+
+ expect( settingsLink ).toBeInTheDocument();
+ expect( settingsLink ).toHaveAttribute(
+ 'href',
+ 'http://example.com/admin.php?page=wc-admin&path=/analytics/settings'
+ );
+ } );
+
+ test( 'should call getAdminLink with correct path', () => {
+ render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect( mockGetAdminLink ).toHaveBeenCalledWith(
+ 'admin.php?page=wc-admin&path=/analytics/settings'
+ );
+ } );
+ } );
+
+ describe( 'Notice content', () => {
+ test( 'should display correct notice message', () => {
+ render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect(
+ screen.getByText( ( content, element ) => {
+ const textContent = element?.textContent || '';
+ return (
+ element?.tagName.toLowerCase() === 'p' &&
+ textContent.includes(
+ 'Analytics now supports scheduled updates, providing improved performance. Enable it in'
+ ) &&
+ textContent.includes( 'Settings' )
+ );
+ } )
+ ).toBeInTheDocument();
+ } );
+
+ test( 'should have correct CSS classes', () => {
+ const { container } = render( <ScheduledUpdatesPromotionNotice /> );
+
+ const notice = container.querySelector(
+ '.notice.notice-info.is-dismissible'
+ );
+ expect( notice ).toBeInTheDocument();
+ } );
+
+ test( 'should render dismiss button with correct attributes', () => {
+ render( <ScheduledUpdatesPromotionNotice /> );
+
+ const dismissButton = screen.getByLabelText(
+ 'Dismiss this notice.'
+ );
+
+ expect( dismissButton ).toBeInTheDocument();
+ expect( dismissButton ).toHaveClass(
+ 'woocommerce-message-close',
+ 'notice-dismiss'
+ );
+ } );
+ } );
+
+ describe( 'Combined conditions', () => {
+ test( 'should render when all conditions are met', () => {
+ ( window as any ).wcAdminFeatures = {
+ 'analytics-scheduled-import': true,
+ };
+
+ mockUseSettings.mockReturnValue( {
+ wcAdminSettings: {},
+ } as unknown as ReturnType< typeof useSettings > );
+
+ mockUseUserPreferences.mockReturnValue( {
+ updateUserPreferences: jest.fn(),
+ scheduled_updates_promotion_notice_dismissed: undefined,
+ isRequesting: false,
+ } as unknown as ReturnType< typeof useUserPreferences > );
+
+ render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect(
+ screen.getByText( ( content, element ) => {
+ const textContent = element?.textContent || '';
+ return (
+ element?.tagName.toLowerCase() === 'p' &&
+ textContent.includes(
+ 'Analytics now supports scheduled updates, providing improved performance. Enable it in'
+ ) &&
+ textContent.includes( 'Settings' )
+ );
+ } )
+ ).toBeInTheDocument();
+ } );
+
+ test( 'should not render when feature flag is disabled even if other conditions are met', () => {
+ ( window as any ).wcAdminFeatures = {
+ 'analytics-scheduled-import': false,
+ };
+
+ mockUseSettings.mockReturnValue( {
+ wcAdminSettings: {},
+ } as unknown as ReturnType< typeof useSettings > );
+
+ mockUseUserPreferences.mockReturnValue( {
+ updateUserPreferences: jest.fn(),
+ scheduled_updates_promotion_notice_dismissed: undefined,
+ isRequesting: false,
+ } as unknown as ReturnType< typeof useUserPreferences > );
+
+ const { container } = render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect( container.firstChild ).toBeNull();
+ } );
+
+ test( 'should not render when option is set even if feature flag is enabled', () => {
+ ( window as any ).wcAdminFeatures = {
+ 'analytics-scheduled-import': true,
+ };
+
+ mockUseSettings.mockReturnValue( {
+ wcAdminSettings: {
+ woocommerce_analytics_immediate_import: 'yes',
+ },
+ } as unknown as ReturnType< typeof useSettings > );
+
+ mockUseUserPreferences.mockReturnValue( {
+ updateUserPreferences: jest.fn(),
+ scheduled_updates_promotion_notice_dismissed: undefined,
+ isRequesting: false,
+ } as unknown as ReturnType< typeof useUserPreferences > );
+
+ const { container } = render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect( container.firstChild ).toBeNull();
+ } );
+
+ test( 'should not render when dismissed even if feature flag is enabled and option is not set', () => {
+ ( window as any ).wcAdminFeatures = {
+ 'analytics-scheduled-import': true,
+ };
+
+ mockUseSettings.mockReturnValue( {
+ wcAdminSettings: {},
+ } as unknown as ReturnType< typeof useSettings > );
+
+ mockUseUserPreferences.mockReturnValue( {
+ updateUserPreferences: jest.fn(),
+ scheduled_updates_promotion_notice_dismissed: 'yes',
+ isRequesting: false,
+ } as unknown as ReturnType< typeof useUserPreferences > );
+
+ const { container } = render( <ScheduledUpdatesPromotionNotice /> );
+
+ expect( container.firstChild ).toBeNull();
+ } );
+ } );
+} );
diff --git a/plugins/woocommerce/client/admin/client/analytics/report/use-reports.js b/plugins/woocommerce/client/admin/client/analytics/report/use-reports.js
index 2cc85fb9fa..9b213f98e3 100644
--- a/plugins/woocommerce/client/admin/client/analytics/report/use-reports.js
+++ b/plugins/woocommerce/client/admin/client/analytics/report/use-reports.js
@@ -3,13 +3,14 @@
*/
import { __ } from '@wordpress/i18n';
import { applyFilters } from '@wordpress/hooks';
-import { lazy } from '@wordpress/element';
+import { lazy, Fragment } from '@wordpress/element';
/**
* Internal dependencies
*/
import { getAdminSetting } from '~/utils/admin-settings';
import { useFilterHook } from '~/utils/use-filter-hook';
+import { ScheduledUpdatesPromotionNotice } from '~/analytics/components';
const RevenueReport = lazy( () =>
import( /* webpackChunkName: "analytics-report-revenue" */ './revenue' )
@@ -132,6 +133,32 @@ const getReports = () => {
},
].filter( Boolean );
+ // Wrap the report component with the scheduled updates promotion notice
+ // Create a new array to avoid mutating the original, which could lead to
+ // multiple wrappings if getReports() is called multiple times.
+ const wrappedReports = reports.map( ( report ) => {
+ const OriginalComponent = report.component;
+
+ function WrappedComponent( props ) {
+ return (
+ <Fragment>
+ <ScheduledUpdatesPromotionNotice />
+ <OriginalComponent { ...props } />
+ </Fragment>
+ );
+ }
+
+ // Add displayName to help with debugging
+ WrappedComponent.displayName = `WithScheduledNotice(${
+ OriginalComponent.displayName || OriginalComponent.name || 'Report'
+ })`;
+
+ return {
+ ...report,
+ component: WrappedComponent,
+ };
+ } );
+
/**
* An object defining a report page.
*
@@ -148,7 +175,7 @@ const getReports = () => {
* @filter woocommerce_admin_reports_list
* @param {Array.<report>} reports Report pages list.
*/
- return applyFilters( REPORTS_FILTER, reports );
+ return applyFilters( REPORTS_FILTER, wrappedReports );
};
export function useReports() {
diff --git a/plugins/woocommerce/client/admin/client/dashboard/index.js b/plugins/woocommerce/client/admin/client/dashboard/index.js
index 3428c00df0..5be57e704a 100644
--- a/plugins/woocommerce/client/admin/client/dashboard/index.js
+++ b/plugins/woocommerce/client/admin/client/dashboard/index.js
@@ -13,6 +13,7 @@ import {
OrderAttributionInstallBannerImage,
} from '~/order-attribution-install-banner';
import './style.scss';
+import { ScheduledUpdatesPromotionNotice } from '~/analytics/components';
const CustomizableDashboard = lazy( () =>
import( /* webpackChunkName: "customizable-dashboard" */ './customizable' )
@@ -38,6 +39,7 @@ class Dashboard extends Component {
bannerImage={ <OrderAttributionInstallBannerImage /> }
dismissable
/>
+ <ScheduledUpdatesPromotionNotice />
<CustomizableDashboard query={ query } path={ path } />
</Suspense>
);
diff --git a/plugins/woocommerce/client/admin/client/typings/global.d.ts b/plugins/woocommerce/client/admin/client/typings/global.d.ts
index 8ca10394e3..6baeb64f92 100644
--- a/plugins/woocommerce/client/admin/client/typings/global.d.ts
+++ b/plugins/woocommerce/client/admin/client/typings/global.d.ts
@@ -49,6 +49,7 @@ declare global {
};
};
wcAdminFeatures: {
+ 'analytics-scheduled-import': boolean;
'activity-panels': boolean;
analytics: boolean;
'coming-soon-newsletter-template': boolean;
diff --git a/plugins/woocommerce/src/Internal/Admin/Analytics.php b/plugins/woocommerce/src/Internal/Admin/Analytics.php
index f706689a19..5f7398173b 100644
--- a/plugins/woocommerce/src/Internal/Admin/Analytics.php
+++ b/plugins/woocommerce/src/Internal/Admin/Analytics.php
@@ -146,6 +146,7 @@ class Analytics {
'dashboard_chart_interval',
'dashboard_leaderboard_rows',
'order_attribution_install_banner_dismissed',
+ 'scheduled_updates_promotion_notice_dismissed',
)
);
}
diff --git a/plugins/woocommerce/src/Internal/Admin/Settings.php b/plugins/woocommerce/src/Internal/Admin/Settings.php
index 4e19552cac..ab9333910b 100644
--- a/plugins/woocommerce/src/Internal/Admin/Settings.php
+++ b/plugins/woocommerce/src/Internal/Admin/Settings.php
@@ -356,7 +356,7 @@ class Settings {
'label' => __( 'Updates', 'woocommerce' ),
'description' => __( 'Controls how analytics data is imported from orders.', 'woocommerce' ),
'type' => 'radio',
- 'default' => 'yes', // Default to immediate import for backward compatibility to ensure we don't accidentally change the behavior for existing stores.
+ 'default' => null, // Default to null so we can know if it's a new site or an existing site. New sites will have the option set.
'options' => array(
'no' => __( 'Scheduled (recommended)', 'woocommerce' ),
'yes' => __( 'Immediately', 'woocommerce' ),