Skip to content
This repository was archived by the owner on Feb 23, 2024. It is now read-only.

Commit 333b630

Browse files
senadiropr
andauthored
Add Local Pickup event and Cart/Checkout page views events (#11225)
Co-authored-by: Thomas Roberts <[email protected]> Co-authored-by: Seghir Nadir <[email protected]>
1 parent a488672 commit 333b630

File tree

12 files changed

+632
-6
lines changed

12 files changed

+632
-6
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const namespace = 'jetpack-woocommerce-analytics';
2+
export const actionPrefix = 'experimental__woocommerce_blocks';
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import { Cart, isObject, objectHasProp } from '@woocommerce/types';
5+
import { select } from '@wordpress/data';
6+
import { getSetting } from '@woocommerce/settings';
7+
8+
/**
9+
* Internal dependencies
10+
*/
11+
import { STORE_KEY as CART_STORE_KEY } from '../../../data/cart/constants';
12+
13+
declare global {
14+
interface Window {
15+
// eslint-disable-next-line @typescript-eslint/naming-convention
16+
_wca: {
17+
// eslint-disable-next-line @typescript-eslint/ban-types
18+
push: ( properties: Record< string, unknown > ) => void;
19+
};
20+
}
21+
}
22+
23+
interface StorePageDetails {
24+
id: number;
25+
title: string;
26+
permalink: string;
27+
}
28+
29+
interface StorePages {
30+
checkout: StorePageDetails;
31+
cart: StorePageDetails;
32+
myaccount: StorePageDetails;
33+
privacy: StorePageDetails;
34+
shop: StorePageDetails;
35+
terms: StorePageDetails;
36+
}
37+
38+
/**
39+
* Check if the _wca object is valid and has a push property that is a function.
40+
*
41+
* @param wca {unknown} Object that might be a Jetpack WooCommerce Analytics object.
42+
*/
43+
// eslint-disable-next-line @typescript-eslint/ban-types
44+
const isValidWCA = (
45+
wca: unknown
46+
): wca is { push: ( properties: Record< string, unknown > ) => void } => {
47+
if ( ! isObject( wca ) || ! objectHasProp( wca, 'push' ) ) {
48+
return false;
49+
}
50+
return typeof wca.push === 'function';
51+
};
52+
53+
const registerActions = (): void => {
54+
if ( ! isValidWCA( window._wca ) ) {
55+
// eslint-disable-next-line no-useless-return
56+
return;
57+
}
58+
59+
// We will register actions here in a later PR.
60+
};
61+
62+
document.addEventListener( 'DOMContentLoaded', () => {
63+
registerActions();
64+
} );
65+
66+
export const cleanUrl = ( link: string ) => {
67+
const url = link.split( '?' )[ 0 ];
68+
if ( url.charAt( url.length - 1 ) !== '/' ) {
69+
return url + '/';
70+
}
71+
return url;
72+
};
73+
74+
const maybeTrackCheckoutPageView = ( cart: Cart ) => {
75+
const storePages = getSetting< StorePages >( 'storePages', {} );
76+
if ( ! objectHasProp( storePages, 'checkout' ) ) {
77+
return;
78+
}
79+
80+
if (
81+
cleanUrl( storePages?.checkout?.permalink ) !==
82+
cleanUrl( window.location.href )
83+
) {
84+
return;
85+
}
86+
87+
if ( ! isValidWCA( window._wca ) ) {
88+
return;
89+
}
90+
91+
const checkoutData = getSetting< Record< string, unknown > >(
92+
'wc-blocks-jetpack-woocommerce-analytics_cart_checkout_info',
93+
{}
94+
);
95+
96+
window._wca.push( {
97+
_en: 'woocommerceanalytics_checkout_view',
98+
products_count: cart.items.length,
99+
order_value: cart.totals.total_price,
100+
products: JSON.stringify(
101+
cart.items.map( ( item ) => {
102+
return {
103+
pp: item.totals.line_total,
104+
pq: item.quantity,
105+
pi: item.id,
106+
pn: item.name,
107+
};
108+
} )
109+
),
110+
...checkoutData,
111+
} );
112+
};
113+
114+
const maybeTrackCartPageView = ( cart: Cart ) => {
115+
const storePages = getSetting< StorePages >( 'storePages', {} );
116+
if ( ! objectHasProp( storePages, 'cart' ) ) {
117+
return;
118+
}
119+
120+
if (
121+
cleanUrl( storePages?.cart?.permalink ) !==
122+
cleanUrl( window.location.href )
123+
) {
124+
return;
125+
}
126+
127+
if ( ! isValidWCA( window._wca ) ) {
128+
return;
129+
}
130+
131+
const checkoutData = getSetting< Record< string, unknown > >(
132+
'wc-blocks-jetpack-woocommerce-analytics_cart_checkout_info',
133+
{}
134+
);
135+
136+
window._wca.push( {
137+
_en: 'woocommerceanalytics_cart_view',
138+
products_count: cart.items.length,
139+
order_value: cart.totals.total_price,
140+
products: JSON.stringify(
141+
cart.items.map( ( item ) => {
142+
return {
143+
pp: item.totals.line_total,
144+
pq: item.quantity,
145+
pi: item.id,
146+
pn: item.name,
147+
pt: item.type,
148+
};
149+
} )
150+
),
151+
...checkoutData,
152+
} );
153+
};
154+
155+
const maybeTrackOrderReceivedPageView = () => {
156+
const orderReceivedProps = getSetting(
157+
'wc-blocks-jetpack-woocommerce-analytics_order_received_properties',
158+
false
159+
);
160+
161+
if ( ! orderReceivedProps || ! isValidWCA( window._wca ) ) {
162+
return;
163+
}
164+
165+
window._wca.push( {
166+
_en: 'woocommerceanalytics_order_confirmation_view',
167+
...orderReceivedProps,
168+
} );
169+
};
170+
171+
document.addEventListener( 'DOMContentLoaded', () => {
172+
const store = select( CART_STORE_KEY );
173+
174+
// If the store doesn't load, we aren't on a cart/checkout block page, so maybe it's order received page.
175+
if ( ! store ) {
176+
maybeTrackOrderReceivedPageView();
177+
return;
178+
}
179+
180+
const hasCartLoaded = store.hasFinishedResolution( 'getCartTotals' );
181+
if ( hasCartLoaded ) {
182+
maybeTrackCartPageView( store.getCartData() );
183+
maybeTrackCheckoutPageView( store.getCartData() );
184+
}
185+
} );
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Internal dependencies
3+
*/
4+
import { cleanUrl } from '../index';
5+
6+
describe( 'WooCommerce Analytics', () => {
7+
describe( 'cleanUrl', () => {
8+
it( 'returns a clean URL with a trailing slash', () => {
9+
expect( cleanUrl( 'https://test.com?test=1' ) ).toEqual(
10+
'https://test.com/'
11+
);
12+
expect( cleanUrl( '' ) ).toEqual( '/' );
13+
expect( cleanUrl( 'https://test.com/' ) ).toEqual(
14+
'https://test.com/'
15+
);
16+
expect( cleanUrl( 'https://test.com' ) ).toEqual(
17+
'https://test.com/'
18+
);
19+
} );
20+
} );
21+
} );

assets/js/previews/cart.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export const previewCart: CartResponse = {
3939
{
4040
key: '1',
4141
id: 1,
42+
type: 'simple',
4243
quantity: 2,
4344
catalog_visibility: 'visible',
4445
name: __( 'Beanie', 'woo-gutenberg-products-block' ),
@@ -120,6 +121,7 @@ export const previewCart: CartResponse = {
120121
{
121122
key: '2',
122123
id: 2,
124+
type: 'simple',
123125
quantity: 1,
124126
catalog_visibility: 'visible',
125127
name: __( 'Cap', 'woo-gutenberg-products-block' ),

assets/js/types/type-defs/cart.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ export type CatalogVisibility = 'catalog' | 'hidden' | 'search' | 'visible';
123123
export interface CartItem {
124124
key: string;
125125
id: number;
126+
type: string;
126127
quantity: number;
127128
catalog_visibility: CatalogVisibility;
128129
quantity_limits: {

bin/webpack-entries.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ const entries = {
227227
'./assets/js/extensions/google-analytics/index.ts',
228228
'wc-shipping-method-pickup-location':
229229
'./assets/js/extensions/shipping-methods/pickup-location/index.js',
230+
'wc-blocks-jetpack-woocommerce-analytics':
231+
'./assets/js/extensions/jetpack/woocommerce-analytics/index.ts',
230232
},
231233
editor: {
232234
'wc-blocks-classic-template-revert-button':

src/Domain/Bootstrap.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Automattic\WooCommerce\Blocks\BlockTemplatesController;
99
use Automattic\WooCommerce\Blocks\BlockTypesController;
1010
use Automattic\WooCommerce\Blocks\Domain\Services\CreateAccount;
11+
use Automattic\WooCommerce\Blocks\Domain\Services\JetpackWooCommerceAnalytics;
1112
use Automattic\WooCommerce\Blocks\Domain\Services\Notices;
1213
use Automattic\WooCommerce\Blocks\Domain\Services\DraftOrders;
1314
use Automattic\WooCommerce\Blocks\Domain\Services\FeatureGating;
@@ -131,6 +132,7 @@ function() {
131132
$this->container->get( CreateAccount::class )->init();
132133
$this->container->get( ShippingController::class )->init();
133134
$this->container->get( TasksController::class )->init();
135+
$this->container->get( JetpackWooCommerceAnalytics::class )->init();
134136

135137
// Load assets in admin and on the frontend.
136138
if ( ! $is_rest ) {
@@ -364,6 +366,15 @@ function( Container $container ) {
364366
return new GoogleAnalytics( $asset_api );
365367
}
366368
);
369+
$this->container->register(
370+
JetpackWooCommerceAnalytics::class,
371+
function( Container $container ) {
372+
$asset_api = $container->get( AssetApi::class );
373+
$asset_data_registry = $container->get( AssetDataRegistry::class );
374+
$block_templates_controller = $container->get( BlockTemplatesController::class );
375+
return new JetpackWooCommerceAnalytics( $asset_api, $asset_data_registry, $block_templates_controller );
376+
}
377+
);
367378
$this->container->register(
368379
Notices::class,
369380
function( Container $container ) {

0 commit comments

Comments
 (0)