Skip to content

Commit f919c6e

Browse files
Merge pull request #652 from newfold-labs/add/PRESS8-243-resume-or-restart-onboarding
Restart Onboarding
2 parents 30a55a8 + 06d9030 commit f919c6e

File tree

9 files changed

+416
-10
lines changed

9 files changed

+416
-10
lines changed

includes/Services/StatusService.php

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
<?php
22
namespace NewfoldLabs\WP\Module\Onboarding\Services;
33

4+
use NewfoldLabs\WP\Module\Onboarding\Data\Brands;
45
use NewfoldLabs\WP\Module\Onboarding\Data\Options;
56
use NewfoldLabs\WP\Module\Onboarding\WP_Admin;
7+
use NewfoldLabs\WP\Module\Onboarding\Data\Config;
68

79
/**
810
* Tracks the Status of Onboarding.
@@ -14,7 +16,7 @@ class StatusService {
1416
*
1517
* @return void
1618
*/
17-
public static function handle_started() {
19+
public static function handle_started(): void {
1820
if ( 'started' !== get_option( Options::get_option_name( 'status' ) ) ) {
1921
update_option( Options::get_option_name( 'status' ), 'started' );
2022
do_action( 'newfold/onboarding/started' );
@@ -26,19 +28,91 @@ public static function handle_started() {
2628
*
2729
* @return void
2830
*/
29-
public static function handle_completed() {
31+
public static function handle_completed(): void {
3032
if ( 'started' === get_option( Options::get_option_name( 'status' ) ) ) {
3133
update_option( Options::get_option_name( 'status' ), 'completed' );
34+
self::update_onboarding_restart_status();
3235
do_action( 'newfold/onboarding/completed' );
3336
}
3437
}
3538

39+
/**
40+
* Checks if the WordPress site was created within the last 9 months (275 days)
41+
* using the 'bluehost_plugin_install_date' option.
42+
*
43+
* @return bool True if the site was created within the last 275 days, false otherwise.
44+
*/
45+
private static function is_site_created_within_last_9_months(): bool {
46+
$install_date_timestamp = get_option( Options::get_option_name( 'bluehost_plugin_install_date', false ) );
47+
48+
// If the option is not set or is invalid, return false
49+
if ( ! $install_date_timestamp ) {
50+
return false;
51+
}
52+
53+
// Calculate the timestamp for 275 days ago (9 months)
54+
$nine_months_ago = time() - ( 275 * 24 * 60 * 60 );
55+
56+
return $install_date_timestamp >= $nine_months_ago;
57+
}
58+
59+
/**
60+
* Checks if the user is eligible to restart onboarding based on brand configuration and AI SiteGen capability.
61+
*
62+
* @return bool True if eligible, false otherwise.
63+
*/
64+
public static function is_onboarding_restart_eligible(): bool {
65+
// Check if the brand is eligible for Restarting Onboarding
66+
$brand_config = Brands::get_brands()[ NFD_ONBOARDING_PLUGIN_BRAND ]['config'] ?? array();
67+
if ( empty( $brand_config['canRestartOnboarding'] ) || ! $brand_config['canRestartOnboarding'] ) {
68+
return false;
69+
}
70+
71+
// Check if AI SiteGen Hiive capability is active and the site was created in the last 9 months
72+
if ( ! Config::has_ai_sitegen() || ! self::is_site_created_within_last_9_months() ) {
73+
return false;
74+
}
75+
76+
return true;
77+
}
78+
79+
/**
80+
* Handles the flow data and updates the restart eligibility status based on total onboarding tries.
81+
*
82+
* @return void
83+
*/
84+
public static function update_onboarding_restart_status(): void {
85+
86+
// Don't do anything if the customer is not eligible
87+
if ( ! self::is_onboarding_restart_eligible() ) {
88+
return;
89+
}
90+
91+
// Get flow data
92+
$flow_data = get_option( Options::get_option_name( 'flow' ) );
93+
94+
if ( isset( $flow_data['onboardingRetries'] ) && ! empty( $flow_data['onboardingRetries'] ) ) {
95+
// Increment the total onboarding tries
96+
$flow_data['onboardingRetries']['retryCount'] = ( $flow_data['onboardingRetries']['retryCount'] ?? 0 ) + 1;
97+
98+
// Update the flow data with the incremented total onboarding tries count
99+
update_option( Options::get_option_name( 'flow' ), $flow_data );
100+
101+
// Determine eligibility for restarting onboarding
102+
$current_retry_count = $flow_data['onboardingRetries']['retryCount'];
103+
$can_restart = $current_retry_count < $flow_data['onboardingRetries']['maxRetryCount'];
104+
105+
// Update the eligibility status in wp_option
106+
update_option( Options::get_option_name( 'can_restart' ), $can_restart );
107+
}
108+
}
109+
36110
/**
37111
* Begin tracking the Onboarding status in an option.
38112
*
39113
* @return void
40114
*/
41-
public static function track() {
115+
public static function track(): void {
42116
global $pagenow;
43117

44118
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
@@ -49,7 +123,7 @@ public static function track() {
49123
case 'index.php':
50124
// If the page is not nfd-onboarding.
51125
//phpcs:ignore
52-
if ( ! isset( $_GET['page'] ) || WP_Admin::$slug !== \sanitize_text_field( $_GET['page'] ) ) {
126+
if ( isset( $_GET['page'] ) && WP_Admin::$slug !== \sanitize_text_field( $_GET['page'] ) ) {
53127
self::handle_completed();
54128
}
55129
break;

includes/WP_Admin.php

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use NewfoldLabs\WP\Module\Onboarding\Data\Services\SiteGenService;
1010
use NewfoldLabs\WP\Module\Onboarding\Data\Themes;
1111
use NewfoldLabs\WP\Module\Onboarding\Services\I18nService;
12+
use NewfoldLabs\WP\Module\Onboarding\Services\StatusService;
1213

1314
/**
1415
* Register Admin Page, Assets & Admin functionality with WordPress.
@@ -32,6 +33,7 @@ public function __construct() {
3233
\add_action( 'admin_menu', array( __CLASS__, 'register_page' ) );
3334
\add_action( 'load-dashboard_page_' . self::$slug, array( __CLASS__, 'page_title' ), 9, 1 );
3435
\add_action( 'load-dashboard_page_' . self::$slug, array( __CLASS__, 'initialize' ) );
36+
\add_action( 'load-themes.php', array( __CLASS__, 'can_restart_onboarding' ) );
3537
if ( 'sitegen' === Data::current_flow() ) {
3638
\add_action( 'load-themes.php', array( __CLASS__, 'mark_sitegen_generated_themes' ) );
3739
SiteGenService::pre_set_filter_wonder_blocks_transients();
@@ -179,6 +181,8 @@ public static function initialize() {
179181
FlowService::initialize_data();
180182

181183
self::register_assets();
184+
185+
self::set_onboarding_restart_option();
182186
}
183187

184188
/**
@@ -223,4 +227,73 @@ public static function mark_sitegen_generated_themes() {
223227
\wp_enqueue_script( 'sitegen-theme-marker' );
224228
\wp_enqueue_style( 'sitegen-theme-marker' );
225229
}
230+
231+
/**
232+
* Sets the option in DB for the Initial Load of Onboarding
233+
*
234+
* @return void
235+
*/
236+
public static function set_onboarding_restart_option(): void {
237+
// Check if the customer is eligible for onboarding restart
238+
if ( StatusService::is_onboarding_restart_eligible() ) {
239+
// Get the option name for 'can_restart'
240+
$option_name = Options::get_option_name( 'can_restart' );
241+
242+
// Check if the option doesn't exist before adding it
243+
if ( ! get_option( $option_name ) ) {
244+
// Add the option if it doesn't exist
245+
add_option( $option_name, true );
246+
}
247+
} else {
248+
// Get the option name for 'can_restart'
249+
$option_name = Options::get_option_name( 'can_restart' );
250+
251+
// Add the option if it doesn't exist
252+
update_option( $option_name, false );
253+
}
254+
}
255+
256+
/**
257+
* Enqueue scripts that adds a new button to Restart Onboarding in themes.php
258+
*
259+
* @return void
260+
*/
261+
public static function can_restart_onboarding(): void {
262+
$can_restart = get_option( Options::get_option_name( 'can_restart' ), false );
263+
264+
// If the customer in ineligible for restart don't enqueue scripts
265+
if ( ! $can_restart || ! StatusService::is_onboarding_restart_eligible() ) {
266+
return;
267+
}
268+
269+
\wp_register_script(
270+
'onboarding-restart-button',
271+
NFD_ONBOARDING_BUILD_URL . '/onboarding-restart-button.js',
272+
array(),
273+
'1.0.0',
274+
true
275+
);
276+
277+
\wp_add_inline_script(
278+
'onboarding-restart-button',
279+
'var nfdOnboardingRestartMeta =' . wp_json_encode(
280+
array(
281+
'buttonText' => \__( 'Build with AI', 'wp-module-onboarding' ),
282+
'buttonHref' => \admin_url( 'index.php?page=' . self::$slug ),
283+
)
284+
) . ';',
285+
'before'
286+
);
287+
288+
\wp_register_style(
289+
'onboarding-restart-button',
290+
NFD_ONBOARDING_BUILD_URL . '/onboarding-restart-button.css.css',
291+
array(),
292+
'1.0.0',
293+
'all'
294+
);
295+
296+
\wp_enqueue_script( 'onboarding-restart-button' );
297+
\wp_enqueue_style( 'onboarding-restart-button' );
298+
}
226299
} // END /NewfoldLabs/WP/Module/Onboarding/Admin()

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
"webpack-merge": "^5.8.0"
2222
},
2323
"scripts": {
24-
"build": "wp-scripts build ./src/onboarding.js ./src/Scripts/sitegen-theme-marker/sitegen-theme-marker.js ./src/Scripts/sitegen-theme-marker/sitegen-theme-marker.css",
24+
"build": "wp-scripts build ./src/onboarding.js ./src/Scripts/sitegen-theme-marker/sitegen-theme-marker.js ./src/Scripts/sitegen-theme-marker/sitegen-theme-marker.css ./src/Scripts/onboarding-restart-button/onboarding-restart-button.js ./src/Scripts/onboarding-restart-button/onboarding-restart-button.css",
2525
"format": "wp-scripts format ./src",
26-
"start": "wp-scripts start ./src/onboarding.js ./src/Scripts/sitegen-theme-marker/sitegen-theme-marker.js ./src/Scripts/sitegen-theme-marker/sitegen-theme-marker.css",
26+
"start": "wp-scripts start ./src/onboarding.js ./src/Scripts/sitegen-theme-marker/sitegen-theme-marker.js ./src/Scripts/sitegen-theme-marker/sitegen-theme-marker.css ./src/Scripts/onboarding-restart-button/onboarding-restart-button.js ./src/Scripts/onboarding-restart-button/onboarding-restart-button.css",
2727
"set-version-bump": "node ./.github/scripts/set-version-bump.js && npm i && rm -rf ./build && npm run build && composer run i18n",
2828
"lint:js": "wp-scripts lint-js ./src",
2929
"lint:js:fix": "wp-scripts lint-js ./src --fix",

src/OnboardingSPA/steps/TheFork/index.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@ import {
2121
OnboardingEvent,
2222
sendOnboardingEvent,
2323
} from '../../utils/analytics/hiive';
24-
import { ACTION_SITEGEN_FORK_OPTION_SELECTED } from '../../utils/analytics/hiive/constants';
24+
import {
25+
ACTION_SITEGEN_FORK_OPTION_SELECTED,
26+
ACTION_ONBOARDING_RESTARTED,
27+
} from '../../utils/analytics/hiive/constants';
2528
import { store as nfdOnboardingStore } from '../../store';
2629
import { DEFAULT_FLOW } from '../../data/flows/constants';
2730

2831
const TheFork = () => {
29-
const { migrationUrl, canMigrateSite, pluginInstallHash } =
30-
useSelect( ( select ) => {
32+
const { migrationUrl, canMigrateSite, pluginInstallHash } = useSelect(
33+
( select ) => {
3134
return {
3235
migrationUrl: select( nfdOnboardingStore ).getMigrationUrl(),
3336
canMigrateSite: select( nfdOnboardingStore ).canMigrateSite(),
@@ -36,7 +39,8 @@ const TheFork = () => {
3639
pluginInstallHash:
3740
select( nfdOnboardingStore ).getPluginInstallHash(),
3841
};
39-
} );
42+
}
43+
);
4044
const {
4145
setIsHeaderEnabled,
4246
setSidebarActiveView,
@@ -58,6 +62,22 @@ const TheFork = () => {
5862
initializePlugins( pluginInstallHash );
5963
} );
6064

65+
useEffect( () => {
66+
const url = new URL( window.location );
67+
const restartParam = url.searchParams.get( 'restart' );
68+
69+
if ( restartParam ) {
70+
// Remove the query parameter from the URL so it doesn't send events on refresh
71+
url.searchParams.delete( 'restart' );
72+
73+
// Use the history API to update the URL without reloading the page
74+
window.history.pushState( {}, '', url.toString() );
75+
sendOnboardingEvent(
76+
new OnboardingEvent( ACTION_ONBOARDING_RESTARTED, restartParam )
77+
);
78+
}
79+
}, [] );
80+
6181
const oldFlow = window.nfdOnboarding?.oldFlow
6282
? window.nfdOnboarding.oldFlow
6383
: DEFAULT_FLOW;

src/OnboardingSPA/utils/analytics/hiive/constants.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export const ACTION_ONBOARDING_STARTED = 'onboarding_started';
22
export const ACTION_ONBOARDING_COMPLETE = 'onboarding_complete';
3+
export const ACTION_ONBOARDING_RESTARTED = 'onboarding_restarted';
34
export const ACTION_PAGEVIEW = 'pageview';
45
export const ACTION_ONBOARDING_TOP_PRIORITY_SET = 'onboarding_top_priority_set';
56
export const ACTION_ONBOARDING_STEP_SKIPPED = 'onboarding_step_skipped';
@@ -69,4 +70,5 @@ export const ACTION_TO_LABEL_KEY_MAP = {
6970
[ ACTION_MIGRATION_INITIATED ]: 'path',
7071
[ ACTION_MFE_MIGRATION_INITIATED ]: 'path',
7172
[ ACTION_SITEGEN_ERROR_STATE_TRIGGERED ]: 'identifier',
73+
[ ACTION_ONBOARDING_RESTARTED ]: 'location',
7274
};
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/* Container for Build with AI */
2+
.build-with-ai {
3+
display: flex;
4+
align-items: center;
5+
justify-content: center;
6+
text-align: center;
7+
height: auto;
8+
border: none;
9+
box-shadow: none;
10+
transition: background 100ms ease-in-out;
11+
}
12+
13+
/* Link inside the Build with AI container */
14+
.build-with-ai__link {
15+
display: flex;
16+
flex-direction: column;
17+
position: relative;
18+
text-decoration: none;
19+
height: 100%;
20+
}
21+
22+
/* Icon container */
23+
.build-with-ai__icon {
24+
flex-grow: 1;
25+
display: flex;
26+
align-items: center;
27+
justify-content: center;
28+
}
29+
30+
/* Icon span */
31+
.build-with-ai__icon-span {
32+
width: 100px;
33+
height: 100px;
34+
display: flex;
35+
align-items: center;
36+
justify-content: center;
37+
margin-top: 25px;
38+
margin-bottom: 10px;
39+
border-radius: 50%;
40+
color: #8c8f94;
41+
font-size: 40px;
42+
background-color: rgba(140, 143, 148, 0.1);
43+
transition: background 100ms ease-in-out;
44+
}
45+
46+
/* Text under the icon */
47+
.build-with-ai__text {
48+
margin: 0;
49+
color: #333;
50+
font-weight: 400;
51+
padding-bottom: 48px;
52+
transition: color 100ms ease-in-out;
53+
}
54+
55+
/* Hover states for the Build with AI component */
56+
.build-with-ai:hover {
57+
background-color: #2271b1;
58+
}
59+
60+
/* Hover effect on the icon span */
61+
.build-with-ai:hover .build-with-ai__icon-span {
62+
background-color: #fff;
63+
}
64+
65+
/* Hover effect on the text */
66+
.build-with-ai:hover .build-with-ai__text {
67+
color: #fff;
68+
}

0 commit comments

Comments
 (0)