initial commit

This commit is contained in:
2021-12-10 12:03:04 +00:00
commit c46c7ddbf0
3643 changed files with 582794 additions and 0 deletions

View File

@ -0,0 +1,2 @@
export const namespace = 'woocommerce-google-analytics';
export const actionPrefix = 'experimental__woocommerce_blocks';

View File

@ -0,0 +1,304 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { addAction } from '@wordpress/hooks';
import type {
ProductResponseItem,
CartResponseItem,
StoreCart,
} from '@woocommerce/types';
/**
* Internal dependencies
*/
import { namespace, actionPrefix } from './constants';
import {
getProductFieldObject,
getProductImpressionObject,
trackEvent,
trackCheckoutStep,
trackCheckoutOption,
} from './utils';
/**
* Track customer progress through steps of the checkout. Triggers the event when the step changes:
* 1 - Contact information
* 2 - Shipping address
* 3 - Billing address
* 4 - Shipping options
* 5 - Payment options
*
* @summary Track checkout progress with begin_checkout and checkout_progress
* @see https://developers.google.com/analytics/devguides/collection/gtagjs/enhanced-ecommerce#1_measure_checkout_steps
*/
addAction(
`${ actionPrefix }-checkout-render-checkout-form`,
namespace,
trackCheckoutStep( 0 )
);
addAction(
`${ actionPrefix }-checkout-set-email-address`,
namespace,
trackCheckoutStep( 1 )
);
addAction(
`${ actionPrefix }-checkout-set-shipping-address`,
namespace,
trackCheckoutStep( 2 )
);
addAction(
`${ actionPrefix }-checkout-set-billing-address`,
namespace,
trackCheckoutStep( 3 )
);
addAction(
`${ actionPrefix }-checkout-set-phone-number`,
namespace,
( { step, ...rest }: { step: string; storeCart: StoreCart } ): void => {
trackCheckoutStep( step === 'shipping' ? 2 : 3 )( rest );
}
);
/**
* Choose a shipping rate
*
* @summary Track the shipping rate being set using set_checkout_option
* @see https://developers.google.com/analytics/devguides/collection/gtagjs/enhanced-ecommerce#2_measure_checkout_options
*/
addAction(
`${ actionPrefix }-checkout-set-selected-shipping-rate`,
namespace,
( { shippingRateId }: { shippingRateId: string } ): void => {
trackCheckoutOption( {
step: 4,
option: __( 'Shipping Method', 'woo-gutenberg-products-block' ),
value: shippingRateId,
} )();
}
);
/**
* Choose a payment method
*
* @summary Track the payment method being set using set_checkout_option
* @see https://developers.google.com/analytics/devguides/collection/gtagjs/enhanced-ecommerce#2_measure_checkout_options
*/
addAction(
`${ actionPrefix }-checkout-set-active-payment-method`,
namespace,
( { paymentMethodSlug }: { paymentMethodSlug: string } ): void => {
trackCheckoutOption( {
step: 5,
option: __( 'Payment Method', 'woo-gutenberg-products-block' ),
value: paymentMethodSlug,
} )();
}
);
/**
* Add Payment Information
*
* This event signifies a user has submitted their payment information. Note, this is used to indicate checkout
* submission, not `purchase` which is triggered on the thanks page.
*
* @summary Track the add_payment_info event
* @see https://developers.google.com/gtagjs/reference/ga4-events#add_payment_info
*/
addAction( `${ actionPrefix }-checkout-submit`, namespace, (): void => {
trackEvent( 'add_payment_info' );
} );
/**
* Add to cart.
*
* This event signifies that an item was added to a cart for purchase.
*
* @summary Track the add_to_cart event
* @see https://developers.google.com/gtagjs/reference/ga4-events#add_to_cart
*/
addAction(
`${ actionPrefix }-cart-add-item`,
namespace,
( {
product,
quantity = 1,
}: {
product: ProductResponseItem;
quantity: number;
} ): void => {
trackEvent( 'add_to_cart', {
event_category: 'ecommerce',
event_label: __( 'Add to Cart', 'woo-gutenberg-products-block' ),
items: [ getProductFieldObject( product, quantity ) ],
} );
}
);
/**
* Remove item from the cart
*
* @summary Track the remove_from_cart event
* @see https://developers.google.com/gtagjs/reference/ga4-events#remove_from_cart
*/
addAction(
`${ actionPrefix }-cart-remove-item`,
namespace,
( {
product,
quantity = 1,
}: {
product: CartResponseItem;
quantity: number;
} ): void => {
trackEvent( 'remove_from_cart', {
event_category: 'ecommerce',
event_label: __(
'Remove Cart Item',
'woo-gutenberg-products-block'
),
items: [ getProductFieldObject( product, quantity ) ],
} );
}
);
/**
* Change cart item quantities
*
* @summary Custom change_cart_quantity event.
*/
addAction(
`${ actionPrefix }-cart-set-item-quantity`,
namespace,
( {
product,
quantity = 1,
}: {
product: CartResponseItem;
quantity: number;
} ): void => {
trackEvent( 'change_cart_quantity', {
event_category: 'ecommerce',
event_label: __(
'Change Cart Item Quantity',
'woo-gutenberg-products-block'
),
items: [ getProductFieldObject( product, quantity ) ],
} );
}
);
/**
* Product List View
*
* @summary Track the view_item_list event
* @see https://developers.google.com/gtagjs/reference/ga4-events#view_item_list
*/
addAction(
`${ actionPrefix }-product-list-render`,
namespace,
( {
products,
listName = __( 'Product List', 'woo-gutenberg-products-block' ),
}: {
products: Array< ProductResponseItem >;
listName: string;
} ): void => {
if ( products.length === 0 ) {
return;
}
trackEvent( 'view_item_list', {
event_category: 'engagement',
event_label: __(
'Viewing products',
'woo-gutenberg-products-block'
),
items: products.map( ( product, index ) => ( {
...getProductImpressionObject( product, listName ),
list_position: index + 1,
} ) ),
} );
}
);
/**
* Product View Link Clicked
*
* @summary Track the select_content event
* @see https://developers.google.com/gtagjs/reference/ga4-events#select_content
*/
addAction(
`${ actionPrefix }-product-view-link`,
namespace,
( {
product,
listName,
}: {
product: ProductResponseItem;
listName: string;
} ): void => {
trackEvent( 'select_content', {
content_type: 'product',
items: [ getProductImpressionObject( product, listName ) ],
} );
}
);
/**
* Product Search
*
* @summary Track the search event
* @see https://developers.google.com/gtagjs/reference/ga4-events#search
*/
addAction(
`${ actionPrefix }-product-search`,
namespace,
( { searchTerm }: { searchTerm: string } ): void => {
trackEvent( 'search', {
search_term: searchTerm,
} );
}
);
/**
* Single Product View
*
* @summary Track the view_item event
* @see https://developers.google.com/gtagjs/reference/ga4-events#view_item
*/
addAction(
`${ actionPrefix }-product-render`,
namespace,
( {
product,
listName,
}: {
product: ProductResponseItem;
listName: string;
} ): void => {
if ( product ) {
trackEvent( 'view_item', {
items: [ getProductImpressionObject( product, listName ) ],
} );
}
}
);
/**
* Track notices as Exception events.
*
* @summary Track the exception event
* @see https://developers.google.com/analytics/devguides/collection/gtagjs/exceptions
*/
addAction(
`${ actionPrefix }-store-notice-create`,
namespace,
( { status, content }: { status: string; content: string } ): void => {
if ( status === 'error' ) {
trackEvent( 'exception', {
description: content,
fatal: false,
} );
}
}
);

View File

@ -0,0 +1,118 @@
/**
* External dependencies
*/
import type {
ProductResponseItem,
CartResponseItem,
StoreCart,
} from '@woocommerce/types';
interface ImpressionItem extends Gtag.Item {
list_name?: string;
}
/**
* Formats data into the productFieldObject shape.
*
* @see https://developers.google.com/analytics/devguides/collection/gtagjs/enhanced-ecommerce#product-data
*/
export const getProductFieldObject = (
product: ProductResponseItem | CartResponseItem,
quantity: number | undefined
): Gtag.Item => {
const productIdentifier = product.sku ? product.sku : '#' + product.id;
const productCategory =
'categories' in product && product.categories.length
? product.categories[ 0 ].name
: '';
return {
id: productIdentifier,
name: product.name,
quantity,
category: productCategory,
price: (
parseInt( product.prices.price, 10 ) /
10 ** product.prices.currency_minor_unit
).toString(),
};
};
/**
* Formats data into the impressionFieldObject shape.
*
* @see https://developers.google.com/analytics/devguides/collection/gtagjs/enhanced-ecommerce#impression-data
*/
export const getProductImpressionObject = (
product: ProductResponseItem,
listName: string
): ImpressionItem => {
const productIdentifier = product.sku ? product.sku : '#' + product.id;
const productCategory = product.categories.length
? product.categories[ 0 ].name
: '';
return {
id: productIdentifier,
name: product.name,
list_name: listName,
category: productCategory,
price: (
parseInt( product.prices.price, 10 ) /
10 ** product.prices.currency_minor_unit
).toString(),
};
};
/**
* Track an event using the global gtag function.
*/
export const trackEvent = (
eventName: Gtag.EventNames | string,
eventParams?: Gtag.ControlParams | Gtag.EventParams | Gtag.CustomParams
): void => {
if ( typeof gtag !== 'function' ) {
throw new Error( 'Function gtag not implemented.' );
}
// eslint-disable-next-line no-console
console.log( `Tracking event ${ eventName }` );
window.gtag( 'event', eventName, eventParams );
};
let currentStep = -1;
export const trackCheckoutStep = ( step: number ) => ( {
storeCart,
}: {
storeCart: StoreCart;
} ): void => {
if ( currentStep === step ) {
return;
}
trackEvent( step === 0 ? 'begin_checkout' : 'checkout_progress', {
items: storeCart.cartItems.map( getProductFieldObject ),
coupon: storeCart.cartCoupons[ 0 ]?.code || '',
currency: storeCart.cartTotals.currency_code,
value: (
parseInt( storeCart.cartTotals.total_price, 10 ) /
10 ** storeCart.cartTotals.currency_minor_unit
).toString(),
checkout_step: step,
} );
currentStep = step;
};
export const trackCheckoutOption = ( {
step,
option,
value,
}: {
step: number;
option: string;
value: string;
} ) => (): void => {
trackEvent( 'set_checkout_option', {
checkout_step: step,
checkout_option: option,
value,
} );
currentStep = step;
};