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

Commit

Permalink
Add Local Pickup event and Cart/Checkout page views events (#11225)
Browse files Browse the repository at this point in the history
Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com>
Co-authored-by: Seghir Nadir <nadir.seghir@gmail.com>
  • Loading branch information
senadir and opr authored Oct 23, 2023
1 parent a488672 commit 333b630
Show file tree
Hide file tree
Showing 12 changed files with 632 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const namespace = 'jetpack-woocommerce-analytics';
export const actionPrefix = 'experimental__woocommerce_blocks';
185 changes: 185 additions & 0 deletions assets/js/extensions/jetpack/woocommerce-analytics/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/**
* External dependencies
*/
import { Cart, isObject, objectHasProp } from '@woocommerce/types';
import { select } from '@wordpress/data';
import { getSetting } from '@woocommerce/settings';

/**
* Internal dependencies
*/
import { STORE_KEY as CART_STORE_KEY } from '../../../data/cart/constants';

declare global {
interface Window {
// eslint-disable-next-line @typescript-eslint/naming-convention
_wca: {
// eslint-disable-next-line @typescript-eslint/ban-types
push: ( properties: Record< string, unknown > ) => void;
};
}
}

interface StorePageDetails {
id: number;
title: string;
permalink: string;
}

interface StorePages {
checkout: StorePageDetails;
cart: StorePageDetails;
myaccount: StorePageDetails;
privacy: StorePageDetails;
shop: StorePageDetails;
terms: StorePageDetails;
}

/**
* Check if the _wca object is valid and has a push property that is a function.
*
* @param wca {unknown} Object that might be a Jetpack WooCommerce Analytics object.
*/
// eslint-disable-next-line @typescript-eslint/ban-types
const isValidWCA = (
wca: unknown
): wca is { push: ( properties: Record< string, unknown > ) => void } => {
if ( ! isObject( wca ) || ! objectHasProp( wca, 'push' ) ) {
return false;
}
return typeof wca.push === 'function';
};

const registerActions = (): void => {
if ( ! isValidWCA( window._wca ) ) {
// eslint-disable-next-line no-useless-return
return;
}

// We will register actions here in a later PR.
};

document.addEventListener( 'DOMContentLoaded', () => {
registerActions();
} );

export const cleanUrl = ( link: string ) => {
const url = link.split( '?' )[ 0 ];
if ( url.charAt( url.length - 1 ) !== '/' ) {
return url + '/';
}
return url;
};

const maybeTrackCheckoutPageView = ( cart: Cart ) => {
const storePages = getSetting< StorePages >( 'storePages', {} );
if ( ! objectHasProp( storePages, 'checkout' ) ) {
return;
}

if (
cleanUrl( storePages?.checkout?.permalink ) !==
cleanUrl( window.location.href )
) {
return;
}

if ( ! isValidWCA( window._wca ) ) {
return;
}

const checkoutData = getSetting< Record< string, unknown > >(
'wc-blocks-jetpack-woocommerce-analytics_cart_checkout_info',
{}
);

window._wca.push( {
_en: 'woocommerceanalytics_checkout_view',
products_count: cart.items.length,
order_value: cart.totals.total_price,
products: JSON.stringify(
cart.items.map( ( item ) => {
return {
pp: item.totals.line_total,
pq: item.quantity,
pi: item.id,
pn: item.name,
};
} )
),
...checkoutData,
} );
};

const maybeTrackCartPageView = ( cart: Cart ) => {
const storePages = getSetting< StorePages >( 'storePages', {} );
if ( ! objectHasProp( storePages, 'cart' ) ) {
return;
}

if (
cleanUrl( storePages?.cart?.permalink ) !==
cleanUrl( window.location.href )
) {
return;
}

if ( ! isValidWCA( window._wca ) ) {
return;
}

const checkoutData = getSetting< Record< string, unknown > >(
'wc-blocks-jetpack-woocommerce-analytics_cart_checkout_info',
{}
);

window._wca.push( {
_en: 'woocommerceanalytics_cart_view',
products_count: cart.items.length,
order_value: cart.totals.total_price,
products: JSON.stringify(
cart.items.map( ( item ) => {
return {
pp: item.totals.line_total,
pq: item.quantity,
pi: item.id,
pn: item.name,
pt: item.type,
};
} )
),
...checkoutData,
} );
};

const maybeTrackOrderReceivedPageView = () => {
const orderReceivedProps = getSetting(
'wc-blocks-jetpack-woocommerce-analytics_order_received_properties',
false
);

if ( ! orderReceivedProps || ! isValidWCA( window._wca ) ) {
return;
}

window._wca.push( {
_en: 'woocommerceanalytics_order_confirmation_view',
...orderReceivedProps,
} );
};

document.addEventListener( 'DOMContentLoaded', () => {
const store = select( CART_STORE_KEY );

// If the store doesn't load, we aren't on a cart/checkout block page, so maybe it's order received page.
if ( ! store ) {
maybeTrackOrderReceivedPageView();
return;
}

const hasCartLoaded = store.hasFinishedResolution( 'getCartTotals' );
if ( hasCartLoaded ) {
maybeTrackCartPageView( store.getCartData() );
maybeTrackCheckoutPageView( store.getCartData() );
}
} );
21 changes: 21 additions & 0 deletions assets/js/extensions/jetpack/woocommerce-analytics/test/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Internal dependencies
*/
import { cleanUrl } from '../index';

describe( 'WooCommerce Analytics', () => {
describe( 'cleanUrl', () => {
it( 'returns a clean URL with a trailing slash', () => {
expect( cleanUrl( 'https://test.com?test=1' ) ).toEqual(
'https://test.com/'
);
expect( cleanUrl( '' ) ).toEqual( '/' );
expect( cleanUrl( 'https://test.com/' ) ).toEqual(
'https://test.com/'
);
expect( cleanUrl( 'https://test.com' ) ).toEqual(
'https://test.com/'
);
} );
} );
} );
2 changes: 2 additions & 0 deletions assets/js/previews/cart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const previewCart: CartResponse = {
{
key: '1',
id: 1,
type: 'simple',
quantity: 2,
catalog_visibility: 'visible',
name: __( 'Beanie', 'woo-gutenberg-products-block' ),
Expand Down Expand Up @@ -120,6 +121,7 @@ export const previewCart: CartResponse = {
{
key: '2',
id: 2,
type: 'simple',
quantity: 1,
catalog_visibility: 'visible',
name: __( 'Cap', 'woo-gutenberg-products-block' ),
Expand Down
1 change: 1 addition & 0 deletions assets/js/types/type-defs/cart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export type CatalogVisibility = 'catalog' | 'hidden' | 'search' | 'visible';
export interface CartItem {
key: string;
id: number;
type: string;
quantity: number;
catalog_visibility: CatalogVisibility;
quantity_limits: {
Expand Down
2 changes: 2 additions & 0 deletions bin/webpack-entries.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ const entries = {
'./assets/js/extensions/google-analytics/index.ts',
'wc-shipping-method-pickup-location':
'./assets/js/extensions/shipping-methods/pickup-location/index.js',
'wc-blocks-jetpack-woocommerce-analytics':
'./assets/js/extensions/jetpack/woocommerce-analytics/index.ts',
},
editor: {
'wc-blocks-classic-template-revert-button':
Expand Down
11 changes: 11 additions & 0 deletions src/Domain/Bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Automattic\WooCommerce\Blocks\BlockTemplatesController;
use Automattic\WooCommerce\Blocks\BlockTypesController;
use Automattic\WooCommerce\Blocks\Domain\Services\CreateAccount;
use Automattic\WooCommerce\Blocks\Domain\Services\JetpackWooCommerceAnalytics;
use Automattic\WooCommerce\Blocks\Domain\Services\Notices;
use Automattic\WooCommerce\Blocks\Domain\Services\DraftOrders;
use Automattic\WooCommerce\Blocks\Domain\Services\FeatureGating;
Expand Down Expand Up @@ -131,6 +132,7 @@ function() {
$this->container->get( CreateAccount::class )->init();
$this->container->get( ShippingController::class )->init();
$this->container->get( TasksController::class )->init();
$this->container->get( JetpackWooCommerceAnalytics::class )->init();

// Load assets in admin and on the frontend.
if ( ! $is_rest ) {
Expand Down Expand Up @@ -364,6 +366,15 @@ function( Container $container ) {
return new GoogleAnalytics( $asset_api );
}
);
$this->container->register(
JetpackWooCommerceAnalytics::class,
function( Container $container ) {
$asset_api = $container->get( AssetApi::class );
$asset_data_registry = $container->get( AssetDataRegistry::class );
$block_templates_controller = $container->get( BlockTemplatesController::class );
return new JetpackWooCommerceAnalytics( $asset_api, $asset_data_registry, $block_templates_controller );
}
);
$this->container->register(
Notices::class,
function( Container $container ) {
Expand Down
Loading

0 comments on commit 333b630

Please sign in to comment.