diff --git a/includes/RestApi/EventsController.php b/includes/RestApi/EventsController.php
index c5cffb52b..7f89ef5da 100644
--- a/includes/RestApi/EventsController.php
+++ b/includes/RestApi/EventsController.php
@@ -71,7 +71,7 @@ public function get_send_args() {
'validate_callback' => array( EventService::class, 'validate_action' ),
),
'category' => array(
- 'default' => Events::get_category(),
+ 'default' => Events::get_category()[0],
'description' => __( 'Event category', 'wp-module-onboarding' ),
'type' => 'string',
'sanitize_callback' => 'sanitize_title',
diff --git a/includes/Services/EventService.php b/includes/Services/EventService.php
index d8b215677..c91c27d8f 100644
--- a/includes/Services/EventService.php
+++ b/includes/Services/EventService.php
@@ -45,7 +45,13 @@ public static function send( $event ) {
* @return boolean
*/
public static function validate_category( $category ) {
- return Events::get_category() === $category;
+ $default_categories = Events::get_category();
+ foreach ( $default_categories as $event_category ) {
+ if ( $event_category === $category ) {
+ return true;
+ }
+ }
+ return false;
}
/**
diff --git a/src/OnboardingSPA/components/StartOptions/contents.js b/src/OnboardingSPA/components/StartOptions/contents.js
new file mode 100644
index 000000000..28a4b8916
--- /dev/null
+++ b/src/OnboardingSPA/components/StartOptions/contents.js
@@ -0,0 +1,9 @@
+import { __ } from '@wordpress/i18n';
+
+const getContents = () => {
+ return {
+ badge: __( 'Fastest', 'wp-module-onboarding' ),
+ };
+};
+
+export default getContents;
diff --git a/src/OnboardingSPA/components/StartOptions/index.js b/src/OnboardingSPA/components/StartOptions/index.js
index 3d400e248..7c1a5118d 100644
--- a/src/OnboardingSPA/components/StartOptions/index.js
+++ b/src/OnboardingSPA/components/StartOptions/index.js
@@ -1,18 +1,34 @@
-import { SITEGEN_FLOW } from '../../data/flows/constants';
-import { resolveGetDataForFlow } from '../../data/flows';
+// WordPress
import { useSelect, useDispatch } from '@wordpress/data';
-import { validateFlow } from '../../data/flows/utils';
+import { memo, useEffect, useState } from '@wordpress/element';
+
+// Classes and functions
import { useNavigate } from 'react-router-dom';
-import { memo } from '@wordpress/element';
-import { store as nfdOnboardingStore } from '../../store';
+import { validateFlow } from '../../data/flows/utils';
+import { resolveGetDataForFlow } from '../../data/flows';
+
+// Misc
import {
OnboardingEvent,
trackOnboardingEvent,
} from '../../utils/analytics/hiive';
+import { SITEGEN_FLOW } from '../../data/flows/constants';
+import { store as nfdOnboardingStore } from '../../store';
import { ACTION_SITEGEN_FORK_OPTION_SELECTED } from '../../utils/analytics/hiive/constants';
+import getContents from './contents';
-const StartOptions = ( { questionnaire, oldFlow, options } ) => {
+const StartOptions = ( {
+ experimentVersion,
+ questionnaire,
+ oldFlow,
+ options,
+} ) => {
+ const content = getContents();
const navigate = useNavigate();
+ const [ forkOptions, setForkOptions ] = useState( [] );
+ const [ showAIRecommendedBadge, setShowAIRecommendedBadge ] =
+ useState( false );
+
const { brandConfig, hireProUrl, currentData } = useSelect( ( select ) => {
return {
brandConfig: select( nfdOnboardingStore ).getNewfoldBrandConfig(),
@@ -31,6 +47,25 @@ const StartOptions = ( { questionnaire, oldFlow, options } ) => {
setCurrentOnboardingData,
} = useDispatch( nfdOnboardingStore );
+ useEffect( () => {
+ if (
+ experimentVersion &&
+ ( experimentVersion === 2 || experimentVersion === 4 )
+ ) {
+ // Swap the DIY flow with the AI Flow
+ [ options[ 0 ], options[ 1 ] ] = [ options[ 1 ], options[ 0 ] ];
+ }
+
+ if (
+ experimentVersion &&
+ ( experimentVersion === 3 || experimentVersion === 4 )
+ ) {
+ // Show a Badge in the AI Option
+ setShowAIRecommendedBadge( true );
+ }
+ setForkOptions( options );
+ }, [ experimentVersion ] );
+
const switchFlow = ( newFlow ) => {
if ( ! validateFlow( brandConfig, newFlow ) ) {
return false;
@@ -81,51 +116,67 @@ const StartOptions = ( { questionnaire, oldFlow, options } ) => {
);
}
};
+
return (
-
-
- { questionnaire }
-
-
- { options.map( ( tab, idx ) => {
- if (
- tab.flow === SITEGEN_FLOW &&
- ! validateFlow( brandConfig, tab.flow )
- ) {
- // Do not show the Sitegen AI option if not enabled for the customer
- return false;
- }
- return (
-
{
- selectFlow( tab.flow );
- } }
- onKeyDown={ () => {
- {
- selectFlow( tab.flow );
+ experimentVersion &&
+ forkOptions && (
+
+
+ { questionnaire }
+
+
+ { forkOptions.map( ( tab, idx ) => {
+ if (
+ tab.flow === SITEGEN_FLOW &&
+ ! validateFlow( brandConfig, tab.flow )
+ ) {
+ // Do not show the Sitegen AI option if not enabled for the customer
+ return false;
+ }
+ return (
+
-
- { tab.span && (
-
- { tab.span }
-
- ) }
- { tab.title }
-
-
- { tab.subtitle }
-
-
- );
- } ) }
+ key={ idx }
+ role="button"
+ tabIndex={ 0 }
+ onClick={ () => {
+ selectFlow( tab.flow );
+ } }
+ onKeyDown={ () => {
+ {
+ selectFlow( tab.flow );
+ }
+ } }
+ >
+ { tab.flow === SITEGEN_FLOW &&
+ showAIRecommendedBadge && (
+
+ { content.badge }
+
+ ) }
+
+ { tab.span && (
+
+ { tab.span }
+
+ ) }
+ { tab.title }
+
+
+ { tab.subtitle }
+
+
+ );
+ } ) }
+
-
+ )
);
};
diff --git a/src/OnboardingSPA/components/StartOptions/stylesheet.scss b/src/OnboardingSPA/components/StartOptions/stylesheet.scss
index b57c58d58..021bde287 100644
--- a/src/OnboardingSPA/components/StartOptions/stylesheet.scss
+++ b/src/OnboardingSPA/components/StartOptions/stylesheet.scss
@@ -23,6 +23,7 @@
&__options {
flex: 1;
+ position: relative;
min-width: 310px;
height: 130px;
border: 1px solid #9ca2a7;
@@ -58,6 +59,16 @@
padding-top: 3px;
padding-bottom: 2px;
}
+
+ &--badge {
+ top: -12px;
+ font-size: 16px;
+ padding: 8px 12px;
+ border-radius: 4px;
+ position: absolute;
+ background: linear-gradient(0deg, #f36, #f36);
+
+ }
}
&__options:hover {
diff --git a/src/OnboardingSPA/steps/TheFork/contents.js b/src/OnboardingSPA/steps/TheFork/contents.js
index fd39793ff..38f301ca6 100644
--- a/src/OnboardingSPA/steps/TheFork/contents.js
+++ b/src/OnboardingSPA/steps/TheFork/contents.js
@@ -12,7 +12,7 @@ const getContents = () => {
{
title: __( 'Guided Configuration', 'wp-module-onboarding' ),
subtitle: __(
- 'A few questions & settings to get you a jumpstart.',
+ 'Robust configuration guide to help you build your site',
'wp-module-onboarding'
),
flow: 'sitebuild',
diff --git a/src/OnboardingSPA/steps/TheFork/index.js b/src/OnboardingSPA/steps/TheFork/index.js
index 1bb4cf42b..2133c0ed0 100644
--- a/src/OnboardingSPA/steps/TheFork/index.js
+++ b/src/OnboardingSPA/steps/TheFork/index.js
@@ -1,29 +1,41 @@
-import CommonLayout from '../../components/Layouts/Common';
-
-import { useEffect } from '@wordpress/element';
+// WordPress
+import { useEffect, useState } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
-import { store as nfdOnboardingStore } from '../../store';
+// Classes and functions
+import getContents from './contents';
+import { setFlow } from '../../utils/api/flow';
+
+// Components
+import StartOptions from '../../components/StartOptions';
+import CommonLayout from '../../components/Layouts/Common';
+import HeadingWithSubHeading from '../../components/HeadingWithSubHeading/SiteGen/index';
+
+// Misc
import {
FOOTER_SITEGEN,
HEADER_SITEGEN,
pluginDashboardPage,
} from '../../../constants';
-
-import { DEFAULT_FLOW } from '../../data/flows/constants';
-import HeadingWithSubHeading from '../../components/HeadingWithSubHeading/SiteGen/index';
-import StartOptions from '../../components/StartOptions';
-import getContents from './contents';
import {
OnboardingEvent,
sendOnboardingEvent,
trackOnboardingEvent,
} from '../../utils/analytics/hiive';
-import { ACTION_SITEGEN_FORK_OPTION_SELECTED } from '../../utils/analytics/hiive/constants';
+import {
+ ACTION_SITEGEN_FORK_AI_EXPERIMENT,
+ ACTION_SITEGEN_FORK_OPTION_SELECTED,
+ CATEGORY_EXPERIMENT,
+} from '../../utils/analytics/hiive/constants';
+import { store as nfdOnboardingStore } from '../../store';
+import { DEFAULT_FLOW } from '../../data/flows/constants';
const TheFork = () => {
- const { migrationUrl } = useSelect( ( select ) => {
+ const [ experimentVersion, setExperimentVersion ] = useState();
+ const { currentData, migrationUrl } = useSelect( ( select ) => {
return {
+ currentData:
+ select( nfdOnboardingStore ).getCurrentOnboardingData(),
migrationUrl: select( nfdOnboardingStore ).getMigrationUrl(),
};
} );
@@ -36,6 +48,7 @@ const TheFork = () => {
setIsHeaderNavigationEnabled,
setFooterActiveView,
setHideFooterNav,
+ setCurrentOnboardingData,
} = useDispatch( nfdOnboardingStore );
useEffect( () => {
@@ -46,8 +59,48 @@ const TheFork = () => {
setHeaderActiveView( HEADER_SITEGEN );
setDrawerActiveView( false );
setFooterActiveView( FOOTER_SITEGEN );
+ handleExperimentVersion();
} );
+ const handleExperimentVersion = async () => {
+ let theForkExperimentVersion = 0;
+ if ( currentData.sitegen.theForkExperimentVersion !== 0 ) {
+ // Use an existing experiment version if it exists
+ setExperimentVersion(
+ currentData.sitegen.theForkExperimentVersion
+ );
+ theForkExperimentVersion =
+ currentData.sitegen.theForkExperimentVersion;
+ } else {
+ // Generate a random experiment version from 1 to 4
+ theForkExperimentVersion = Math.floor( Math.random() * 5 );
+ setExperimentVersion( theForkExperimentVersion );
+
+ // Sync that to the store and DB for same version on refresh
+ currentData.sitegen.theForkExperimentVersion =
+ theForkExperimentVersion;
+ setCurrentOnboardingData( currentData );
+ await setFlow( currentData );
+ const experimentVersionNames = {
+ 1: 'control',
+ 2: 'position',
+ 3: 'badge',
+ 4: 'position_badge',
+ };
+
+ // Send an event for the experiment version shown to the user.
+ sendOnboardingEvent(
+ new OnboardingEvent(
+ ACTION_SITEGEN_FORK_AI_EXPERIMENT,
+ experimentVersionNames[ theForkExperimentVersion ],
+ null,
+ null,
+ CATEGORY_EXPERIMENT
+ )
+ );
+ }
+ };
+
const oldFlow = window.nfdOnboarding?.oldFlow
? window.nfdOnboarding.oldFlow
: DEFAULT_FLOW;
@@ -73,6 +126,7 @@ const TheFork = () => {
subtitle={ content.subheading }
/>
{
@@ -24,6 +27,19 @@ if ( runtimeDataExists ) {
},
} );
+ HiiveAnalytics.initialize( {
+ namespace: CATEGORY_EXPERIMENT,
+ urls: {
+ single: onboardingRestURL( 'events' ),
+ batch: onboardingRestURL( 'events/batch' ),
+ },
+ settings: {
+ debounce: {
+ time: 3000,
+ },
+ },
+ } );
+
initializeNFDOnboarding(
NFD_ONBOARDING_ELEMENT_ID,
window.nfdOnboarding
diff --git a/tests/cypress/integration/5-AI-SiteGen-onboarding-flow/1-fork.cy.js b/tests/cypress/integration/5-AI-SiteGen-onboarding-flow/1-fork.cy.js
index 97a2e3f65..b66cf91d5 100644
--- a/tests/cypress/integration/5-AI-SiteGen-onboarding-flow/1-fork.cy.js
+++ b/tests/cypress/integration/5-AI-SiteGen-onboarding-flow/1-fork.cy.js
@@ -43,7 +43,7 @@ describe( 'SiteGen Fork Step', function () {
.should('have.length', 3);
} );
- it( 'Check for selection of different container options', () => {
+ it.skip( 'Check for selection of different container options', () => {
let options = 0;
const className = '.nfd-onboarding-sitegen-options__container__options';
const arr = cy.get( className );