add_action( 'rest_api_init', $this, 'register_routes' ); } /** * Registers GET/POST /onboarding. * * @return void */ public function register_routes(): void { register_rest_route( ABDS_SEO_Rest_Controller::NAMESPACE_V1, '/onboarding', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_status' ), 'permission_callback' => array( $this, 'can_manage' ), ), array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'update_status' ), 'permission_callback' => array( $this, 'can_manage' ), 'args' => array( 'status' => array( 'type' => 'string', 'required' => true, 'sanitize_callback' => 'sanitize_text_field', ), 'step' => array( 'type' => 'integer', 'required' => false, ), ), ), ) ); } /** * Capability check. * * @return bool */ public function can_manage(): bool { return current_user_can( ABDS_SEO_Activator::CAPABILITY ); } /** * The wizard state for a user. Defaults to pending/step 0 (a fresh admin who * has never seen it). * * @param int $user_id User id. * @return array{status:string, step:int} */ public function get_state( int $user_id ): array { $raw = get_user_meta( $user_id, self::META_KEY, true ); if ( ! is_array( $raw ) ) { return array( 'status' => self::STATUS_PENDING, 'step' => 0, ); } return array( 'status' => self::STATUS_DONE === ( $raw['status'] ?? '' ) ? self::STATUS_DONE : self::STATUS_PENDING, 'step' => max( 0, (int) ( $raw['step'] ?? 0 ) ), ); } /** * Persists the wizard state for a user. * * @param int $user_id User id. * @param string $status STATUS_PENDING or STATUS_DONE. * @param int $step Last-seen step index. * @return array{status:string, step:int} The stored state. */ public function set_state( int $user_id, string $status, int $step ): array { $state = array( 'status' => self::STATUS_DONE === $status ? self::STATUS_DONE : self::STATUS_PENDING, 'step' => max( 0, $step ), ); update_user_meta( $user_id, self::META_KEY, $state ); return $state; } /** * GET /onboarding. * * @return WP_REST_Response */ public function get_status(): WP_REST_Response { return new WP_REST_Response( $this->get_state( get_current_user_id() ), 200 ); } /** * POST /onboarding — persists status (and step). The wizard calls this on * every step advance and on finish/skip/close, so a dismissal is never lost. * * @param WP_REST_Request $request Request. * @return WP_REST_Response */ public function update_status( WP_REST_Request $request ): WP_REST_Response { $status = (string) $request->get_param( 'status' ); $step = null !== $request->get_param( 'step' ) ? (int) $request->get_param( 'step' ) : 0; return new WP_REST_Response( $this->set_state( get_current_user_id(), $status, $step ), 200 ); } }