PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / trunk
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar vtrunk
3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 trunk 0.2.5.5 0.2.5.6 0.2.5.7 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 1.2.2 All 155 releases
notificationx / includes / Core / SetupWizard.php

SetupWizard.php in NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar trunk, at includes/Core/SetupWizard.php

212 lines 6.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Setup Wizard (Onboarding) Class File.
4 *
5 * Registers a standalone, full-screen onboarding wizard under its own
6 * top-level "Setup Wizard" menu. The UI is rendered by the existing admin
7 * React SPA via the `nx-setup-wizard` route.
8 *
9 * @package NotificationX\Core
10 */
11
12 namespace NotificationX\Core;
13
14 use NotificationX\Admin\Admin;
15 use NotificationX\GetInstance;
16
17 /**
18 * @method static SetupWizard get_instance($args = null)
19 */
20 class SetupWizard {
21
22 /**
23 * Instance of SetupWizard
24 *
25 * @var SetupWizard
26 */
27 use GetInstance;
28
29 /**
30 * Page slug for the wizard.
31 */
32 const PAGE = 'nx-setup-wizard';
33
34 /**
35 * Option key that marks onboarding as finished/skipped.
36 */
37 const COMPLETED_OPTION = 'nx_onboarding_completed';
38
39 /**
40 * Initially Invoked when initialized.
41 */
42 public function __construct() {
43 add_action( 'admin_menu', [ $this, 'menu' ], 35 );
44 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_preview_styles' ] );
45 add_filter( 'admin_body_class', [ $this, 'body_class' ] );
46 add_filter( 'nx_rest_miscellaneous', [ $this, 'handle_actions' ], 10, 2 );
47 add_filter( 'nx_builder_configs', [ $this, 'add_status_to_context' ], 10, 1 );
48 }
49
50 /**
51 * Register the "Setup Wizard" submenu under the NotificationX menu.
52 *
53 * Rendered by Admin::views() (the same React SPA root) so the
54 * `nx-setup-wizard` route can take over the full screen.
55 *
56 * @return void
57 */
58 public function menu() {
59 add_submenu_page(
60 'nx-admin',
61 __( 'Setup Wizard', 'notificationx' ),
62 __( 'Setup Wizard', 'notificationx' ),
63 'read_notificationx',
64 self::PAGE,
65 [ Admin::get_instance(), 'views' ],
66 30
67 );
68 }
69
70 /**
71 * Load the real frontend notification stylesheet on the wizard page so the
72 * Welcome-screen "Live Preview" renders the actual popup/bar/announcement
73 * designs 1:1. The frontend CSS is fully scoped (no global resets), so it
74 * is safe to load inside wp-admin.
75 *
76 * @param string $hook
77 * @return void
78 */
79 public function enqueue_preview_styles( $hook ) {
80 if ( 'notificationx_page_' . self::PAGE !== $hook ) {
81 return;
82 }
83 wp_enqueue_style(
84 'notificationx-public',
85 Helper::file( 'public/css/frontend.css', true ),
86 [],
87 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context.
88 apply_filters( 'nx_frontend_css_version', NOTIFICATIONX_VERSION ),
89 'all'
90 );
91 }
92
93 /**
94 * Add a body class on the wizard page so the SPA can render a
95 * full-screen layout (covering the WP sidebar / admin bar).
96 *
97 * @param string $classes
98 * @return string
99 */
100 public function body_class( $classes ) {
101 if ( $this->is_wizard_page() ) {
102 $classes .= ' nx-setup-wizard-active';
103 }
104 return $classes;
105 }
106
107 /**
108 * Whether the current admin request is the wizard page.
109 *
110 * @return bool
111 */
112 protected function is_wizard_page() {
113 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
114 return is_admin() && isset( $_GET['page'] ) && self::PAGE === sanitize_key( wp_unslash( $_GET['page'] ) );
115 }
116
117 /**
118 * Handle the `complete_setup_wizard` miscellaneous REST action.
119 *
120 * Returning a non-null value makes the /miscellaneous endpoint respond
121 * with `{ success: true }`.
122 *
123 * @param mixed $result
124 * @param array $params
125 * @return mixed
126 */
127 public function handle_actions( $result, $params ) {
128 if ( isset( $params['action'] ) ) {
129 if ( 'complete_setup_wizard' === $params['action'] ) {
130 return $this->complete( $params );
131 }
132 if ( 'setup_wizard_optin' === $params['action'] ) {
133 return $this->optin_tracking();
134 }
135 }
136 return $result;
137 }
138
139 /**
140 * Record the user's opt-in to WP Insights usage tracking and send the data
141 * to the insights API immediately. Triggered when the user proceeds past
142 * the Welcome step — the in-card notice states that proceeding consents to
143 * collecting the admin email to personalise the setup.
144 *
145 * The wizard no longer decides *whether* data is collected: collection is
146 * enabled from the backend on activation regardless of this flow (see
147 * {@see \NotificationX\Admin\PluginInsights::is_tracking_allowed()}).
148 * This only stores the explicit consent state and sends immediately.
149 *
150 * @return bool
151 */
152 public function optin_tracking() {
153 if ( ! current_user_can( 'read_notificationx' ) ) {
154 return false;
155 }
156 if (
157 class_exists( '\NotificationX\Admin\PluginInsights' )
158 && method_exists( '\NotificationX\Admin\PluginInsights', 'optin' )
159 ) {
160 \NotificationX\Admin\PluginInsights::get_instance( NOTIFICATIONX_FILE )->optin( true );
161 }
162 return true;
163 }
164
165 /**
166 * Mark onboarding as completed (also used when skipped) so the wizard
167 * is not auto-launched again, and persist the collected choices.
168 *
169 * @param array $params
170 * @return bool
171 */
172 public function complete( $params = [] ) {
173 if ( ! current_user_can( 'read_notificationx' ) ) {
174 return false;
175 }
176
177 $goals = [];
178 if ( ! empty( $params['goals'] ) ) {
179 $goals = array_filter( array_map( 'sanitize_key', explode( ',', $params['goals'] ) ) );
180 }
181
182 $data = [
183 'business_type' => isset( $params['business_type'] ) ? sanitize_key( $params['business_type'] ) : '',
184 'goals' => array_values( $goals ),
185 'completed_at' => current_time( 'mysql' ),
186 ];
187 update_option( 'nx_onboarding_data', $data );
188
189 return update_option( self::COMPLETED_OPTION, true );
190 }
191
192 /**
193 * Whether onboarding has already been completed/skipped.
194 *
195 * @return bool
196 */
197 public static function is_completed() {
198 return (bool) get_option( self::COMPLETED_OPTION, false );
199 }
200
201 /**
202 * Expose onboarding status to the admin React app.
203 *
204 * @param array $data
205 * @return array
206 */
207 public function add_status_to_context( $data ) {
208 $data['onboarding_completed'] = self::is_completed();
209 return $data;
210 }
211 }
212