feat: improvements to onboarding flow#1295
feat: improvements to onboarding flow#1295HardeepAsrani wants to merge 2 commits intodevelopmentfrom
Conversation
…in install, XSS Agent-Logs-Url: https://github.com/Codeinwp/visualizer/sessions/0ea8792d-4154-4e13-989d-301380d262b1 Co-authored-by: selul <3330746+selul@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR streamlines the Visualizer setup wizard/onboarding flow by reducing the number of steps and consolidating “extra features” + newsletter into a single final step, while updating UI, JS behavior, and E2E coverage accordingly.
Changes:
- Reduced wizard from 5 steps to 3 and redesigned the final step to include optional plugin installs + newsletter opt-in.
- Updated wizard frontend logic to run chart import inline, install selected plugins sequentially, and then finish/redirect.
- Refreshed wizard styling (grid-based chart picker, new option cards) and updated E2E onboarding test to match the new flow.
Reviewed changes
Copilot reviewed 6 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/e2e/specs/onboarding.spec.ts | Updates E2E onboarding assertions and interactions for the new 3-step wizard flow. |
| templates/setup-wizard.php | Restructures wizard steps, adds final consolidated “You’re all set!” options UI, adds new plugin-active checks. |
| js/setup-wizard.js | Refactors step transitions (inline import), adds sequential plugin install flow, updates finish/subscribe behavior. |
| css/style-wizard.css | Updates layout/styling for new step structure and chart list grid; adds final-step option card styles. |
| classes/Visualizer/Module/Wizard.php | Improves POST sanitization; returns chart_id on import; generalizes plugin install/activation for multiple slugs. |
| classes/Visualizer/Module/Setup.php | Avoids activation redirect during AJAX/cron; keeps activation redirect behavior for normal admin requests. |
| images/spc-logo.svg | Adds Super Page Cache logo asset for final-step option card UI. |
| images/otter-logo.png | Adds Otter Blocks logo asset for final-step option card UI. |
Comments suppressed due to low confidence (2)
js/setup-wizard.js:38
res.messageis inserted into the DOM via.html(...)(and plugin-install errors are also injected with.html('<p>' + message + '</p>')). To avoid XSS risk from unexpected markup in server-provided messages, prefer.text(...)(or escape before injecting) and build the DOM nodes without string concatenation.
$.post(visualizerSetupWizardData.ajax.url, postData, function (res) {
// Toggle the redirect popup.
$('.redirect-popup').find('h3.popup-title').html(res.message);
$('.redirect-popup').show();
js/setup-wizard.js:393
- This script no longer initializes Slick (the previous
$('.vz-chart-list > ul').slick(...)block was removed), but the wizard still enqueuesslick.min.cssand registersjquery-slickas a dependency for SmartWizard. To avoid loading unused JS/CSS on the wizard screen, consider removing the Slick enqueues/dependency if it’s no longer needed anywhere in the setup wizard.
$(window).bind('pageshow', function() {
if ( jQuery('.vz-chart-option input').is(':checked') ) {
$('#step-1').find('button.disabled').removeClass('disabled');
}
});
});
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <div class="vz-pro-option"> | ||
| <label class="vz-chart-option"> | ||
| <input type="radio" class="vz-radio-btn" id="vz-chart-6" readonly> | ||
| <div class="vz-pro-label-wrap"> |
There was a problem hiding this comment.
The PRO chart options use readonly on <input type="radio">, but readonly has no effect for radio inputs. Since these inputs still have the .vz-radio-btn class (and no value), users can select them and the JS will treat them as a valid chart selection; runImport() will then submit an invalid chart_type (often "on") and the import will fail. Mark these PRO radios as disabled (and ideally remove .vz-radio-btn or otherwise exclude them from the selection logic), and ensure they can’t be selected via keyboard.
| if ( ! empty( $installed_plugins ) ) { | ||
| $plugin_files = array_keys( $installed_plugins ); | ||
| $plugin_file = sanitize_key( wp_unslash( $slug ) ) . '/' . $plugin_files[0]; | ||
| activate_plugin( $plugin_file ); |
There was a problem hiding this comment.
activate_plugin() can return a WP_Error (e.g., activation failure due to missing requirements). The current code ignores the return value, so the wizard may report success even though the plugin wasn’t activated. Capture the return value and wp_send_json an error status/message when activation fails (and avoid updating wizard_data in that case).
| activate_plugin( $plugin_file ); | |
| $activation_result = activate_plugin( $plugin_file ); | |
| if ( is_wp_error( $activation_result ) ) { | |
| wp_send_json( | |
| array( | |
| 'status' => 0, | |
| 'message' => $activation_result->get_error_message(), | |
| ) | |
| ); | |
| } |
| $installed_plugins = get_plugins( '/' . sanitize_key( wp_unslash( $slug ) ) ); | ||
| if ( ! empty( $installed_plugins ) ) { | ||
| $plugin_files = array_keys( $installed_plugins ); | ||
| $plugin_file = sanitize_key( wp_unslash( $slug ) ) . '/' . $plugin_files[0]; |
There was a problem hiding this comment.
The plugin file detection uses get_plugins() + array_keys()[0] to pick the first plugin file in the folder. This relies on ordering and may activate the wrong file if the folder contains multiple plugin-header files. Since this wizard only installs known slugs, consider mapping slug → expected main plugin file (e.g. optimole-wp/optimole-wp.php, otter-blocks/otter-blocks.php, wp-cloudflare-page-cache/wp-cloudflare-super-page-cache.php) and activate that explicitly (or otherwise deterministically choose the correct file).
| $installed_plugins = get_plugins( '/' . sanitize_key( wp_unslash( $slug ) ) ); | |
| if ( ! empty( $installed_plugins ) ) { | |
| $plugin_files = array_keys( $installed_plugins ); | |
| $plugin_file = sanitize_key( wp_unslash( $slug ) ) . '/' . $plugin_files[0]; | |
| $slug_key = sanitize_key( wp_unslash( $slug ) ); | |
| $installed_plugins = get_plugins( '/' . $slug_key ); | |
| if ( ! empty( $installed_plugins ) ) { | |
| $plugin_main_files = array( | |
| 'optimole-wp' = > 'optimole-wp/optimole-wp.php', | |
| 'otter-blocks' => 'otter-blocks/otter-blocks.php', | |
| 'wp-cloudflare-page-cache' => 'wp-cloudflare-page-cache/wp-cloudflare-super-page-cache.php', | |
| ); | |
| if ( isset( $plugin_main_files[ $slug_key ] ) ) { | |
| $plugin_file = $plugin_main_files[ $slug_key ]; | |
| } else { | |
| $plugin_files = array_keys( $installed_plugins ); | |
| sort( $plugin_files ); | |
| $plugin_file = $slug_key . '/' . $plugin_files[0]; | |
| } |
Summary
This PR improves the onboarding flow by removing redundant steps and combining them. All e2e related to the PR have passed. The remaining are unrelated to the PR and will be fixed separately.
Will affect visual aspect of the product
YES
Screenshots
Test instructions
Check before Pull Request is ready:
Closes https://github.com/Codeinwp/visualizer-pro/issues/554.