Commit 84c617828f3 for woocommerce
commit 84c617828f3be3013b86f0d01a17ce84919bb698
Author: Taha Paksu <3295+tpaksu@users.noreply.github.com>
Date: Tue Mar 3 20:09:52 2026 +0300
[WOOPLUG-6346] Add unified shipping partner Tracks events on task list (#63438)
diff --git a/plugins/woocommerce/client/admin/client/task-lists/fills/shipping/index.js b/plugins/woocommerce/client/admin/client/task-lists/fills/shipping/index.js
index d7d78e2a09f..eb6246a84cd 100644
--- a/plugins/woocommerce/client/admin/client/task-lists/fills/shipping/index.js
+++ b/plugins/woocommerce/client/admin/client/task-lists/fills/shipping/index.js
@@ -65,6 +65,7 @@ export class Shipping extends Component {
this.storeLocationCompleted = false;
this.shippingPartners = props.shippingPartners;
+ this.impressionFired = false;
this.jetpackAuthRedirectUrl = getAdminLink( 'admin.php?page=wc-admin' );
}
@@ -136,6 +137,58 @@ export class Shipping extends Component {
this.setState( { isPending: false, shippingZones } );
}
+ getShippingPartnerTrackingProps() {
+ const { countryCode, shippingPartners = [] } = this.props;
+ const pluginSlugs = shippingPartners
+ .map( ( partner ) => partner.slug )
+ .filter(
+ ( slug ) => typeof slug === 'string' && slug.trim().length > 0
+ )
+ .join( ',' );
+ return {
+ context: 'tasklist',
+ country: countryCode,
+ plugins: pluginSlugs,
+ };
+ }
+
+ recordInstallAndActivateEvents( selectedPlugin, success ) {
+ const trackingBase = {
+ ...this.getShippingPartnerTrackingProps(),
+ selected_plugin: selectedPlugin,
+ };
+
+ if ( success ) {
+ recordEvent( 'shipping_partner_install', {
+ ...trackingBase,
+ success: true,
+ } );
+ recordEvent( 'shipping_partner_activate', {
+ ...trackingBase,
+ success: true,
+ } );
+ } else {
+ const { installedPlugins = [] } = this.props;
+ const wasInstalled = installedPlugins.includes( selectedPlugin );
+
+ if ( wasInstalled ) {
+ recordEvent( 'shipping_partner_install', {
+ ...trackingBase,
+ success: true,
+ } );
+ recordEvent( 'shipping_partner_activate', {
+ ...trackingBase,
+ success: false,
+ } );
+ } else {
+ recordEvent( 'shipping_partner_install', {
+ ...trackingBase,
+ success: false,
+ } );
+ }
+ }
+ }
+
componentDidUpdate( prevProps, prevState ) {
const { countryCode, countryName, settings } = this.props;
const {
@@ -157,6 +210,21 @@ export class Shipping extends Component {
}
}
+ if (
+ step === 'label_printing' &&
+ prevState.step !== 'label_printing' &&
+ ! this.impressionFired
+ ) {
+ const { shippingPartners = [] } = this.props;
+ if ( shippingPartners.length > 0 ) {
+ recordEvent(
+ 'shipping_partner_impression',
+ this.getShippingPartnerTrackingProps()
+ );
+ this.impressionFired = true;
+ }
+ }
+
const isCompleteAddress = Boolean(
storeAddress && defaultCountry && storePostCode
);
@@ -350,26 +418,26 @@ export class Shipping extends Component {
<Plugins
onComplete={ ( _plugins, response ) => {
createNoticesFromResponse( response );
- recordEvent(
- 'tasklist_shipping_label_printing',
- {
- install: true,
- plugins_to_activate: pluginsToActivate,
- }
+ this.recordInstallAndActivateEvents(
+ pluginsToActivate[ 0 ],
+ true
);
this.completeStep();
} }
- onError={ ( errors, response ) =>
- createNoticesFromResponse( response )
- }
- onSkip={ () => {
- recordEvent(
- 'tasklist_shipping_label_printing',
- {
- install: false,
- plugins_to_activate: pluginsToActivate,
- }
+ onError={ ( errors, response ) => {
+ createNoticesFromResponse( response );
+ this.recordInstallAndActivateEvents(
+ pluginsToActivate[ 0 ],
+ false
);
+ } }
+ onClick={ () => {
+ recordEvent( 'shipping_partner_click', {
+ ...this.getShippingPartnerTrackingProps(),
+ selected_plugin: pluginsToActivate[ 0 ],
+ } );
+ } }
+ onSkip={ () => {
invalidateResolutionForStoreSelector();
getHistory().push( getNewPath( {}, '/', {} ) );
onComplete();
@@ -483,13 +551,9 @@ export class Shipping extends Component {
createNoticesFromResponse(
response
);
- recordEvent(
- 'tasklist_shipping_label_printing',
- {
- install: true,
- plugins_to_activate:
- pluginsForPartner,
- }
+ this.recordInstallAndActivateEvents(
+ shippingMethod.slug,
+ true
);
invalidateResolutionForStoreSelector();
this.completeStep();
@@ -497,11 +561,25 @@ export class Shipping extends Component {
onError={ (
errors,
response
- ) =>
+ ) => {
createNoticesFromResponse(
response
- )
- }
+ );
+ this.recordInstallAndActivateEvents(
+ shippingMethod.slug,
+ false
+ );
+ } }
+ onClick={ () => {
+ recordEvent(
+ 'shipping_partner_click',
+ {
+ ...this.getShippingPartnerTrackingProps(),
+ selected_plugin:
+ shippingMethod.slug,
+ }
+ );
+ } }
installText={ __(
'Install and enable',
'woocommerce'
@@ -566,22 +644,33 @@ export class Shipping extends Component {
createNoticesFromResponse(
response
);
- recordEvent(
- 'tasklist_shipping_label_printing',
- {
- install: true,
- plugins_to_activate:
- pluginsToActivate,
- }
+ this.recordInstallAndActivateEvents(
+ pluginsToPromote[ 0 ]?.slug,
+ true
);
invalidateResolutionForStoreSelector();
this.completeStep();
} }
- onError={ ( errors, response ) =>
+ onError={ ( errors, response ) => {
createNoticesFromResponse(
response
- )
- }
+ );
+ this.recordInstallAndActivateEvents(
+ pluginsToPromote[ 0 ]?.slug,
+ false
+ );
+ } }
+ onClick={ () => {
+ recordEvent(
+ 'shipping_partner_click',
+ {
+ ...this.getShippingPartnerTrackingProps(),
+ selected_plugin:
+ pluginsToPromote[ 0 ]
+ ?.slug,
+ }
+ );
+ } }
onSkip={
onShippingPluginInstalltionSkip
}
@@ -687,7 +776,8 @@ const ShippingWrapper = compose(
withSelect( ( select ) => {
const { getSettings, isUpdateSettingsRequesting } =
select( settingsStore );
- const { getActivePlugins, isJetpackConnected } = select( pluginsStore );
+ const { getActivePlugins, getInstalledPlugins, isJetpackConnected } =
+ select( pluginsStore );
const { getCountry } = select( COUNTRIES_STORE_NAME );
const { general: settings = {} } = getSettings( 'general' );
@@ -701,6 +791,7 @@ const ShippingWrapper = compose(
const country = countryCode ? getCountry( countryCode ) : null;
const countryName = country ? country.name : null;
const activePlugins = getActivePlugins();
+ const installedPlugins = getInstalledPlugins();
return {
countryCode,
@@ -708,6 +799,7 @@ const ShippingWrapper = compose(
isUpdateSettingsRequesting: isUpdateSettingsRequesting( 'general' ),
settings,
activePlugins,
+ installedPlugins,
isJetpackConnected: isJetpackConnected(),
shippingPartners,
};
diff --git a/plugins/woocommerce/client/admin/client/task-lists/fills/shipping/test/index.tsx b/plugins/woocommerce/client/admin/client/task-lists/fills/shipping/test/index.tsx
index 5ebfcb82a12..1c2c5297c4a 100644
--- a/plugins/woocommerce/client/admin/client/task-lists/fills/shipping/test/index.tsx
+++ b/plugins/woocommerce/client/admin/client/task-lists/fills/shipping/test/index.tsx
@@ -97,4 +97,289 @@ describe( 'Shipping', () => {
it( 'treats missing slugs as non-installable partners', () => {
expect( hasInstallableSlug( {} ) ).toBe( false );
} );
+
+ describe( 'shipping partner impression tracking', () => {
+ it( 'should fire shipping_partner_impression when entering label_printing step with partners', () => {
+ const shippingPartners = [
+ {
+ id: 'woocommerce-shipping',
+ name: 'WooCommerce Shipping',
+ slug: 'woocommerce-shipping',
+ },
+ {
+ id: 'shipstation',
+ name: 'ShipStation',
+ slug: 'woocommerce-shipstation-integration',
+ },
+ ];
+
+ const component = new Shipping( {
+ ...props,
+ shippingPartners,
+ } );
+
+ // Simulate componentDidMount
+ component.setState = jest.fn();
+ component.state = { ...component.state, step: 'store_location' };
+
+ // Simulate stepping to label_printing
+ component.componentDidUpdate(
+ { ...props, shippingPartners },
+ { step: 'rates' }
+ );
+
+ // Should not fire yet because step is store_location, not label_printing
+ expect( recordEvent ).not.toHaveBeenCalledWith(
+ 'shipping_partner_impression',
+ expect.anything()
+ );
+
+ // Now simulate the step being label_printing
+ component.state = { ...component.state, step: 'label_printing' };
+ component.componentDidUpdate(
+ { ...props, shippingPartners },
+ { step: 'rates' }
+ );
+
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_impression',
+ {
+ context: 'tasklist',
+ country: 'US',
+ plugins:
+ 'woocommerce-shipping,woocommerce-shipstation-integration',
+ }
+ );
+ } );
+
+ it( 'should not fire shipping_partner_impression when there are no shipping partners', () => {
+ ( recordEvent as jest.Mock ).mockClear();
+
+ const component = new Shipping( {
+ ...props,
+ shippingPartners: [],
+ } );
+
+ component.setState = jest.fn();
+ component.state = { ...component.state, step: 'label_printing' };
+
+ component.componentDidUpdate(
+ { ...props, shippingPartners: [] },
+ { step: 'rates' }
+ );
+
+ expect( recordEvent ).not.toHaveBeenCalledWith(
+ 'shipping_partner_impression',
+ expect.anything()
+ );
+ } );
+
+ it( 'should only fire shipping_partner_impression once', () => {
+ ( recordEvent as jest.Mock ).mockClear();
+
+ const shippingPartners = [
+ {
+ id: 'woocommerce-shipping',
+ name: 'WooCommerce Shipping',
+ slug: 'woocommerce-shipping',
+ },
+ ];
+
+ const component = new Shipping( {
+ ...props,
+ shippingPartners,
+ } );
+
+ component.setState = jest.fn();
+ component.state = { ...component.state, step: 'label_printing' };
+
+ // First transition into label_printing
+ component.componentDidUpdate(
+ { ...props, shippingPartners },
+ { step: 'rates' }
+ );
+
+ // Second transition (e.g., re-entering)
+ component.componentDidUpdate(
+ { ...props, shippingPartners },
+ { step: 'rates' }
+ );
+
+ const impressionCalls = (
+ recordEvent as jest.Mock
+ ).mock.calls.filter(
+ ( call ) => call[ 0 ] === 'shipping_partner_impression'
+ );
+ expect( impressionCalls ).toHaveLength( 1 );
+ } );
+ } );
+
+ describe( 'recordInstallAndActivateEvents', () => {
+ const shippingPartners = [
+ {
+ id: 'woocommerce-shipping',
+ name: 'WooCommerce Shipping',
+ slug: 'woocommerce-shipping',
+ },
+ ];
+
+ it( 'should fire both install and activate success events on success', () => {
+ ( recordEvent as jest.Mock ).mockClear();
+
+ const component = new Shipping( {
+ ...props,
+ shippingPartners,
+ installedPlugins: [],
+ } );
+
+ component.recordInstallAndActivateEvents(
+ 'woocommerce-shipping',
+ true
+ );
+
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_install',
+ {
+ context: 'tasklist',
+ country: 'US',
+ plugins: 'woocommerce-shipping',
+ selected_plugin: 'woocommerce-shipping',
+ success: true,
+ }
+ );
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_activate',
+ {
+ context: 'tasklist',
+ country: 'US',
+ plugins: 'woocommerce-shipping',
+ selected_plugin: 'woocommerce-shipping',
+ success: true,
+ }
+ );
+ } );
+
+ it( 'should fire install failure only when plugin was not installed', () => {
+ ( recordEvent as jest.Mock ).mockClear();
+
+ const component = new Shipping( {
+ ...props,
+ shippingPartners,
+ installedPlugins: [],
+ } );
+
+ component.recordInstallAndActivateEvents(
+ 'woocommerce-shipping',
+ false
+ );
+
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_install',
+ {
+ context: 'tasklist',
+ country: 'US',
+ plugins: 'woocommerce-shipping',
+ selected_plugin: 'woocommerce-shipping',
+ success: false,
+ }
+ );
+ expect( recordEvent ).not.toHaveBeenCalledWith(
+ 'shipping_partner_activate',
+ expect.anything()
+ );
+ } );
+
+ it( 'should fire install success and activate failure when plugin was installed but activation failed', () => {
+ ( recordEvent as jest.Mock ).mockClear();
+
+ const component = new Shipping( {
+ ...props,
+ shippingPartners,
+ installedPlugins: [ 'woocommerce-shipping' ],
+ } );
+
+ component.recordInstallAndActivateEvents(
+ 'woocommerce-shipping',
+ false
+ );
+
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_install',
+ {
+ context: 'tasklist',
+ country: 'US',
+ plugins: 'woocommerce-shipping',
+ selected_plugin: 'woocommerce-shipping',
+ success: true,
+ }
+ );
+ expect( recordEvent ).toHaveBeenCalledWith(
+ 'shipping_partner_activate',
+ {
+ context: 'tasklist',
+ country: 'US',
+ plugins: 'woocommerce-shipping',
+ selected_plugin: 'woocommerce-shipping',
+ success: false,
+ }
+ );
+ } );
+ } );
+
+ describe( 'getShippingPartnerTrackingProps', () => {
+ it( 'should return correct tracking props', () => {
+ const shippingPartners = [
+ {
+ id: 'woocommerce-shipping',
+ name: 'WooCommerce Shipping',
+ slug: 'woocommerce-shipping',
+ },
+ {
+ id: 'shipstation',
+ name: 'ShipStation',
+ slug: 'woocommerce-shipstation-integration',
+ },
+ ];
+
+ const component = new Shipping( {
+ ...props,
+ shippingPartners,
+ } );
+
+ const trackingProps = component.getShippingPartnerTrackingProps();
+ expect( trackingProps ).toEqual( {
+ context: 'tasklist',
+ country: 'US',
+ plugins:
+ 'woocommerce-shipping,woocommerce-shipstation-integration',
+ } );
+ } );
+
+ it( 'should filter out partners without slugs', () => {
+ const shippingPartners = [
+ {
+ id: 'woocommerce-shipping',
+ name: 'WooCommerce Shipping',
+ slug: 'woocommerce-shipping',
+ },
+ {
+ id: 'envia',
+ name: 'Envia',
+ slug: '',
+ },
+ ];
+
+ const component = new Shipping( {
+ ...props,
+ shippingPartners,
+ } );
+
+ const trackingProps = component.getShippingPartnerTrackingProps();
+ expect( trackingProps ).toEqual( {
+ context: 'tasklist',
+ country: 'US',
+ plugins: 'woocommerce-shipping',
+ } );
+ } );
+ } );
} );