diff --git a/.github/workflows/lint-check-spa.yml b/.github/workflows/lint-check-spa.yml
index c4e31c619..8c8470e4f 100644
--- a/.github/workflows/lint-check-spa.yml
+++ b/.github/workflows/lint-check-spa.yml
@@ -38,10 +38,14 @@ jobs:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: ${{ runner.os }}-node-
+
+ - name: Setup Registry
+ run: printf "@newfold-labs:registry=https://npm.pkg.github.com/\n//npm.pkg.github.com/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc
+ if: steps.cache.outputs.cache-hit != 'true'
# Installs @wordpress/scripts for lint checks if it does not exist in the cache.
- name: Install dependencies
- run: npm i @wordpress/scripts
+ run: npm i @wordpress/scripts @newfold-labs/js-utility-ui-analytics
if: steps.cache.outputs.cache-hit != 'true'
# Gets the files changed wrt to trunk and filters out the js files.
diff --git a/includes/Data/Events.php b/includes/Data/Events.php
index 62a457d1c..a8796031d 100644
--- a/includes/Data/Events.php
+++ b/includes/Data/Events.php
@@ -2,29 +2,65 @@
namespace NewfoldLabs\WP\Module\Onboarding\Data;
/**
- * List of Onboarding events.
+ * Contains data related to Onboarding Hiive Events.
*/
final class Events {
+ /**
+ * The category of an event.
+ *
+ * @var string
+ */
+ protected static $category = 'wp-onboarding';
- /**
- * Contains a list of events with the key being the event slug.
- *
- * @var array
- */
- protected static $events = array(
- 'nfd-module-onboarding-event-pageview' => array(
- 'category' => 'Admin',
- 'action' => 'pageview',
- ),
+ /**
+ * List of valid actions that an event can perform.
+ *
+ * A value of true indicates that the action is valid, set it to null if you want to invalidate an action.
+ *
+ * @var array
+ */
+ protected static $valid_actions = array(
+ 'pageview' => true,
+ 'sidebar-opened' => true,
+ 'sidebar-closed' => true,
+ 'wp-experience' => true,
+ 'primary-type' => true,
+ 'secondary-type' => true,
+ 'tax-information' => true,
+ 'selected-style' => true,
+ 'default-style' => true,
+ 'customize-design' => true,
+ 'font-selection' => true,
+ 'theme-header' => true,
+ 'homepage-layout' => true,
+ 'top-priority' => true,
+ 'top-priority-skipped' => true,
+ 'exit-to-wordpress' => true,
+ 'products-info' => true,
+ 'yith-wonder/company-page-layout' => true,
+ 'yith-wonder/contact-us-layout' => true,
+ 'yith-wonder/blog-page-layout' => true,
+ 'yith-wonder/testimonials-page-layout' => true,
+ 'site-features' => true,
+ 'color-selection' => true,
+ 'color-selection-reset' => true,
);
/**
- * Retrieves the active theme color variations.
+ * Returns the list of valid actions that an event can perform
+ *
+ * @return array
+ */
+ public static function get_valid_actions() {
+ return self::$valid_actions;
+ }
+
+ /**
+ * Valid category of on event.
*
- * @param array $event_slug Event data.
- * @return array|boolean
+ * @return string
*/
- public static function get_event( $event_slug ) {
- return self::$events[ $event_slug ] ? self::$events[ $event_slug ] : false;
+ public static function get_category() {
+ return self::$category;
}
}
diff --git a/includes/RestApi/EventsController.php b/includes/RestApi/EventsController.php
index 03b31752f..c5cffb52b 100644
--- a/includes/RestApi/EventsController.php
+++ b/includes/RestApi/EventsController.php
@@ -3,31 +3,32 @@
use NewfoldLabs\WP\Module\Onboarding\Data\Events;
use NewfoldLabs\WP\Module\Onboarding\Permissions;
+use NewfoldLabs\WP\Module\Onboarding\Services\EventService;
/**
- * [Class EventsController]
+ * Controller to send analytics events.
*/
class EventsController extends \WP_REST_Controller {
/**
- * This is the REST API namespace that will be used for our custom API
+ * The namespace of the controller.
*
* @var string
*/
- protected $namespace = 'newfold-onboarding/v1';
+ protected $namespace = 'newfold-onboarding/v1';
- /**
- * This is the REST endpoint
- *
- * @var string
- */
- protected $rest_base = '/events';
+ /**
+ * The REST base endpoint.
+ *
+ * @var string
+ */
+ protected $rest_base = '/events';
- /**
- * Register REST routes for EventsController class.
- *
- * @return void
- */
+ /**
+ * Register routes that the controller will expose.
+ *
+ * @return void
+ */
public function register_routes() {
\register_rest_route(
$this->namespace,
@@ -35,68 +36,106 @@ public function register_routes() {
array(
array(
'methods' => \WP_REST_Server::CREATABLE,
- 'callback' => array( $this, 'send_event' ),
+ 'callback' => array( $this, 'send' ),
+ 'permission_callback' => array( Permissions::class, 'rest_is_authorized_admin' ),
+ 'args' => $this->get_send_args(),
+ ),
+ )
+ );
+
+ \register_rest_route(
+ $this->namespace,
+ $this->rest_base . '/batch',
+ array(
+ array(
+ 'methods' => \WP_REST_Server::CREATABLE,
+ 'callback' => array( $this, 'send_batch' ),
'permission_callback' => array( Permissions::class, 'rest_is_authorized_admin' ),
- 'args' => $this->get_send_event_args(),
),
)
);
}
- /**
- * Get args for the send_event endpoint.
- *
- * @return array
- */
- public function get_send_event_args() {
- return array(
- 'slug' => array(
- 'required' => true,
- 'type' => 'string',
- 'sanitize_callback' => 'sanitize_text_field',
- ),
- 'data' => array(
- 'type' => 'object',
- ),
- );
+ /**
+ * Args for a single event.
+ *
+ * @return array
+ */
+ public function get_send_args() {
+ return array(
+ 'action' => array(
+ 'required' => true,
+ 'description' => __( 'Event action', 'wp-module-onboarding' ),
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_title',
+ 'validate_callback' => array( EventService::class, 'validate_action' ),
+ ),
+ 'category' => array(
+ 'default' => Events::get_category(),
+ 'description' => __( 'Event category', 'wp-module-onboarding' ),
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_title',
+ 'validate_callback' => array( EventService::class, 'validate_category' ),
+ ),
+ 'data' => array(
+ 'description' => __( 'Event data', 'wp-module-onboarding' ),
+ 'type' => 'object',
+ ),
+ );
+ }
+
+ /**
+ * Sends a Hiive Event to the data module API.
+ *
+ * @param \WP_REST_Request $request The incoming request object.
+ * @return \WP_REST_Response|\WP_Error
+ */
+ public function send( \WP_REST_Request $request ) {
+ return EventService::send( $request->get_params() );
}
- /**
- * Send events to the data module events API.
- *
- * @param \WP_REST_Request $request Request model.
- *
- * @return \WP_REST_Response|\WP_Error
- */
- public function send_event( \WP_REST_Request $request ) {
- $event = Events::get_event( $request->get_param( 'slug' ) );
- if ( ! $event ) {
+ /**
+ * Sends an array of Hiive Events to the data module API programmatically.
+ *
+ * @param \WP_REST_Request $request The incoming request object.
+ * @return \WP_REST_Response|\WP_Error
+ */
+ public function send_batch( \WP_REST_Request $request ) {
+ $events = $request->get_json_params();
+ if ( ! rest_is_array( $events ) ) {
return new \WP_Error(
- 'event-error',
- 'No such event found',
- array( 'status' => 404 )
+ 'nfd_module_onboarding_error',
+ __( 'Request does not contain an array of events.', 'wp-module-onboarding' )
);
}
- $event['data'] = $request->get_param( 'data' );
-
- if ( ! empty( $event['data'] ) && ! empty( $event['data']['stepID'] ) ) {
- $event['data']['page'] = \admin_url( '/index.php?page=nfd-onboarding#' . $event['data']['stepID'] );
+ $response_errors = array();
+ foreach ( $events as $index => $event ) {
+ $response = EventService::send( $event );
+ if ( is_wp_error( $response ) ) {
+ array_push(
+ $response_errors,
+ array(
+ 'index' => $index,
+ 'data' => $response,
+ )
+ );
+ }
}
- $event_data_request = new \WP_REST_Request(
- \WP_REST_Server::CREATABLE,
- NFD_MODULE_DATA_EVENTS_API
- );
- $event_data_request->set_body_params( $event );
- $response = \rest_do_request( $event_data_request );
- if ( $response->is_error() ) {
- return $response->as_error();
+ if ( ! empty( $response_errors ) ) {
+ return new \WP_Error(
+ 'nfd_module_onboarding_error',
+ __( 'Some events failed.', 'wp-module-onboarding' ),
+ array(
+ 'data' => $response_errors,
+ )
+ );
}
return new \WP_REST_Response(
- $response,
- $response->status
+ array(),
+ 202
);
}
}
diff --git a/includes/Services/EventService.php b/includes/Services/EventService.php
new file mode 100644
index 000000000..d8b215677
--- /dev/null
+++ b/includes/Services/EventService.php
@@ -0,0 +1,83 @@
+set_body_params( $event );
+
+ $response = rest_do_request( $event_data_request );
+ if ( $response->is_error() ) {
+ return $response->as_error();
+ }
+
+ return $response;
+ }
+
+ /**
+ * Validates the category of an event.
+ *
+ * @param string $category The category of an event.
+ * @return boolean
+ */
+ public static function validate_category( $category ) {
+ return Events::get_category() === $category;
+ }
+
+ /**
+ * Validates the action performed in an event.
+ *
+ * @param string $action The action performed in an event.
+ * @return boolean
+ */
+ public static function validate_action( $action ) {
+ $valid_actions = Events::get_valid_actions();
+ if ( ! isset( $valid_actions[ $action ] ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Sanitizes and validates the action and category parameters of an event.
+ *
+ * @param array $event The event to sanitize and validate.
+ * @return array|boolean
+ */
+ public static function validate( $event ) {
+ if ( ! isset( $event['action'] ) || ! self::validate_action( $event['action'] ) ) {
+ return false;
+ }
+
+ if ( ! isset( $event['category'] ) || ! self::validate_category( $event['category'] ) ) {
+ return false;
+ }
+
+ return $event;
+ }
+}
diff --git a/package.json b/package.json
index 9ca986950..e72aac706 100644
--- a/package.json
+++ b/package.json
@@ -29,6 +29,7 @@
"test:unit": "npx wp-env run phpunit 'phpunit -c /var/www/html/wp-content/plugins//phpunit.xml --verbose'"
},
"dependencies": {
+ "@newfold-labs/js-utility-ui-analytics": "1.0.0",
"@wordpress/interface": "^5.10.0",
"@wordpress/style-engine": "^0.11.0",
"classnames": "^2.3.1",
diff --git a/src/OnboardingSPA/components/App/index.js b/src/OnboardingSPA/components/App/index.js
index 73faaa137..79aef8539 100644
--- a/src/OnboardingSPA/components/App/index.js
+++ b/src/OnboardingSPA/components/App/index.js
@@ -19,6 +19,8 @@ import { useEffect, Fragment, useState } from '@wordpress/element';
import { FullscreenMode } from '@wordpress/interface';
import { API_REQUEST } from '../../../constants';
import NewfoldInterfaceSkeleton from '../NewfoldInterfaceSkeleton';
+import { HiiveAnalytics } from '@newfold-labs/js-utility-ui-analytics';
+import { trackHiiveEvent } from '../../utils/analytics';
/**
* Primary app that renders the .
@@ -139,6 +141,7 @@ const App = () => {
setIsRequestPlaced( false );
}
}
+
// Check if the Basic Info page was visited
if ( location?.pathname.includes( 'basic-info' ) ) {
setDidVisitBasicInfo( true );
@@ -223,12 +226,57 @@ const App = () => {
}
}
+ const handlePreviousStepTracking = () => {
+ const previousStep = window.nfdOnboarding?.previousStepID;
+ if ( typeof previousStep !== 'string' ) {
+ window.nfdOnboarding.previousStepID = location.pathname;
+ HiiveAnalytics.dispatchEvents();
+ return;
+ }
+
+ if ( previousStep.includes( 'products' ) ) {
+ trackHiiveEvent( 'products-info', {
+ productCount:
+ currentData.storeDetails.productInfo.product_count,
+ productTypes:
+ currentData.storeDetails.productInfo.product_types.join(
+ ','
+ ),
+ } );
+ }
+
+ if ( previousStep.includes( 'site-pages' ) ) {
+ currentData.data.sitePages?.other?.forEach( ( sitePage ) => {
+ trackHiiveEvent( `${ sitePage.slug }-layout`, sitePage.slug );
+ } );
+ }
+
+ if ( previousStep.includes( 'site-features' ) ) {
+ const siteFeatures = currentData.data?.siteFeatures;
+ if ( siteFeatures ) {
+ const siteFeaturesArray = Object.keys( siteFeatures ).filter(
+ ( key ) => {
+ return siteFeatures[ key ] !== false;
+ }
+ );
+ trackHiiveEvent(
+ 'site-features',
+ siteFeaturesArray.join( ',' )
+ );
+ }
+ }
+
+ window.nfdOnboarding.previousStepID = location.pathname;
+ HiiveAnalytics.dispatchEvents();
+ };
+
useEffect( () => {
document.body.classList.add( `nfd-brand-${ newfoldBrand }` );
}, [ newfoldBrand ] );
useEffect( () => {
syncStoreToDB();
+ handlePreviousStepTracking();
handleColorsAndTypographyRoutes();
if ( location.pathname.includes( '/step' ) ) {
setActiveFlow( onboardingFlow );
diff --git a/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignColors.js b/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignColors.js
index fa542bdea..a2de97be9 100644
--- a/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignColors.js
+++ b/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignColors.js
@@ -8,6 +8,7 @@ import { getGlobalStyles, getThemeColors } from '../../../utils/api/themes';
import { useGlobalStylesOutput } from '../../../utils/global-styles/use-global-styles-output';
import { THEME_STATUS_ACTIVE, THEME_STATUS_INIT } from '../../../../constants';
import Animate from '../../Animate';
+import { trackHiiveEvent } from '../../../utils/analytics';
const DesignColors = () => {
const customColorsResetRef = useRef( null );
@@ -84,9 +85,6 @@ const DesignColors = () => {
selectedColorsLocalTemp = selectedColors,
globalStylesTemp = storedPreviewSettings
) {
- if ( selectedColors?.slug === colorStyle ) {
- return true;
- }
const isCustomStyle = colorStyle === 'custom';
const selectedGlobalStyle = globalStylesTemp;
const selectedThemeColorPalette =
@@ -102,7 +100,7 @@ const DesignColors = () => {
selectedThemeColorPalette[ idx ].color =
selectedColorsLocalTemp[ slug ];
} else if (
- // Add Exception for Background.(perhaps scope to yith-wonder in future)
+ // Add Exception for Background. (perhaps scope to yith-wonder in future)
colorPalettesTemp?.[ colorStyle ]?.[ slug ] &&
'base' === slug
) {
@@ -240,6 +238,9 @@ const DesignColors = () => {
}, [ isLoaded, themeStatus ] );
const handleClick = ( colorStyle ) => {
+ if ( selectedColors?.slug === colorStyle ) {
+ return true;
+ }
const customColorsTemp = customColors;
for ( const custom in customColorsTemp ) {
customColorsTemp[ custom ] = '';
@@ -249,6 +250,7 @@ const DesignColors = () => {
saveThemeColorPalette( colorStyle );
setSelectedColorsLocal( colorPalettes[ colorStyle ] );
LocalToState( colorPalettes[ colorStyle ], colorStyle );
+ trackHiiveEvent( 'color-selection', colorStyle );
};
const changeCustomPickerColor = async ( color ) => {
@@ -267,6 +269,9 @@ const DesignColors = () => {
saveCustomColors();
LocalToState( selectedColorsLocalCopy, 'custom' );
setSelectedColorsLocal( selectedColorsLocalCopy );
+ if ( ! isCustomColorActive() ) {
+ trackHiiveEvent( 'color-selection', 'custom' );
+ }
setCustomColors( selectedColorsLocalCopy );
};
@@ -305,6 +310,7 @@ const DesignColors = () => {
setSelectedColors( selectedColors );
setCurrentOnboardingData( currentData );
+ trackHiiveEvent( 'color-selection-reset', selectedGlobalStyle.title );
}
function buildPalettes() {
diff --git a/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignHeaderMenu.js b/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignHeaderMenu.js
index ba020515a..4b455404a 100644
--- a/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignHeaderMenu.js
+++ b/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignHeaderMenu.js
@@ -10,6 +10,7 @@ import {
import { setFlow } from '../../../utils/api/flow';
import { THEME_STATUS_ACTIVE, THEME_STATUS_INIT } from '../../../../constants';
+import { trackHiiveEvent } from '../../../utils/analytics';
const DesignHeaderMenu = () => {
const headerMenuSlugs = [
@@ -122,6 +123,7 @@ const DesignHeaderMenu = () => {
if ( result?.error === null ) {
setCurrentOnboardingData( currentData );
}
+ trackHiiveEvent( 'theme-header', chosenPattern.slug );
};
const buildPreviews = () => {
diff --git a/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignThemeStylesPreview.js b/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignThemeStylesPreview.js
index 580d3abc4..9ee64490a 100644
--- a/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignThemeStylesPreview.js
+++ b/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignThemeStylesPreview.js
@@ -10,6 +10,7 @@ import {
LivePreviewSelectableCard,
LivePreviewSkeleton,
} from '../../LivePreview';
+import { trackHiiveEvent } from '../../../utils/analytics';
const DesignThemeStylesPreview = () => {
const [ pattern, setPattern ] = useState();
@@ -106,6 +107,7 @@ const DesignThemeStylesPreview = () => {
setSelectedStyle( selectedGlobalStyle.title );
currentData.data.theme.variation = selectedGlobalStyle.title;
setCurrentOnboardingData( currentData );
+ trackHiiveEvent( 'selected-style', selectedGlobalStyle.title );
};
const buildPreviews = () => {
diff --git a/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignTypography.js b/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignTypography.js
index 01cf6889a..7b049e778 100644
--- a/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignTypography.js
+++ b/src/OnboardingSPA/components/Drawer/DrawerPanel/DesignTypography.js
@@ -6,6 +6,7 @@ import { store as nfdOnboardingStore } from '../../../store';
import { getThemeFonts } from '../../../utils/api/themes';
import { useGlobalStylesOutput } from '../../../utils/global-styles/use-global-styles-output';
import { THEME_STATUS_ACTIVE, THEME_STATUS_INIT } from '../../../../constants';
+import { trackHiiveEvent } from '../../../utils/analytics';
const DesignTypography = () => {
const drawerFontOptions = useRef();
@@ -57,16 +58,17 @@ const DesignTypography = () => {
fontPalettes !== undefined
) {
setSelectedFont( currentData?.data?.typography?.slug );
- handleClick( currentData?.data?.typography?.slug );
+ handleClick( currentData?.data?.typography?.slug, 'flow' );
}
}, [ fontPalettes, storedPreviewSettings ] );
useEffect( () => {
- if ( ! isLoaded && THEME_STATUS_ACTIVE === themeStatus )
+ if ( ! isLoaded && THEME_STATUS_ACTIVE === themeStatus ) {
getFontStylesAndPatterns();
+ }
}, [ isLoaded, themeStatus ] );
- const handleClick = async ( fontStyle ) => {
+ const handleClick = async ( fontStyle, context = 'click' ) => {
if ( selectedFont === fontStyle ) {
return true;
}
@@ -124,12 +126,17 @@ const DesignTypography = () => {
useGlobalStylesOutput( globalStylesCopy, storedPreviewSettings )
);
setCurrentOnboardingData( currentData );
+ if ( 'click' === context ) {
+ trackHiiveEvent( 'font-selection', fontStyle );
+ }
};
function buildPalettes() {
return Object.keys( fontPalettes ).map( ( fontStyle, idx ) => {
const splitLabel = fontPalettes[ fontStyle ]?.label.split( '&', 2 );
- if ( splitLabel.length === 0 ) return null;
+ if ( splitLabel.length === 0 ) {
+ return null;
+ }
return (
{
+} ) => {
const location = useLocation();
- const mainContainer = document.querySelector('.nfd-onboard-content');
+ const mainContainer = document.querySelector( '.nfd-onboard-content' );
- const speakRouteTitle = (
- location,
- title = 'Showing new Onboarding Page'
- ) => {
+ const speakRouteTitle = ( title = 'Showing new Onboarding Page' ) => {
// [TODO]: Determine if some routes should not speak the title
- speak(title, 'assertive');
+ speak( title, 'assertive' );
};
- useEffect(() => {
- mainContainer?.focus({ preventScroll: true });
- speakRouteTitle(location, 'Override');
- new Event(`${NFD_ONBOARDING_EVENT_PREFIX}-pageview`, {
- stepID: location.pathname,
- previousStepID: window.nfdOnboarding.previousStepID
- }).send();
- window.nfdOnboarding.previousStepID = location.pathname
- }, [location.pathname]);
+ useEffect( () => {
+ mainContainer?.focus( { preventScroll: true } );
+ speakRouteTitle( 'Override' );
+ trackHiiveEvent( 'pageview', window.location.href );
+ }, [ location.pathname ] );
return (
-
- {children}
+
+ { children }
);
};
diff --git a/src/OnboardingSPA/components/Sidebar/components/LearnMore/Menu.js b/src/OnboardingSPA/components/Sidebar/components/LearnMore/Menu.js
index 355a41cc1..7da4ba233 100644
--- a/src/OnboardingSPA/components/Sidebar/components/LearnMore/Menu.js
+++ b/src/OnboardingSPA/components/Sidebar/components/LearnMore/Menu.js
@@ -8,6 +8,7 @@ import {
SIDEBAR_MENU_SLOTFILL_PREFIX,
} from '../../../../../constants';
import classNames from 'classnames';
+import { trackHiiveEvent } from '../../../../utils/analytics';
const LearnMoreMenu = () => {
const { isSidebarOpened, sideBarView, currentStep } = useSelect(
@@ -23,12 +24,16 @@ const LearnMoreMenu = () => {
const { setIsSidebarOpened, setSidebarActiveView } =
useDispatch( nfdOnboardingStore );
const toggleSidebar = () => {
- setSidebarActiveView( SIDEBAR_LEARN_MORE );
- setIsSidebarOpened(
+ const isSidebarOpenedNew =
sideBarView === SIDEBAR_LEARN_MORE
? ! isSidebarOpened
- : isSidebarOpened
+ : isSidebarOpened;
+ trackHiiveEvent(
+ isSidebarOpenedNew ? 'sidebar-opened' : 'sidebar-closed',
+ window.location.href
);
+ setSidebarActiveView( SIDEBAR_LEARN_MORE );
+ setIsSidebarOpened( isSidebarOpenedNew );
};
return (
diff --git a/src/OnboardingSPA/components/Sidebar/components/LearnMore/Sidebar.js b/src/OnboardingSPA/components/Sidebar/components/LearnMore/Sidebar.js
index 0d3055c4f..d6bf8ecef 100644
--- a/src/OnboardingSPA/components/Sidebar/components/LearnMore/Sidebar.js
+++ b/src/OnboardingSPA/components/Sidebar/components/LearnMore/Sidebar.js
@@ -10,6 +10,7 @@ import {
SIDEBAR_SLOTFILL_PREFIX,
} from '../../../../../constants';
import SidebarSkeleton from './Skeleton/SidebarSkeleton';
+import { trackHiiveEvent } from '../../../../utils/analytics';
const LearnMoreSidebar = () => {
const { currentStep } = useSelect( ( select ) => {
@@ -22,6 +23,7 @@ const LearnMoreSidebar = () => {
const closeSideBar = () => {
setIsSidebarOpened( false );
+ trackHiiveEvent( 'sidebar-closed', window.location.href );
};
return (
diff --git a/src/OnboardingSPA/components/SkipButton/index.js b/src/OnboardingSPA/components/SkipButton/index.js
index d47cb3636..a68159a2a 100644
--- a/src/OnboardingSPA/components/SkipButton/index.js
+++ b/src/OnboardingSPA/components/SkipButton/index.js
@@ -8,6 +8,7 @@ import { setFlow } from '../../utils/api/flow';
import { store as nfdOnboardingStore } from '../../store';
import { getSettings, setSettings } from '../../utils/api/settings';
import { wpAdminPage, pluginDashboardPage } from '../../../constants';
+import { HiiveAnalytics } from '@newfold-labs/js-utility-ui-analytics';
const SkipButton = ( { callback = false } ) => {
const navigate = useNavigate();
@@ -45,6 +46,7 @@ const SkipButton = ( { callback = false } ) => {
if ( socialDataResp ) {
setOnboardingSocialData( socialDataResp );
}
+ await HiiveAnalytics.dispatchEvents();
}
setFlow( currentData );
}
@@ -56,6 +58,13 @@ const SkipButton = ( { callback = false } ) => {
window.location.replace( exitLink );
}
+ function skip() {
+ if ( typeof callback === 'function' ) {
+ callback();
+ }
+ navigate( nextStep.path );
+ }
+
function skipStep() {
if ( isLastStep ) {
return (
@@ -68,15 +77,7 @@ const SkipButton = ( { callback = false } ) => {
);
}
return (
-
diff --git a/src/OnboardingSPA/pages/Steps/TopPriority/index.js b/src/OnboardingSPA/pages/Steps/TopPriority/index.js
index ffeb3ce32..06fdb23ea 100644
--- a/src/OnboardingSPA/pages/Steps/TopPriority/index.js
+++ b/src/OnboardingSPA/pages/Steps/TopPriority/index.js
@@ -10,6 +10,7 @@ import CommonLayout from '../../../components/Layouts/Common';
import HeadingWithSubHeading from '../../../components/HeadingWithSubHeading';
import SelectableCardList from '../../../components/SelectableCardList/selectable-card-list';
import getContents from './contents';
+import { trackHiiveEvent } from '../../../utils/analytics';
const StepTopPriority = () => {
const priorityTypes = {
@@ -83,6 +84,7 @@ const StepTopPriority = () => {
const selectedPriorityType = priorityTypes[ selected ];
currentData.data.topPriority.priority1 = selectedPriorityType;
setCurrentOnboardingData( currentData );
+ trackHiiveEvent( 'top-priority', priorityTypes[ selected ] );
if ( 'selling' === selectedPriorityType ) {
handleSelling();
} else {
@@ -94,6 +96,10 @@ const StepTopPriority = () => {
window.nfdOnboarding.newFlow = undefined;
currentData.data.topPriority.priority1 = priorityTypes[ 0 ];
setCurrentOnboardingData( currentData );
+ trackHiiveEvent(
+ 'top-priority-skipped',
+ priorityTypes[ 0 ]
+ );
};
const content = getContents();
diff --git a/src/OnboardingSPA/utils/analytics/index.js b/src/OnboardingSPA/utils/analytics/index.js
new file mode 100644
index 000000000..58fd001d8
--- /dev/null
+++ b/src/OnboardingSPA/utils/analytics/index.js
@@ -0,0 +1,11 @@
+import { HiiveAnalytics, HiiveEvent } from '@newfold-labs/js-utility-ui-analytics';
+import { HIIVE_ANALYTICS_CATEGORY } from '../../../constants';
+
+export const trackHiiveEvent = ( action, value ) => {
+ const hiiveEvent = new HiiveEvent( HIIVE_ANALYTICS_CATEGORY, action, {
+ value,
+ timestamp: Date.now(),
+ } );
+
+ HiiveAnalytics.track( hiiveEvent );
+};
diff --git a/src/OnboardingSPA/utils/api/events.js b/src/OnboardingSPA/utils/api/events.js
deleted file mode 100644
index b4b40cec2..000000000
--- a/src/OnboardingSPA/utils/api/events.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import apiFetch from '@wordpress/api-fetch';
-
-import { onboardingRestURL } from './common';
-
-class Event {
- constructor( eventSlug, eventData = {} ) {
- this.eventSlug = eventSlug;
- this.eventData = eventData;
- }
-
- send() {
- apiFetch( {
- url: onboardingRestURL( 'events' ),
- method: 'POST',
- data: {
- slug: this.eventSlug,
- data: this.eventData,
- },
- } ).catch( ( error ) => {
- console.error( error );
- } );
- }
-}
-
-export default Event;
diff --git a/src/constants.js b/src/constants.js
index eed2f4c2b..75a0432b9 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -51,6 +51,7 @@ export const PLUGIN_STATUS_NOT_ACTIVE = 'inactive';
export const PLUGIN_STATUS_INSTALLING = 'installing';
export const PLUGIN_STATUS_ACTIVE = 'activated';
export const PLUGIN_INSTALL_WAIT_TIMEOUT = 30000;
+export const HIIVE_ANALYTICS_CATEGORY = 'wp-onboarding';
/**
* All views for the
component.
diff --git a/src/onboarding.js b/src/onboarding.js
index 8a78591fe..0f54397e6 100644
--- a/src/onboarding.js
+++ b/src/onboarding.js
@@ -5,9 +5,23 @@ import { NFD_ONBOARDING_ELEMENT_ID, runtimeDataExists } from './constants';
import domReady from '@wordpress/dom-ready';
import { registerCoreBlocks } from '@wordpress/block-library';
import initializeNFDOnboarding from './OnboardingSPA';
+import { HiiveAnalytics } from '@newfold-labs/js-utility-ui-analytics';
+import { onboardingRestURL } from './OnboardingSPA/utils/api/common';
if ( runtimeDataExists ) {
domReady( () => {
+ HiiveAnalytics.initialize( {
+ urls: {
+ single: onboardingRestURL( 'events' ),
+ batch: onboardingRestURL( 'events/batch' ),
+ },
+ settings: {
+ debounce: {
+ time: 3000,
+ },
+ },
+ } );
+
initializeNFDOnboarding(
NFD_ONBOARDING_ELEMENT_ID,
window.nfdOnboarding
@@ -15,6 +29,7 @@ if ( runtimeDataExists ) {
registerCoreBlocks();
} );
} else {
+ /* eslint-disable no-console */
console.log(
'Cannot find Newfold Onboarding runtime data to set __webpack_public_path__.'
);