Jake Vanderwerf
2026-08-25 3d25ad7de4fdbb3eba2cde2a62422e6be5d79a0a
inc/managers/MagicLinks.php
File was renamed from inc/managers/MagicLinkManager.php
@@ -3,6 +3,8 @@
use JetBrains\PhpStorm\NoReturn;
use JVBase\base\Site;
use JVBase\Instance;
use JVBase\integrations\services\Cloudflare;
use JVBase\meta\Form;
use JVBase\ui\Tabs;
use WP_User;
@@ -18,10 +20,12 @@
 * NOTE: Login form integration is now handled by LoginManager.php
 * This class focuses solely on magic link generation and verification
 */
class MagicLinkManager
class MagicLinks
{
   use Instance;
   protected Cache $cache;
   protected Cache $referral_cache;
   protected Cache $rateLimitCache;
   // Token settings
   protected int $token_expiry = 900; // 15 minutes in seconds
@@ -36,8 +40,9 @@
   public function __construct()
   {
      $this->cache = Cache::for('magic_links', $this->token_expiry);
      $this->referral_cache = Cache::for('referral_magic_links', 14 * DAY_IN_SECONDS);
      $this->cache = Cache::for('magic_links',null, $this->token_expiry);
      $this->referral_cache = Cache::for('referral_magic_links', null, 14 * DAY_IN_SECONDS);
      $this->rateLimitCache = Cache::for('magic_link_rate_limit', null, $this->rate_limit_window);
      // Hook into WordPress auth flow
      add_action('template_redirect', [$this, 'handleMagicLinkClick']);
@@ -145,20 +150,15 @@
    */
   protected function checkRateLimit(string $email): bool|WP_Error
   {
      $cache_key = 'rate_limit_' . md5($email);
      $attempts = $this->cache->get($cache_key);
      $key = md5($email);
      $attempts = $this->rateLimitCache->get($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()];
         $attempts = 1;
      }
      // Check if limit exceeded
      if ($attempts['count'] >= $this->max_attempts_per_hour) {
      if ($attempts >= $this->max_attempts_per_hour) {
         return new WP_Error(
            'rate_limit_exceeded',
            'Too many magic link requests. Please try again in an hour.'
@@ -166,8 +166,8 @@
      }
      // Increment counter
      $attempts['count']++;
      $this->cache->set($cache_key, $attempts, $this->rate_limit_window);
      $attempts++;
      $this->rateLimitCache->set($key, $attempts);
      return true;
   }
@@ -200,7 +200,7 @@
      $subject = 'Sign in to ' . get_bloginfo('name');
      $message = $this->getLoginEmailTemplate($user->display_name, $magic_url);
      $sent = JVB()->email()->sendEmail($email, $subject, $message, 'Log in to '. get_bloginfo('name'));
      $sent = Emails::getInstance()->sendEmail($email, $subject, $message, 'Log in to '. get_bloginfo('name'));
      return $sent ? true : new WP_Error('email_failed', 'Failed to send magic link');
   }
@@ -232,7 +232,7 @@
      $subject = 'Complete your ' . get_bloginfo('name') . ' registration';
      $message = $this->getSignupEmailTemplate($context['name'] ?? '', $magic_url);
      $sent = JVB()->email()->sendEmail($email, $subject, $message, 'Complete Registration');
      $sent = Emails::getInstance()->sendEmail($email, $subject, $message, 'Complete Registration');
      return $sent ? true : new WP_Error('email_failed', 'Failed to send signup link');
   }
@@ -267,7 +267,7 @@
      $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);
      $sent = JVB()->email()->sendEmail($email, $subject, $message, 'Accept Invitation');
      $sent = Emails::getInstance()->sendEmail($email, $subject, $message, 'Accept Invitation');
      return $sent ? true : new WP_Error('email_failed', 'Failed to send referral link');
   }
@@ -295,7 +295,7 @@
      $subject = 'Reset your password';
      $message = $this->getResetEmailTemplate($user->display_name, $magic_url);
      $sent = JVB()->email()->sendEmail($email, $subject, $message, 'Reset Password');
      $sent = Emails::getInstance()->sendEmail($email, $subject, $message, 'Reset Password');
      return $sent ? true : new WP_Error('email_failed', 'Failed to send reset link');
   }
@@ -436,7 +436,7 @@
         $this->processSignup($token_data);
      }
      $role = JVB()->referrals()->getRole();
      $role = Referrals::getInstance()->getRole();
      $pass = wp_generate_password(20, true, true);
      $name = sanitize_text_field($token_data['name']);
      $user_id = wp_insert_user([
@@ -515,31 +515,31 @@
   protected function getLoginEmailTemplate(string $name, string $magic_url): string
   {
      $content = JVB()->email()->h2('Hey ' . esc_html($name) . '!');
      $content = Emails::getInstance()->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 .= Emails::getInstance()->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 .= Emails::getInstance()->link($magic_url);
      $content .= Emails::getInstance()->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 = JVB()->email()->h2('Welcome' . ($name ? ', ' . esc_html($name) : '') . '!');
      $content = Emails::getInstance()->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 .= Emails::getInstance()->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 .= Emails::getInstance()->link($magic_url);
      $content .= Emails::getInstance()->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, array $context): string
   {
      $content = JVB()->email()->h2('Hey' . ($name ? ' ' . esc_html($name) : '') . '!');
      $content = Emails::getInstance()->h2('Hey' . ($name ? ' ' . esc_html($name) : '') . '!');
      $content .= sprintf(
         '<p><strong>%s</strong> thinks you\'d love %s!</p>',
         esc_html($referrer_name),
@@ -547,20 +547,20 @@
      );
      if (!empty($context['message'])) {
         $content .= JVB()->email()->callout(nl2br(esc_html($context['message'])));
         $content .= Emails::getInstance()->callout(nl2br(esc_html($context['message'])));
      }
      if ($reward_text) {
         $content .= JVB()->email()->alert(
         $content .= Emails::getInstance()->alert(
            '<strong>Special Welcome Offer:</strong> ' . esc_html($reward_text),
            'success'
         );
      }
      $content .= JVB()->email()->button($magic_url, 'Join Now');
      $content .= Emails::getInstance()->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 .= Emails::getInstance()->link($magic_url);
      $content .= Emails::getInstance()->spacer(10);
      $content .= '<p><small>This invitation expires in 14 days.</small></p>';
      return $content;
@@ -569,7 +569,7 @@
   public function renderForm():string
   {
      ob_start();
      JVB()->connect('cloudflare')->renderTurnstile();
      Cloudflare::getInstance()->renderTurnstile();
      $turnstile = ob_get_clean();
      global $wp;
@@ -599,7 +599,7 @@
//       wp_login_url()
      );
       $login = LoginManager::getInstance()->renderLoginForm('login', get_home_url(null,'/'.$wp->request));
       $login = Login::getInstance()->renderLoginForm('login', get_home_url(null,'/'.$wp->request));
       $tabs = new Tabs();
       $tabs->addTab('magic')