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' },