From 75a097a018a0090f5902758353c578fce4aa2a25 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sat, 23 May 2026 18:43:42 +0000
Subject: [PATCH] =CustomBlocks.php overhaul relatively complete. Also refactored the gallery in gallery.min.js and the jvbRenderGallery.

---
 inc/managers/MagicLinkManager.php |  536 +++++++++++++++++++++++++----------------------------------
 1 files changed, 227 insertions(+), 309 deletions(-)

diff --git a/inc/managers/MagicLinkManager.php b/inc/managers/MagicLinkManager.php
index 5b551d2..c8d0a88 100644
--- a/inc/managers/MagicLinkManager.php
+++ b/inc/managers/MagicLinkManager.php
@@ -11,20 +11,20 @@
 /**
  * Magic Link Authentication Manager
  *
- * Handles passwordless authentication via email magic links.
- * Can be used for referral signups, password resets, or general login.
+ * NOTE: Login form integration is now handled by LoginManager.php
+ * This class focuses solely on magic link generation and verification
  */
 class MagicLinkManager
 {
-	protected CacheManager $cache;
-	protected EmailManager $email;
+	protected Cache $cache;
+	protected Cache $referral_cache;
 
 	// Token settings
 	protected int $token_expiry = 900; // 15 minutes in seconds
 	protected int $rate_limit_window = 3600; // 1 hour
 	protected int $max_attempts_per_hour = 5;
 
-	// Link types - allows different flows for different purposes
+	// Link types
 	const TYPE_LOGIN = 'login';
 	const TYPE_SIGNUP = 'signup';
 	const TYPE_REFERRAL = 'referral';
@@ -32,16 +32,13 @@
 
 	public function __construct()
 	{
-		$this->cache = new CacheManager('magic_links', $this->token_expiry);
-		$this->email = new EmailManager();
+		$this->cache = Cache::for('magic_links', $this->token_expiry);
+		$this->referral_cache = Cache::for('referral_magic_links', 14 * DAY_IN_SECONDS);
 
 		// Hook into WordPress auth flow
 		add_action('template_redirect', [$this, 'handleMagicLinkClick']);
 		add_action('wp_login_failed', [$this, 'handleFailedLogin']);
-
-		// Add magic link option to login page
-		add_action('login_form', [$this, 'addMagicLinkOption']);
-		add_filter('authenticate', [$this, 'blockStandardAuth'], 30, 3);
+		add_action('jvb_process_login_tokens', [$this, 'processRegistrationToken'], 10, 3);
 	}
 
 	/**
@@ -86,38 +83,120 @@
 	}
 
 	/**
+	 * Generate a secure token
+	 */
+	protected function generateToken(string $email, string $type, array $data = []): string
+	{
+		$token = wp_generate_password(32, false);
+
+		$token_data = array_merge([
+			'email' => $email,
+			'type' => $type,
+			'created' => time()
+		], $data);
+
+		// Use longer expiry for referral tokens
+		if ($type === self::TYPE_REFERRAL) {
+			$this->referral_cache->set($token, $token_data);
+		} else {
+			$this->cache->set($token, $token_data);
+		}
+
+		return $token;
+	}
+
+	/**
+	 * Verify a token
+	 */
+	public function verifyToken(string $token, string $email): array|WP_Error
+	{
+		// Try regular cache first, then referral cache
+		$token_data = $this->cache->get($token);
+
+		if (!$token_data) {
+			$token_data = $this->referral_cache->get($token);
+		}
+
+		if (!$token_data) {
+			error_log('Token not found. Checking cache stats...');
+			return new WP_Error('invalid_token', 'Invalid or expired token');
+		}
+
+		if ($token_data['email'] !== $email) {
+			return new WP_Error('email_mismatch', 'Token does not match email');
+		}
+
+		// Delete token after verification (single use)
+		// Check which cache it's in and delete from the correct one
+		if ($token_data['type'] === 'referral') {
+			$this->referral_cache->forget($token);
+		} else {
+			$this->cache->forget($token);
+		}
+
+		return $token_data;
+	}
+
+	/**
+	 * Check rate limiting for sending magic links
+	 */
+	protected function checkRateLimit(string $email): bool|WP_Error
+	{
+		$cache_key = 'rate_limit_' . md5($email);
+		$attempts = $this->cache->get($cache_key);
+
+		if (!$attempts) {
+			$attempts = ['count' => 0, 'timestamp' => time()];
+		}
+
+		// Reset counter if window has passed
+		if (time() - $attempts['timestamp'] > $this->rate_limit_window) {
+			$attempts = ['count' => 0, 'timestamp' => time()];
+		}
+
+		// Check if limit exceeded
+		if ($attempts['count'] >= $this->max_attempts_per_hour) {
+			return new WP_Error(
+				'rate_limit_exceeded',
+				'Too many magic link requests. Please try again in an hour.'
+			);
+		}
+
+		// Increment counter
+		$attempts['count']++;
+		$this->cache->set($cache_key, $attempts, $this->rate_limit_window);
+
+		return true;
+	}
+
+	/**
 	 * Send login magic link to existing user
 	 */
 	protected function sendLoginLink(string $email, array $context): bool|WP_Error
 	{
-		// Check if user exists
 		$user = get_user_by('email', $email);
 		if (!$user) {
 			return new WP_Error('user_not_found', 'No account found with this email');
 		}
 
-		// Generate token
 		$token = $this->generateToken($email, self::TYPE_LOGIN, [
 			'user_id' => $user->ID
 		]);
 
-		// Build magic link URL
 		$magic_url = add_query_arg([
 			'magic_token' => $token,
-			'email' => urlencode($email),
+			'email' => rawurlencode($email),
 			'action' => 'magic_login'
 		], home_url('/'));
 
-		// Add redirect if specified
 		if (!empty($context['redirect_to'])) {
 			$magic_url = add_query_arg('redirect_to', urlencode($context['redirect_to']), $magic_url);
 		}
 
-		// Send email
 		$subject = 'Sign in to ' . get_bloginfo('name');
 		$message = $this->getLoginEmailTemplate($user->display_name, $magic_url);
 
-		$sent = $this->email->sendEmail($email, $subject, $message, 'Log in to '. get_bloginfo('name'));
+		$sent = JVB()->email()->sendEmail($email, $subject, $message, 'Log in to '. get_bloginfo('name'));
 
 		return $sent ? true : new WP_Error('email_failed', 'Failed to send magic link');
 	}
@@ -125,14 +204,13 @@
 	/**
 	 * Send signup magic link for new user registration
 	 */
-	protected function sendSignupLink(string $email, array $context):bool|WP_Error
+	protected function sendSignupLink(string $email, array $context): bool|WP_Error
 	{
 		// Check if user already exists
 		if (email_exists($email)) {
 			return $this->sendLoginLink($email, $context);
 		}
 
-		// Generate token with signup data
 		$token_data = [
 			'name' => $context['name'] ?? '',
 			'role' => $context['role'] ?? 'subscriber',
@@ -141,18 +219,16 @@
 
 		$token = $this->generateToken($email, self::TYPE_SIGNUP, $token_data);
 
-		// Build signup completion URL
 		$magic_url = add_query_arg([
 			'magic_token' => $token,
-			'email' => urlencode($email),
+			'email' => rawurlencode($email),
 			'action' => 'magic_signup'
 		], home_url('/'));
 
-		// Send welcome email
 		$subject = 'Complete your ' . get_bloginfo('name') . ' registration';
 		$message = $this->getSignupEmailTemplate($context['name'] ?? '', $magic_url);
 
-		$sent = $this->email->sendEmail($email, $subject, $message, 'Confirm Your Account');
+		$sent = JVB()->email()->sendEmail($email, $subject, $message, 'Complete Registration');
 
 		return $sent ? true : new WP_Error('email_failed', 'Failed to send signup link');
 	}
@@ -160,60 +236,46 @@
 	/**
 	 * Send referral signup link
 	 */
-	protected function sendReferralLink(string $email, array $context):bool|WP_Error
+	protected function sendReferralLink(string $email, array $context): bool|WP_Error
 	{
-		// Check if user already exists
-		if (email_exists($email)) {
-			return new WP_Error('user_exists', 'This person already has an account');
-		}
-
-		// Validate referral code
 		if (empty($context['referral_code'])) {
-			return new WP_Error('missing_referral_code', 'Referral code is required');
+			return new WP_Error('missing_referral', 'Referral code is required');
 		}
 
-		// Get referrer info for personalized email
-		$referrer_name = $context['referrer_name'] ?? 'A friend';
-
-		// Generate token with referral context
 		$token_data = [
-			'name' => $context['name'] ?? '',
 			'referral_code' => $context['referral_code'],
-			'referrer_id' => $context['referrer_id'] ?? 0
+			'name' => $context['name'] ?? '',
+			'role' => $context['role'] ?? 'subscriber',
+			'email'	=> $email
 		];
 
 		$token = $this->generateToken($email, self::TYPE_REFERRAL, $token_data);
 
-		// Build referral signup URL
 		$magic_url = add_query_arg([
 			'magic_token' => $token,
-			'email' => urlencode($email),
+			'email' => rawurlencode($email),
 			'action' => 'magic_referral'
 		], home_url('/'));
 
-		// Send personalized referral email
-		$subject = $referrer_name . ' invited you to ' . get_bloginfo('name');
-		$message = $this->getReferralEmailTemplate(
-			$context['name'] ?? '',
-			$referrer_name,
-			$magic_url,
-			$context['reward_text'] ?? ''
-		);
+		$referrer_name = $context['referrer_name'] ?? 'A friend';
+		$reward_text = $context['reward_text'] ?? '';
 
-		$sent = $this->email->sendEmail($email, $subject, $message, $referrer_name.' invites you to see the difference at Legacy');
+		$subject = (array_key_exists('subject', $context) && $context['subject'] !== '') ? $context['subject'] : $referrer_name . ' invited you to join ' . get_bloginfo('name');
+		$message = $this->getReferralEmailTemplate($context['name'] ?? '', $referrer_name, $magic_url, $reward_text, $context);
 
-		return $sent ? true : new WP_Error('email_failed', 'Failed to send referral invitation');
+		$sent = JVB()->email()->sendEmail($email, $subject, $message, 'Accept Invitation');
+
+		return $sent ? true : new WP_Error('email_failed', 'Failed to send referral link');
 	}
 
 	/**
 	 * Send password reset magic link
 	 */
-	protected function sendResetLink(string $email, array $context):bool|WP_Error
+	protected function sendResetLink(string $email, array $context): bool|WP_Error
 	{
 		$user = get_user_by('email', $email);
 		if (!$user) {
-			// Return success even if user doesn't exist (security best practice)
-			return true;
+			return new WP_Error('user_not_found', 'No account found with this email');
 		}
 
 		$token = $this->generateToken($email, self::TYPE_RESET, [
@@ -222,14 +284,14 @@
 
 		$magic_url = add_query_arg([
 			'magic_token' => $token,
-			'email' => urlencode($email),
+			'email' => rawurlencode($email),
 			'action' => 'magic_reset'
 		], home_url('/'));
 
 		$subject = 'Reset your password';
 		$message = $this->getResetEmailTemplate($user->display_name, $magic_url);
 
-		$sent = $this->email->sendEmail($email, $subject, $message);
+		$sent = JVB()->email()->sendEmail($email, $subject, $message, 'Reset Password');
 
 		return $sent ? true : new WP_Error('email_failed', 'Failed to send reset link');
 	}
@@ -239,21 +301,18 @@
 	 */
 	public function handleMagicLinkClick(): void
 	{
-		// Check if this is a magic link request
 		if (!isset($_GET['action']) || !isset($_GET['magic_token']) || !isset($_GET['email'])) {
 			return;
 		}
 
 		$action = sanitize_text_field($_GET['action']);
 		$token = sanitize_text_field($_GET['magic_token']);
-		$email = sanitize_email($_GET['email']);
+		$email = sanitize_email(rawurldecode($_GET['email']));
 
-		// Only handle magic link actions
 		if (!in_array($action, ['magic_login', 'magic_signup', 'magic_referral', 'magic_reset'])) {
 			return;
 		}
 
-		// Verify token
 		$token_data = $this->verifyToken($token, $email);
 
 		if (is_wp_error($token_data)) {
@@ -261,7 +320,6 @@
 			return;
 		}
 
-		// Handle different action types
 		switch ($action) {
 			case 'magic_login':
 				$this->processLogin($token_data);
@@ -292,18 +350,14 @@
 			wp_die('Invalid user');
 		}
 
-		// Log the user in
 		wp_clear_auth_cookie();
 		wp_set_current_user($user->ID);
 		wp_set_auth_cookie($user->ID, true);
 
-		// Trigger login action
 		do_action('wp_login', $user->user_login, $user);
 
-		// Determine redirect
 		$redirect = isset($_GET['redirect_to']) ? esc_url_raw($_GET['redirect_to']) : home_url('/dash');
 
-		// Redirect
 		wp_safe_redirect($redirect);
 		exit;
 	}
@@ -313,56 +367,10 @@
 	 */
 	protected function processSignup(array $token_data): void
 	{
-		// Create the user account
-		$user_id = wp_create_user(
-			$token_data['email'],
-			wp_generate_password(20, true, true), // Random password
-			$token_data['email']
-		);
-
-		if (is_wp_error($user_id)) {
-			wp_die('Failed to create account: ' . $user_id->get_error_message());
+		if (!array_key_exists('email', $token_data) || !array_key_exists('name', $token_data)) {
+			JVB()->error()->log('[MagicLinkManager]Could not process Signup');
+			return;
 		}
-
-		// Set role
-		$user = get_user_by('ID', $user_id);
-		$user->set_role($token_data['role']);
-
-		// Update display name if provided
-		if (!empty($token_data['name'])) {
-			wp_update_user([
-				'ID' => $user_id,
-				'display_name' => $token_data['name'],
-				'first_name' => $token_data['name']
-			]);
-		}
-
-		// Save any additional meta
-		if (!empty($token_data['meta'])) {
-			foreach ($token_data['meta'] as $key => $value) {
-				update_user_meta($user_id, BASE . $key, $value);
-			}
-		}
-
-		// Log the user in
-		wp_set_current_user($user_id);
-		wp_set_auth_cookie($user_id, true);
-
-		// Trigger registration actions
-		do_action('user_register', $user_id);
-		do_action('wp_login', $user->user_login, $user);
-
-		// Redirect to welcome page or dashboard
-		wp_safe_redirect(home_url('/dash?welcome=1'));
-		exit;
-	}
-
-	/**
-	 * Process referral signup via magic link
-	 */
-	protected function processReferralSignup(array $token_data): void
-	{
-		// Create user account
 		$user_id = wp_create_user(
 			$token_data['email'],
 			wp_generate_password(20, true, true),
@@ -373,7 +381,9 @@
 			wp_die('Failed to create account: ' . $user_id->get_error_message());
 		}
 
-		// Update user info
+		$user = get_user_by('ID', $user_id);
+		$user->set_role($token_data['role']);
+
 		if (!empty($token_data['name'])) {
 			wp_update_user([
 				'ID' => $user_id,
@@ -382,192 +392,105 @@
 			]);
 		}
 
-		// Store referral code in session for ReferralManager to pick up
-		if (session_status() === PHP_SESSION_NONE) {
-			session_start();
+		if (!empty($token_data['meta'])) {
+			foreach ($token_data['meta'] as $key => $value) {
+				update_user_meta($user_id, BASE . $key, $value);
+			}
 		}
-		$_SESSION[BASE . 'referral_code'] = $token_data['referral_code'];
-		setcookie(BASE . 'referral_code', $token_data['referral_code'], time() + (30 * DAY_IN_SECONDS), '/');
 
-		// Process referral (this will be picked up by ReferralManager::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'));
+		do_action('user_register', $user_id);
+		do_action('wp_login', $user->user_login, $user);
+
+		wp_safe_redirect(home_url('/dash?welcome=1'));
 		exit;
 	}
 
 	/**
-	 * Process password reset
+	 * Process referral signup via magic link
+	 */
+	/**
+	 * Process referral signup via magic link
+	 */
+	protected function processReferralSignup(array $token_data): void
+	{
+		if (!array_key_exists('email', $token_data) || !array_key_exists('name', $token_data)) {
+			JVB()->error()->log('[MagicLinkManager]Could not process Referral Signup');
+			return;
+		}
+
+		$email = sanitize_email($token_data['email']);
+		if (email_exists($email)) {
+			wp_die('Looks like you already have an account!');
+		}
+		$role = JVB()->referrals()->getRole();
+		$pass = wp_generate_password(20, true, true);
+		$name = sanitize_text_field($token_data['name']);
+		$user_id = wp_insert_user([
+			'user_login' 	=> $email,
+			'user_email' 	=> $email,
+			'user_pass'		=> $pass,
+			'display_name'	=> $name,
+			'role'			=> $role
+		]);
+		if (!is_wp_error($user_id)) {
+			$response = JVB()->routes('login')->login($email, $pass, true);
+			if ($response) {
+				wp_safe_redirect(home_url('/dash?welcome=1&referral=1'));
+				exit;
+			}
+		} else {
+			JVB()->error()->log(
+				'[MagicLinkManager]',
+				$user_id->get_error_message(),
+				$token_data
+			);
+		}
+	}
+
+	/**
+	 * Process password reset via magic link
 	 */
 	protected function processPasswordReset(array $token_data): void
 	{
-		// Redirect to password reset form with token
-		wp_safe_redirect(add_query_arg([
-			'action' => 'rp',
-			'key' => $token_data['token'], // Could use magic token or generate WP reset key
-			'login' => $token_data['email']
-		], wp_login_url()));
+		$user = get_user_by('ID', $token_data['user_id']);
+
+		if (!$user) {
+			wp_die('Invalid user');
+		}
+
+		// Log user in and redirect to password change page
+		wp_set_current_user($user->ID);
+		wp_set_auth_cookie($user->ID, true);
+
+		wp_safe_redirect(admin_url('profile.php?password_reset=1'));
 		exit;
 	}
 
 	/**
-	 * Generate a secure token
-	 */
-	protected function generateToken(string $email, string $type, array $data): string
-	{
-		// Create unique token
-		$token = wp_generate_password(64, false, false);
-
-		// Store token data in transient
-		$token_data = [
-			'email' => $email,
-			'type' => $type,
-			'created_at' => time(),
-			'expires_at' => time() + $this->token_expiry,
-			'data' => $data
-		];
-
-		$cache_key = 'magic_token_' . $token;
-		set_transient($cache_key, $token_data, $this->token_expiry);
-
-		// Also index by email for rate limiting
-		$this->recordTokenGeneration($email);
-
-		return $token;
-	}
-
-	/**
-	 * Verify a magic link token
-	 */
-	protected function verifyToken(string $token, string $email)
-	{
-		// Retrieve token data
-		$cache_key = 'magic_token_' . $token;
-		$token_data = get_transient($cache_key);
-
-		if (!$token_data) {
-			return new WP_Error('expired_token', 'This link has expired. Please request a new one.');
-		}
-
-		// Verify email matches
-		if ($token_data['email'] !== $email) {
-			return new WP_Error('invalid_token', 'Invalid magic link');
-		}
-
-		// Check expiration
-		if (time() > $token_data['expires_at']) {
-			delete_transient($cache_key);
-			return new WP_Error('expired_token', 'This link has expired. Please request a new one.');
-		}
-
-		// Token is valid - delete it (single use)
-		delete_transient($cache_key);
-
-		// Return merged data
-		return array_merge($token_data['data'], [
-			'email' => $token_data['email'],
-			'type' => $token_data['type']
-		]);
-	}
-
-	/**
-	 * Rate limiting for magic link generation
-	 */
-	protected function checkRateLimit(string $email):bool|WP_Error
-	{
-		$limit_key = 'magic_link_limit_' . md5($email);
-		$attempts = (int) get_transient($limit_key);
-
-		if ($attempts >= $this->max_attempts_per_hour) {
-			return new WP_Error(
-				'rate_limit_exceeded',
-				'Too many login attempts. Please try again in an hour.'
-			);
-		}
-
-		return true;
-	}
-
-	/**
-	 * Record token generation for rate limiting
-	 */
-	protected function recordTokenGeneration(string $email): void
-	{
-		$limit_key = 'magic_link_limit_' . md5($email);
-		$attempts = (int) get_transient($limit_key);
-		set_transient($limit_key, $attempts + 1, $this->rate_limit_window);
-	}
-
-	/**
-	 * Handle invalid/expired tokens
+	 * Handle invalid token
 	 */
 	protected function handleInvalidToken(WP_Error $error): void
 	{
-		wp_die(
-			$error->get_error_message(),
-			'Invalid Link',
-			[
-				'response' => 400,
-				'back_link' => true
-			]
-		);
+		wp_die($error->get_error_message());
 	}
 
 	/**
-	 * Add "Send me a magic link" option to login form
+	 * Handle failed login - offer magic link option
 	 */
-	public function addMagicLinkOption(): void
+	public function handleFailedLogin(string $username): void
 	{
-		?>
-		<p class="magic-link-option">
-			<a href="#" id="use-magic-link">Send me a login link instead</a>
-		</p>
-		<script>
-			document.getElementById('use-magic-link')?.addEventListener('click', function(e) {
-				e.preventDefault();
-				const email = document.getElementById('user_login')?.value;
-
-				if (!email) {
-					alert('Please enter your email address first');
-					return;
-				}
-
-				// Send magic link request
-				fetch('<?php echo rest_url(BASE . '/v1/magic-link/send'); ?>', {
-					method: 'POST',
-					headers: {
-						'Content-Type': 'application/json',
-					},
-					body: JSON.stringify({
-						email: email,
-						type: 'login'
-					})
-				})
-					.then(r => r.json())
-					.then(data => {
-						if (data.success) {
-							alert('Check your email! We sent you a login link.');
-						} else {
-							alert(data.message || 'Failed to send link');
-						}
-					});
-			});
-		</script>
-		<?php
+		// Could add logic here to automatically offer magic link
+		// after multiple failed attempts
 	}
 
 	/**
-	 * Optionally block standard password auth for certain users
+	 * Optionally block standard password auth for magic-link-only users
 	 */
 	public function blockStandardAuth($user, $username, $password)
 	{
-		// Only block if user has magic-link-only flag
 		if ($user instanceof WP_User) {
 			$magic_only = get_user_meta($user->ID, BASE . 'magic_link_only', true);
 			if ($magic_only) {
@@ -584,59 +507,54 @@
 
 	protected function getLoginEmailTemplate(string $name, string $magic_url): string
 	{
-		$content = '<h2>Hey ' . esc_html($name) . '!</h2>';
-		$content .= '<p>Click the button below to sign in to your account. This link expires in 15 minutes.</p>';
-		$content .= '<p style="text-align: center; margin: 30px 0;">';
-		$content .= '<a href="' . $magic_url . '" style="background: #2271b1; color: #fff; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">Sign In</a>';
-		$content .= '</p>';
-		$content .= '<p style="color: #666; font-size: 14px;">If you didn\'t request this, you can safely ignore this email.</p>';
-
+		$content = JVB()->email()->h2('Hey ' . esc_html($name) . '!');
+		$content .= '<p>Click the button below to sign in to your account instantly - no password needed!</p>';
+		$content .= JVB()->email()->button($magic_url, 'Sign In Now');
+		$content .= '<p>Or copy and paste this link into your browser:</p>';
+		$content .= JVB()->email()->link($magic_url);
+		$content .= JVB()->email()->divider();
+		$content .= '<p>If you didn\'t request this, you can safely ignore this email. This link expires in 15 minutes.</p>';
 		return $content;
 	}
 
 	protected function getSignupEmailTemplate(string $name, string $magic_url): string
 	{
-		$content = '<h2>Welcome' . ($name ? ', ' . esc_html($name) : '') . '!</h2>';
-		$content .= '<p>You\'re almost there! Click the button below to complete your registration and access your account.</p>';
-		$content .= '<p style="text-align: center; margin: 30px 0;">';
-		$content .= '<a href="' . $magic_url . '" style="background: #2271b1; color: #fff; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">Complete Registration</a>';
-		$content .= '</p>';
-		$content .= '<p style="color: #666; font-size: 14px;">This link expires in 15 minutes.</p>';
-
+		$content = JVB()->email()->h2('Welcome' . ($name ? ', ' . esc_html($name) : '') . '!');
+		$content .= '<p>Click the button below to complete your registration and access your account!</p>';
+		$content .= JVB()->email()->button($magic_url, 'Complete Registration');
+		$content .= '<p>Or copy and paste this link:</p>';
+		$content .= JVB()->email()->link($magic_url);
+		$content .= JVB()->email()->spacer(10);
+		$content .= '<p><small>This link expires in 24 hours.</small></p>';
 		return $content;
 	}
 
-	protected function getReferralEmailTemplate(string $name, string $referrer_name, string $magic_url, string $reward_text): string
+	protected function getReferralEmailTemplate(string $name, string $referrer_name, string $magic_url, string $reward_text, array $context): string
 	{
-		$content = '<h2>Hey' . ($name ? ' ' . esc_html($name) : '') . '!</h2>';
-		$content .= '<p><strong>' . esc_html($referrer_name) . '</strong> thinks you\'d love ' . get_bloginfo('name') . ' and invited you to join!</p>';
+		$content = JVB()->email()->h2('Hey' . ($name ? ' ' . esc_html($name) : '') . '!');
+		$content .= sprintf(
+			'<p><strong>%s</strong> thinks you\'d love %s!</p>',
+			esc_html($referrer_name),
+			esc_html(get_bloginfo('name'))
+		);
 
-		if ($reward_text) {
-			$content .= '<div style="background: #e7f5ff; padding: 20px; border-radius: 8px; margin: 20px 0;">';
-			$content .= '<h3 style="margin-top: 0;">🎉 Special Offer</h3>';
-			$content .= '<p>' . esc_html($reward_text) . '</p>';
-			$content .= '</div>';
+		if (!empty($context['message'])) {
+			$content .= JVB()->email()->callout(nl2br(esc_html($context['message'])));
 		}
 
-		$content .= '<p style="text-align: center; margin: 30px 0;">';
-		$content .= '<a href="' . $magic_url . '" style="background: #2271b1; color: #fff; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">Accept Invitation</a>';
-		$content .= '</p>';
-		$content .= '<p style="color: #666; font-size: 14px;">This link expires in 15 minutes.</p>';
+		if ($reward_text) {
+			$content .= JVB()->email()->alert(
+				'<strong>Special Welcome Offer:</strong> ' . esc_html($reward_text),
+				'success'
+			);
+		}
 
-		return $content;
-	}
-
-	protected function getResetEmailTemplate(string $name, string $magic_url): string
-	{
-		$content = '<h2>Reset Your Password</h2>';
-		$content .= '<p>Hey ' . esc_html($name) . ', we received a request to reset your password.</p>';
-		$content .= '<p style="text-align: center; margin: 30px 0;">';
-		$content .= '<a href="' . $magic_url . '" style="background: #2271b1; color: #fff; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">Reset Password</a>';
-		$content .= '</p>';
-		$content .= '<p style="color: #666; font-size: 14px;">If you didn\'t request this, you can safely ignore this email.</p>';
+		$content .= JVB()->email()->button($magic_url, 'Join Now');
+		$content .= '<p>Or copy and paste this link:</p>';
+		$content .= JVB()->email()->link($magic_url);
+		$content .= JVB()->email()->spacer(10);
+		$content .= '<p><small>This invitation expires in 14 days.</small></p>';
 
 		return $content;
 	}
 }
-
-new MagicLinkManager();

--
Gitblit v1.10.0