magic_link = new MagicLinkManager(); parent::__construct(); } /** * Register REST routes */ public function registerRoutes(): void { // Send magic link register_rest_route($this->namespace, '/magic-link', [ 'methods' => 'POST', 'callback' => [$this, 'sendMagicLink'], 'permission_callback' => '__return_true', // Public endpoint 'args' => [ 'email' => [ 'required' => true, 'type' => 'string', 'format' => 'email', 'validate_callback' => function($param) { return is_email($param); } ], 'type' => [ 'required' => false, 'type' => 'string', 'default' => 'login', 'enum' => ['login', 'signup', 'referral', 'reset'] ], 'context' => [ 'required' => false, 'type' => 'object', 'default' => [] ] ] ]); // Resend magic link register_rest_route($this->namespace, '/magic-link/resend', [ 'methods' => 'POST', 'callback' => [$this, 'resendMagicLink'], 'permission_callback' => '__return_true', 'args' => [ 'email' => [ 'required' => true, 'type' => 'string', 'format' => 'email' ], 'type' => [ 'required' => true, 'type' => 'string' ] ] ]); // Check token validity (useful for frontend) register_rest_route($this->namespace, '/magic-link/verify', [ 'methods' => 'POST', 'callback' => [$this, 'verifyToken'], 'permission_callback' => '__return_true', 'args' => [ 'token' => [ 'required' => true, 'type' => 'string' ], 'email' => [ 'required' => true, 'type' => 'string', 'format' => 'email' ] ] ]); } /** * Send a magic link via email * * @param WP_REST_Request $request * @return WP_REST_Response */ public function sendMagicLink(WP_REST_Request $request): WP_REST_Response { $email = sanitize_email($request->get_param('email')); $type = sanitize_text_field($request->get_param('type')); $context = $request->get_param('context') ?? []; error_log('SendMagicLink request: '.print_r($email, true)); error_log('Type: '.print_r($type, true)); error_log('Context: '.print_r($context, true)); // Validate email if (!is_email($email)) { return new WP_REST_Response([ 'success' => false, 'message' => 'Invalid email address' ], 400); } // Send the magic link $result = $this->magic_link->sendMagicLink($email, $type, $context); error_log('Result: '.print_r($result, true)); if (is_wp_error($result)) { return new WP_REST_Response([ 'success' => false, 'message' => $result->get_error_message(), 'code' => $result->get_error_code() ], 400); } // Return success (never reveal if user exists or not) return new WP_REST_Response([ 'success' => true, 'message' => 'If an account exists with this email, we\'ve sent a login link.' ], 200); } /** * Resend a magic link * * @param WP_REST_Request $request * @return WP_REST_Response */ public function resendMagicLink(WP_REST_Request $request): WP_REST_Response { // Same as sending, but could add additional logging return $this->sendMagicLink($request); } /** * Verify a token without consuming it * Useful for frontend validation before redirect * * @param WP_REST_Request $request * @return WP_REST_Response */ public function verifyToken(WP_REST_Request $request): WP_REST_Response { $token = sanitize_text_field($request->get_param('token')); $email = sanitize_email($request->get_param('email')); $cache_key = 'magic_token_' . $token; $token_data = get_transient($cache_key); if (!$token_data) { return new WP_REST_Response([ 'valid' => false, 'message' => 'Token expired or invalid' ], 400); } if ($token_data['email'] !== $email) { return new WP_REST_Response([ 'valid' => false, 'message' => 'Invalid token' ], 400); } if (time() > $token_data['expires_at']) { return new WP_REST_Response([ 'valid' => false, 'message' => 'Token expired' ], 400); } return new WP_REST_Response([ 'valid' => true, 'type' => $token_data['type'], 'expires_in' => $token_data['expires_at'] - time() ], 200); } protected function processReferralSignup(array $token_data): void { // Create user account $user_id = wp_create_user( $token_data['email'], wp_generate_password(20, true, true), $token_data['email'] ); if (is_wp_error($user_id)) { wp_die('Failed to create account: ' . $user_id->get_error_message()); } // Update user info if (!empty($token_data['name'])) { wp_update_user([ 'ID' => $user_id, 'display_name' => $token_data['name'], 'first_name' => $token_data['name'] ]); } // Store referral code in user meta (temporary) // ReferralManager::processReferral will pick this up update_user_meta($user_id, BASE . 'pending_referral_code', $token_data['referral_code']); // Trigger registration actions (this calls processReferral) do_action('user_register', $user_id); // Log the user in wp_set_current_user($user_id); wp_set_auth_cookie($user_id, true); do_action('wp_login', get_user_by('ID', $user_id)->user_login, get_user_by('ID', $user_id)); // Redirect with referral welcome message wp_safe_redirect(home_url('/dash?referral_welcome=1')); exit; } }