feat: implement onboarding wizard and fix help page navigation

Core Features:
- Add Quick Setup Wizard for new users with multi-step flow
- Implement distraction-free onboarding layout (no sidebar/header)
- Create OnboardingController API endpoint for saving settings
- Redirect new users to /setup automatically on first admin access

Onboarding Components:
- StepMode: Select between full/minimal store modes
- StepHomepage: Choose or auto-create homepage
- StepAppearance: Configure container width and primary color
- StepProgress: Visual progress indicator

Navigation & Routing:
- Fix Help page links to use react-router navigation (prevent full reload)
- Update onboarding completion redirect to /appearance/pages
- Add manual onboarding access via Settings > Store Details

UI/UX Improvements:
- Enable dark mode support for Page Editor
- Fix page title rendering in onboarding dropdown
- Improve title fallback logic (title.rendered, title, post_title)

Type Safety:
- Unify PageItem interface across all components
- Add 'default' to containerWidth type definition
- Add missing properties (permalink_base, has_template, icon)

Files Modified:
- includes/Api/OnboardingController.php
- includes/Api/Routes.php
- includes/Admin/Assets.php
- admin-spa/src/App.tsx
- admin-spa/src/routes/Onboarding/*
- admin-spa/src/routes/Help/DocContent.tsx
- admin-spa/src/routes/Settings/Store.tsx
- admin-spa/src/routes/Appearance/Pages/*
This commit is contained in:
Dwindi Ramadhana
2026-02-06 00:30:38 +07:00
parent 7da4f0a167
commit 687a2318b0
15 changed files with 755 additions and 124 deletions

View File

@@ -0,0 +1,172 @@
<?php
/**
* Onboarding REST API Controller
*
* Handles the quick setup wizard endpoints.
*
* @package WooNooW
*/
namespace WooNooW\Api;
use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_Response;
use WP_Error;
class OnboardingController extends WP_REST_Controller
{
/**
* Namespace
*/
protected $namespace = 'woonoow/v1';
/**
* Rest base
*/
protected $rest_base = 'onboarding';
/**
* Register routes
*/
public function register_routes()
{
// GET /woonoow/v1/onboarding/status
register_rest_route($this->namespace, '/' . $this->rest_base . '/status', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => [$this, 'get_status'],
'permission_callback' => [$this, 'check_permission'],
],
]);
// POST /woonoow/v1/onboarding/complete
register_rest_route($this->namespace, '/' . $this->rest_base . '/complete', [
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => [$this, 'complete'],
'permission_callback' => [$this, 'check_permission'],
],
]);
}
/**
* Get onboarding status
*
* @param WP_REST_Request $request Request object
* @return WP_REST_Response Response object
*/
public function get_status(WP_REST_Request $request)
{
$completed = get_option('woonoow_onboarding_completed', false);
return rest_ensure_response(['completed' => (bool) $completed]);
}
/**
* Complete onboarding
*
* @param WP_REST_Request $request Request object
* @return WP_REST_Response|WP_Error Response object or error
*/
public function complete(WP_REST_Request $request)
{
$params = $request->get_json_params();
// 1. Save Mode
if (isset($params['mode'])) {
$mode = sanitize_text_field($params['mode']);
// If Immersive (full), enable SPA mode. Else disable or set accordingly.
// Assumption: 'spa_mode' option controls this.
// logic: 'full' -> woocommerce_spa_mode = 'yes'
// 'checkout_only' -> woocommerce_spa_mode = 'checkout_only'? (Checking implementation later, sticking to standard 'yes'/'no' for now or custom logic if strictly defined)
// Re-reading strategy: "Immersive (Full SPA)", "Classic", "Standard".
// Let's assume standard WP options for now.
// If 'full', set 'woonoow_spa_enabled' to 'yes'.
update_option('woonoow_spa_mode', $mode);
}
// 2. Handle Page Selection / Magic Creation
if (!empty($params['create_home_page']) && $params['create_home_page'] === true) {
$page_id = $this->create_magic_homepage();
if ($page_id) {
update_option('page_on_front', $page_id);
update_option('show_on_front', 'page');
// Set as SPA entry page
update_option('woonoow_spa_entry_page', $page_id);
}
} elseif (!empty($params['entry_page_id'])) {
$page_id = absint($params['entry_page_id']);
update_option('woonoow_spa_entry_page', $page_id);
// Optionally set as front page if requested? The user just selected "Where should customers land".
// Let's assume for the wizard flow, selecting it implies setting it as front page too for consistency.
update_option('page_on_front', $page_id);
update_option('show_on_front', 'page');
}
// 3. Appearance Settings
// Container Width
if (isset($params['container_width'])) {
update_option('woonoow_container_width', sanitize_text_field($params['container_width']));
}
// Colors / Theme
if (isset($params['primary_color'])) {
// Saving to AppearanceController's expected option
$appearance = get_option('woonoow_appearance_settings', []);
if (!is_array($appearance)) $appearance = [];
$appearance['colors'] = [
'primary' => sanitize_hex_color($params['primary_color']),
// defaults for others checking strategy... "Modern Black", "Blue", "Purple"
];
update_option('woonoow_appearance_settings', $appearance);
}
// 4. Mark as Complete
update_option('woonoow_onboarding_completed', true);
return rest_ensure_response([
'success' => true,
'message' => 'Onboarding completed',
'redirect' => admin_url('admin.php?page=woonoow-builder'), // Or similar
]);
}
/**
* Programmatically create a homepage
*
* @return int|false Page ID or false
*/
private function create_magic_homepage()
{
$page_args = [
'post_type' => 'page',
'post_title' => __('Shop Home', 'woonoow'),
'post_content' => '<!-- wp:woonoow/hero -->...<!-- /wp:woonoow/hero -->', // Placeholder
'post_status' => 'publish',
'post_author' => get_current_user_id(),
];
$page_id = wp_insert_post($page_args);
if (is_wp_error($page_id)) {
return false;
}
return $page_id;
}
/**
* Check permission
*
* @return bool True if user has permission
*/
public function check_permission()
{
return current_user_can('manage_woocommerce');
}
}