Commit b04bbd6b05 for woocommerce
commit b04bbd6b05aa3aab0fc148a80c9b5e7ac4d9f76d
Author: Taha Paksu <3295+tpaksu@users.noreply.github.com>
Date: Wed Feb 25 18:35:28 2026 +0300
[WOOPLUG-6347] Add unified shipping partner Tracks events on Core Profiler (#63439)
diff --git a/plugins/woocommerce/changelog/63439-add-wooplug-6347-core-profiler-shipping-tracks b/plugins/woocommerce/changelog/63439-add-wooplug-6347-core-profiler-shipping-tracks
new file mode 100644
index 0000000000..c95a02c51c
--- /dev/null
+++ b/plugins/woocommerce/changelog/63439-add-wooplug-6347-core-profiler-shipping-tracks
@@ -0,0 +1,4 @@
+Significance: patch
+Type: add
+
+Add unified shipping partner Tracks events (impression, click, install, activate) in the Core Profiler onboarding flow.
\ No newline at end of file
diff --git a/plugins/woocommerce/client/admin/client/core-profiler/actions/test/tracks.test.ts b/plugins/woocommerce/client/admin/client/core-profiler/actions/test/tracks.test.ts
new file mode 100644
index 0000000000..7b58cb13e6
--- /dev/null
+++ b/plugins/woocommerce/client/admin/client/core-profiler/actions/test/tracks.test.ts
@@ -0,0 +1,411 @@
+/**
+ * External dependencies
+ */
+import { recordEvent } from '@woocommerce/tracks';
+
+/**
+ * Internal dependencies
+ */
+import tracksActions, { resetShippingPartnerImpressionFlag } from '../tracks';
+import type { CoreProfilerStateMachineContext } from '../../index';
+import type { PluginInstallError } from '../../services/installAndActivatePlugins';
+
+jest.mock( '@woocommerce/tracks', () => ( {
+ recordEvent: jest.fn(),
+} ) );
+
+jest.mock( '@woocommerce/settings', () => ( {
+ getSetting: jest.fn( () => '9.8.0' ),
+} ) );
+
+const makeContext = (
+ overrides: Partial< CoreProfilerStateMachineContext > = {}
+): CoreProfilerStateMachineContext =>
+ ( {
+ optInDataSharing: false,
+ userProfile: {},
+ pluginsAvailable: [],
+ pluginsSelected: [],
+ pluginsInstallationErrors: [],
+ geolocatedLocation: undefined,
+ businessInfo: { location: 'US:CA' },
+ countries: [],
+ loader: {},
+ coreProfilerCompletedSteps: {},
+ onboardingProfile: {},
+ currentUserEmail: undefined,
+ ...overrides,
+ } as CoreProfilerStateMachineContext );
+
+const shippingPlugins = [
+ {
+ key: 'woocommerce-shipping',
+ slug: 'woocommerce-shipping',
+ name: 'WooCommerce Shipping',
+ label: 'WooCommerce Shipping',
+ is_activated: false,
+ description: '',
+ image_url: '',
+ manage_url: '',
+ is_built_by_wc: true,
+ is_visible: true,
+ },
+ {
+ key: 'woocommerce-shipstation-integration',
+ slug: 'woocommerce-shipstation-integration',
+ name: 'ShipStation',
+ label: 'ShipStation',
+ is_activated: false,
+ description: '',
+ image_url: '',
+ manage_url: '',
+ is_built_by_wc: false,
+ is_visible: true,
+ },
+];
+
+const nonShippingPlugin = {
+ key: 'woocommerce-payments',
+ slug: 'woocommerce-payments',
+ name: 'WooPayments',
+ label: 'WooPayments',
+ is_activated: false,
+ description: '',
+ image_url: '',
+ manage_url: '',
+ is_built_by_wc: true,
+ is_visible: true,
+};
+
+describe( 'Core Profiler shipping partner tracking', () => {
+ beforeEach( () => {
+ jest.clearAllMocks();
+ resetShippingPartnerImpressionFlag();
+ } );
+
+ describe( 'recordShippingPartnerImpression', () => {
+ it( 'should fire shipping_partner_impression when shipping plugins are available', () => {
+ const context = makeContext( {
+ pluginsAvailable: [ ...shippingPlugins, nonShippingPlugin ],
+ } );
+
+ tracksActions.recordShippingPartnerImpression( { context } );
+
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_impression',
+ {
+ context: 'core-profiler',
+ country: 'US',
+ plugins:
+ 'woocommerce-shipping,woocommerce-shipstation-integration',
+ }
+ );
+ } );
+
+ it( 'should not fire shipping_partner_impression when no shipping plugins are available', () => {
+ const context = makeContext( {
+ pluginsAvailable: [ nonShippingPlugin ],
+ } );
+
+ tracksActions.recordShippingPartnerImpression( { context } );
+
+ expect( recordEvent ).not.toHaveBeenCalledWith(
+ 'shipping_partner_impression',
+ expect.anything()
+ );
+ } );
+
+ it( 'should only fire shipping_partner_impression once even if called multiple times', () => {
+ const context = makeContext( {
+ pluginsAvailable: [ ...shippingPlugins, nonShippingPlugin ],
+ } );
+
+ tracksActions.recordShippingPartnerImpression( { context } );
+ tracksActions.recordShippingPartnerImpression( { context } );
+
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_impression',
+ {
+ context: 'core-profiler',
+ country: 'US',
+ plugins:
+ 'woocommerce-shipping,woocommerce-shipstation-integration',
+ }
+ );
+ expect(
+ ( recordEvent as jest.Mock ).mock.calls.filter(
+ ( [ eventName ] ) =>
+ eventName === 'shipping_partner_impression'
+ )
+ ).toHaveLength( 1 );
+ } );
+ } );
+
+ describe( 'recordTracksPluginsInstallationRequest (shipping_partner_click)', () => {
+ it( 'should fire shipping_partner_click for each selected shipping plugin', () => {
+ const context = makeContext( {
+ pluginsAvailable: [ ...shippingPlugins, nonShippingPlugin ],
+ } );
+
+ tracksActions.recordTracksPluginsInstallationRequest( {
+ context,
+ event: {
+ type: 'PLUGINS_INSTALLATION_REQUESTED',
+ payload: {
+ pluginsShown: [
+ 'woocommerce-shipping',
+ 'woocommerce-shipstation-integration',
+ 'woocommerce-payments',
+ ],
+ pluginsSelected: [
+ 'woocommerce-shipping',
+ 'woocommerce-shipstation-integration',
+ 'woocommerce-payments',
+ ],
+ pluginsUnselected: [],
+ },
+ },
+ } );
+
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_click',
+ {
+ context: 'core-profiler',
+ country: 'US',
+ plugins:
+ 'woocommerce-shipping,woocommerce-shipstation-integration',
+ selected_plugin: 'woocommerce-shipping',
+ }
+ );
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_click',
+ {
+ context: 'core-profiler',
+ country: 'US',
+ plugins:
+ 'woocommerce-shipping,woocommerce-shipstation-integration',
+ selected_plugin: 'woocommerce-shipstation-integration',
+ }
+ );
+ } );
+
+ it( 'should not fire shipping_partner_click when no shipping plugins are selected', () => {
+ const context = makeContext( {
+ pluginsAvailable: [ ...shippingPlugins, nonShippingPlugin ],
+ } );
+
+ tracksActions.recordTracksPluginsInstallationRequest( {
+ context,
+ event: {
+ type: 'PLUGINS_INSTALLATION_REQUESTED',
+ payload: {
+ pluginsShown: [
+ 'woocommerce-shipping',
+ 'woocommerce-payments',
+ ],
+ pluginsSelected: [ 'woocommerce-payments' ],
+ pluginsUnselected: [ 'woocommerce-shipping' ],
+ },
+ },
+ } );
+
+ expect( recordEvent ).not.toHaveBeenCalledWith(
+ 'shipping_partner_click',
+ expect.anything()
+ );
+ } );
+ } );
+
+ describe( 'recordSuccessfulPluginInstallation (shipping_partner_install + shipping_partner_activate)', () => {
+ it( 'should fire install and activate success for each shipping plugin', () => {
+ const context = makeContext( {
+ pluginsAvailable: [ ...shippingPlugins, nonShippingPlugin ],
+ } );
+
+ tracksActions.recordSuccessfulPluginInstallation( {
+ context,
+ event: {
+ type: 'PLUGINS_INSTALLATION_COMPLETED',
+ payload: {
+ installationCompletedResult: {
+ installedPlugins: [
+ {
+ plugin: 'woocommerce-shipping',
+ installTime: 1000,
+ },
+ {
+ plugin: 'woocommerce-payments',
+ installTime: 2000,
+ },
+ ],
+ totalTime: 3000,
+ },
+ },
+ },
+ } );
+
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_install',
+ {
+ context: 'core-profiler',
+ country: 'US',
+ plugins:
+ 'woocommerce-shipping,woocommerce-shipstation-integration',
+ selected_plugin: 'woocommerce-shipping',
+ success: true,
+ }
+ );
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_activate',
+ {
+ context: 'core-profiler',
+ country: 'US',
+ plugins:
+ 'woocommerce-shipping,woocommerce-shipstation-integration',
+ selected_plugin: 'woocommerce-shipping',
+ success: true,
+ }
+ );
+ } );
+
+ it( 'should not fire shipping events for non-shipping plugins', () => {
+ const context = makeContext( {
+ pluginsAvailable: [ nonShippingPlugin ],
+ } );
+
+ tracksActions.recordSuccessfulPluginInstallation( {
+ context,
+ event: {
+ type: 'PLUGINS_INSTALLATION_COMPLETED',
+ payload: {
+ installationCompletedResult: {
+ installedPlugins: [
+ {
+ plugin: 'woocommerce-payments',
+ installTime: 2000,
+ },
+ ],
+ totalTime: 2000,
+ },
+ },
+ },
+ } );
+
+ expect( recordEvent ).not.toHaveBeenCalledWith(
+ 'shipping_partner_install',
+ expect.anything()
+ );
+ expect( recordEvent ).not.toHaveBeenCalledWith(
+ 'shipping_partner_activate',
+ expect.anything()
+ );
+ } );
+ } );
+
+ describe( 'recordFailedPluginInstallations (shipping_partner_install failure)', () => {
+ it( 'should fire shipping_partner_install with failure for failed shipping plugins', () => {
+ const context = makeContext( {
+ pluginsAvailable: [ ...shippingPlugins, nonShippingPlugin ],
+ } );
+
+ const errors: PluginInstallError[] = [
+ {
+ plugin: 'woocommerce-shipping',
+ error: 'Install failed',
+ errorDetails: {
+ data: {
+ code: 'install_error',
+ data: { status: 500 },
+ },
+ },
+ },
+ ];
+
+ tracksActions.recordFailedPluginInstallations( {
+ context,
+ event: {
+ type: 'PLUGINS_INSTALLATION_COMPLETED_WITH_ERRORS',
+ payload: { errors },
+ },
+ } );
+
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_install',
+ {
+ context: 'core-profiler',
+ country: 'US',
+ plugins:
+ 'woocommerce-shipping,woocommerce-shipstation-integration',
+ selected_plugin: 'woocommerce-shipping',
+ success: false,
+ }
+ );
+ expect( recordEvent ).not.toHaveBeenCalledWith(
+ 'shipping_partner_activate',
+ expect.anything()
+ );
+ } );
+
+ it( 'should not fire shipping_partner_install for failed non-shipping plugins', () => {
+ const context = makeContext( {
+ pluginsAvailable: [ ...shippingPlugins, nonShippingPlugin ],
+ } );
+
+ const errors: PluginInstallError[] = [
+ {
+ plugin: 'woocommerce-payments',
+ error: 'Install failed',
+ errorDetails: {
+ data: {
+ code: 'install_error',
+ data: { status: 500 },
+ },
+ },
+ },
+ ];
+
+ tracksActions.recordFailedPluginInstallations( {
+ context,
+ event: {
+ type: 'PLUGINS_INSTALLATION_COMPLETED_WITH_ERRORS',
+ payload: { errors },
+ },
+ } );
+
+ expect( recordEvent ).not.toHaveBeenCalledWith(
+ 'shipping_partner_install',
+ expect.anything()
+ );
+ } );
+ } );
+
+ describe( 'country code extraction', () => {
+ it( 'should extract country code from location with state', () => {
+ const context = makeContext( {
+ pluginsAvailable: [ shippingPlugins[ 0 ] ],
+ businessInfo: { location: 'DE:BE' },
+ } );
+
+ tracksActions.recordShippingPartnerImpression( { context } );
+
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_impression',
+ expect.objectContaining( { country: 'DE' } )
+ );
+ } );
+
+ it( 'should handle missing location gracefully', () => {
+ const context = makeContext( {
+ pluginsAvailable: [ shippingPlugins[ 0 ] ],
+ businessInfo: {},
+ } );
+
+ tracksActions.recordShippingPartnerImpression( { context } );
+
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_impression',
+ expect.objectContaining( { country: '' } )
+ );
+ } );
+ } );
+} );
diff --git a/plugins/woocommerce/client/admin/client/core-profiler/actions/tracks.tsx b/plugins/woocommerce/client/admin/client/core-profiler/actions/tracks.tsx
index b0df2c24cb..ffc635e423 100644
--- a/plugins/woocommerce/client/admin/client/core-profiler/actions/tracks.tsx
+++ b/plugins/woocommerce/client/admin/client/core-profiler/actions/tracks.tsx
@@ -22,6 +22,32 @@ import {
PluginInstallError,
} from '../services/installAndActivatePlugins';
import { getPluginTrackKey, getTimeFrame } from '~/utils';
+import { getPluginSlug } from '~/utils/plugins';
+import { getCountryCode } from '~/dashboard/utils';
+
+const SHIPPING_PLUGIN_SLUGS = new Set( [
+ 'woocommerce-shipping',
+ 'woocommerce-shipstation-integration',
+ 'packlink-pro-shipping',
+] );
+
+const isShippingPlugin = ( pluginKey: string ) =>
+ SHIPPING_PLUGIN_SLUGS.has( getPluginSlug( pluginKey ) );
+
+const getShippingPartnerTrackingBase = (
+ context: CoreProfilerStateMachineContext
+) => {
+ const shippingPlugins = context.pluginsAvailable
+ .filter( ( plugin ) => isShippingPlugin( plugin.key ) )
+ .map( ( plugin ) => getPluginSlug( plugin.key ) )
+ .join( ',' );
+
+ return {
+ context: 'core-profiler' as const,
+ country: getCountryCode( context.businessInfo.location ) ?? '',
+ plugins: shippingPlugins,
+ };
+};
const recordTracksStepViewed = ( _: unknown, params: { step: string } ) => {
recordEvent( 'coreprofiler_step_view', {
@@ -138,9 +164,30 @@ const recordTracksBusinessInfoCompleted = ( {
} );
};
+let shippingPartnerImpressionRecorded = false;
+
+const recordShippingPartnerImpression = ( {
+ context,
+}: {
+ context: CoreProfilerStateMachineContext;
+} ) => {
+ if ( shippingPartnerImpressionRecorded ) {
+ return;
+ }
+
+ const trackingBase = getShippingPartnerTrackingBase( context );
+
+ if ( trackingBase.plugins.length > 0 ) {
+ shippingPartnerImpressionRecorded = true;
+ recordEvent( 'shipping_partner_impression', trackingBase );
+ }
+};
+
const recordTracksPluginsInstallationRequest = ( {
+ context,
event,
}: {
+ context: CoreProfilerStateMachineContext;
event: Extract<
PluginsInstallationRequestedEvent,
{ type: 'PLUGINS_INSTALLATION_REQUESTED' }
@@ -151,6 +198,18 @@ const recordTracksPluginsInstallationRequest = ( {
selected: event.payload.pluginsSelected || [],
unselected: event.payload.pluginsUnselected || [],
} );
+
+ const trackingBase = getShippingPartnerTrackingBase( context );
+ const selectedShippingPlugins = (
+ event.payload.pluginsSelected || []
+ ).filter( ( slug ) => SHIPPING_PLUGIN_SLUGS.has( getPluginSlug( slug ) ) );
+
+ selectedShippingPlugins.forEach( ( pluginSlug ) => {
+ recordEvent( 'shipping_partner_click', {
+ ...trackingBase,
+ selected_plugin: getPluginSlug( pluginSlug ),
+ } );
+ } );
};
const recordTracksPluginsLearnMoreLinkClicked = (
@@ -167,8 +226,10 @@ const recordTracksPluginsInstallationNoPermissionError = () =>
recordEvent( 'coreprofiler_store_extensions_no_permission_error' );
const recordFailedPluginInstallations = ( {
+ context,
event,
}: {
+ context: CoreProfilerStateMachineContext;
event: PluginsInstallationCompletedWithErrorsEvent;
} ) => {
const failedExtensions = event.payload.errors.map(
@@ -180,18 +241,30 @@ const recordFailedPluginInstallations = ( {
failed_extensions: failedExtensions,
} );
+ const trackingBase = getShippingPartnerTrackingBase( context );
+
event.payload.errors.forEach( ( error: PluginInstallError ) => {
recordEvent( 'coreprofiler_store_extension_installed_and_activated', {
success: false,
extension: getPluginTrackKey( error.plugin ),
error_message: error.error,
} );
+
+ if ( isShippingPlugin( error.plugin ) ) {
+ recordEvent( 'shipping_partner_install', {
+ ...trackingBase,
+ selected_plugin: getPluginSlug( error.plugin ),
+ success: false,
+ } );
+ }
} );
};
const recordSuccessfulPluginInstallation = ( {
+ context,
event,
}: {
+ context: CoreProfilerStateMachineContext;
event: PluginsInstallationCompletedEvent;
} ) => {
const installationCompletedResult =
@@ -211,6 +284,8 @@ const recordSuccessfulPluginInstallation = ( {
total_time: getTimeFrame( installationCompletedResult.totalTime ),
};
+ const trackingBase = getShippingPartnerTrackingBase( context );
+
for ( const installedPlugin of installationCompletedResult.installedPlugins ) {
const pluginKey = getPluginTrackKey( installedPlugin.plugin );
const installTime = getTimeFrame( installedPlugin.installTime );
@@ -221,6 +296,20 @@ const recordSuccessfulPluginInstallation = ( {
extension: pluginKey,
install_time: installTime,
} );
+
+ if ( isShippingPlugin( installedPlugin.plugin ) ) {
+ const slug = getPluginSlug( installedPlugin.plugin );
+ recordEvent( 'shipping_partner_install', {
+ ...trackingBase,
+ selected_plugin: slug,
+ success: true,
+ } );
+ recordEvent( 'shipping_partner_activate', {
+ ...trackingBase,
+ selected_plugin: slug,
+ success: true,
+ } );
+ }
}
recordEvent(
@@ -229,6 +318,10 @@ const recordSuccessfulPluginInstallation = ( {
);
};
+export const resetShippingPartnerImpressionFlag = () => {
+ shippingPartnerImpressionRecorded = false;
+};
+
export default {
recordTracksStepViewed,
recordTracksStepSkipped,
@@ -243,4 +336,5 @@ export default {
recordSuccessfulPluginInstallation,
recordTracksPluginsInstallationRequest,
recordTracksIsEmailChanged,
+ recordShippingPartnerImpression,
};
diff --git a/plugins/woocommerce/client/admin/client/core-profiler/index.tsx b/plugins/woocommerce/client/admin/client/core-profiler/index.tsx
index a777dde2fe..fc610bd391 100644
--- a/plugins/woocommerce/client/admin/client/core-profiler/index.tsx
+++ b/plugins/woocommerce/client/admin/client/core-profiler/index.tsx
@@ -1503,6 +1503,9 @@ export const coreProfilerStateMachineDefinition = createMachine( {
type: 'recordTracksStepViewed',
params: { step: 'plugins' },
},
+ {
+ type: 'recordShippingPartnerImpression',
+ },
{
type: 'updateQueryStep',
params: { step: 'plugins' },