Jake Vanderwerf
2025-11-04 42fa8304ddb811b0f725f245130f70c0f5e86a6c
inc/managers/ReferralManager.php
@@ -40,7 +40,7 @@
   {
      global $wpdb;
      $this->wpdb = $wpdb;
      $this->cache = new CacheManager('referrals');
      $this->cache = CacheManager::for('referrals', WEEK_IN_SECONDS);
      $this->referrals_table = BASE . 'referrals';
      $this->rewards_table = BASE . 'referral_rewards';
      $this->magic_link = new MagicLinkManager();
@@ -64,6 +64,21 @@
      add_action('wp_enqueue_scripts', [$this, 'enqueueScripts']);
      // Schedule cron jobs for reports
      $this->registerCronJobs();
      // Register admin subpage
      add_filter('jvbAdminSubpages', [$this, 'addSubpage'], 10, 1);
      // Add admin bar label for referral page
      add_action('admin_bar_menu', [$this, 'addReferralPageLabel'], 999);
      // Add admin notice to referral page edit screen
      add_action('admin_notices', [$this, 'showReferralPageNotice']);
      add_filter('jvbDashboardPage', [$this, 'renderDashPage'], 10, 2);
      // Handle settings save
      add_action('admin_init', [$this, 'registerSettings']);
   }
   public function enqueueScripts():void
@@ -887,7 +902,7 @@
      $content .= '</aside>';
      $actions[] =[
         'button' => '<button type="button" class="toggle-referral row" title="Your Referrals" data-action="toggle-referral" aria-label="Open Referral Sidebar" aria-controls="referral" aria-expanded="false">
         'button' => '<button type="button" class="attn toggle-referral row" title="Your Referrals" data-action="toggle-referral" aria-label="Open Referral Sidebar" aria-controls="referral" aria-expanded="false">
               '.jvbIcon('hand-heart').'<span class="screen-reader-text"></span>
            </button>',
         'content'   => $content
@@ -1447,5 +1462,352 @@
      return $csv_content;
   }
   /**
    * Add referral settings subpage to admin menu
    *
    * @param array $subpages
    * @return array
    */
   public function addSubpage(array $subpages): array
   {
      $subpages[] = [
         'page_title' => 'Referral Settings',
         'menu_title' => 'Referrals',
         'capability' => 'manage_options',
         'menu_slug'  => 'jvb-referrals',
         'callback'   => [$this, 'renderAdminPage'],
         'icon'       => 'users',
      ];
      return $subpages;
   }
   /**
    * Register settings
    */
   public function registerSettings(): void
   {
      register_setting(
         BASE . 'referral_settings',
         BASE . 'referral_page_id',
         [
            'type' => 'integer',
            'sanitize_callback' => 'absint',
            'default' => 0
         ]
      );
      register_setting(
         BASE . 'referral_settings',
         BASE . 'referral_reward_settings',
         [
            'type' => 'array',
            'sanitize_callback' => [$this, 'sanitizeRewardSettings'],
            'default' => $this->default_settings
         ]
      );
   }
   /**
    * Sanitize reward settings
    */
   public function sanitizeRewardSettings(array $settings): array
   {
      return [
         'referrer_reward_applies_to' => in_array($settings['referrer_reward_applies_to'] ?? '', ['per_user', 'flat_total'])
            ? $settings['referrer_reward_applies_to']
            : 'per_user',
         'referrer_reward_amount' => floatval($settings['referrer_reward_amount'] ?? 25.00),
         'referrer_reward_type' => in_array($settings['referrer_reward_type'] ?? '', ['fixed', 'percentage'])
            ? $settings['referrer_reward_type']
            : 'fixed',
         'referee_reward_type' => in_array($settings['referee_reward_type'] ?? '', ['percentage', 'fixed'])
            ? $settings['referee_reward_type']
            : 'percentage',
         'referee_reward_amount' => floatval($settings['referee_reward_amount'] ?? 20),
         'referee_reward_applies_to' => in_array($settings['referee_reward_applies_to'] ?? '', ['first_order', 'all_orders'])
            ? $settings['referee_reward_applies_to']
            : 'first_order',
      ];
   }
   /**
    * Render the admin settings page
    */
   public function renderAdminPage(): void
   {
      // Handle form submission
      if (isset($_POST['submit']) && check_admin_referer(BASE . 'referral_settings_nonce')) {
         update_option(BASE . 'referral_page_id', absint($_POST[BASE . 'referral_page_id'] ?? 0));
         $reward_settings = [
            'referrer_reward_applies_to' => sanitize_text_field($_POST['referrer_reward_applies_to'] ?? 'per_user'),
            'referrer_reward_amount' => floatval($_POST['referrer_reward_amount'] ?? 25.00),
            'referrer_reward_type' => sanitize_text_field($_POST['referrer_reward_type'] ?? 'fixed'),
            'referee_reward_type' => sanitize_text_field($_POST['referee_reward_type'] ?? 'percentage'),
            'referee_reward_amount' => floatval($_POST['referee_reward_amount'] ?? 20),
            'referee_reward_applies_to' => sanitize_text_field($_POST['referee_reward_applies_to'] ?? 'first_order'),
         ];
         update_option(BASE . 'referral_reward_settings', $this->sanitizeRewardSettings($reward_settings));
         echo '<div class="notice notice-success is-dismissible"><p>Settings saved successfully.</p></div>';
      }
      $referral_page_id = $this->getReferralPageId();
      $settings = $this->getRewardSettings();
      echo $this->renderAdminHTML();
   }
   protected function renderAdminHTML():string
   {
      ob_start();
      ?>
      <div class="wrap">
         <h1>Referral Settings</h1>
         <form method="post" action="">
            <?php wp_nonce_field(BASE . 'referral_settings_nonce'); ?>
            <div class="card">
               <h2>Referral Page</h2>
               <p>Select the page where users can access their referral dashboard.</p>
               <table class="form-table">
                  <tr>
                     <th scope="row">
                        <label for="<?= BASE ?>referral_page_id">Referral Page</label>
                     </th>
                     <td>
                        <?php
                        wp_dropdown_pages([
                           'name' => BASE . 'referral_page_id',
                           'id' => BASE . 'referral_page_id',
                           'selected' => $referral_page_id,
                           'show_option_none' => __('— Select —', 'jvbase'),
                           'option_none_value' => '0'
                        ]);
                        ?>
                        <p class="description">
                           This page will show "Referral Page" in the admin bar when editing.
                        </p>
                     </td>
                  </tr>
               </table>
            </div>
            <div class="card">
               <h2>Reward Settings</h2>
               <table class="form-table">
                  <tr>
                     <th colspan="2"><h3>Referrer Rewards</h3></th>
                  </tr>
                  <tr>
                     <th scope="row">
                        <label for="referrer_reward_type">Reward Type</label>
                     </th>
                     <td>
                        <select name="referrer_reward_type" id="referrer_reward_type">
                           <option value="fixed" <?php selected($settings['referrer_reward_type'], 'fixed'); ?>>Fixed Amount</option>
                           <option value="percentage" <?php selected($settings['referrer_reward_type'], 'percentage'); ?>>Percentage</option>
                        </select>
                     </td>
                  </tr>
                  <tr>
                     <th scope="row">
                        <label for="referrer_reward_amount">Reward Amount</label>
                     </th>
                     <td>
                        <input type="number"
                              name="referrer_reward_amount"
                              id="referrer_reward_amount"
                              value="<?= esc_attr($settings['referrer_reward_amount']) ?>"
                              step="0.01"
                              min="0">
                        <p class="description">Amount in dollars or percentage</p>
                     </td>
                  </tr>
                  <tr>
                     <th scope="row">
                        <label for="referrer_reward_applies_to">Applies To</label>
                     </th>
                     <td>
                        <select name="referrer_reward_applies_to" id="referrer_reward_applies_to">
                           <option value="per_user" <?php selected($settings['referrer_reward_applies_to'], 'per_user'); ?>>Per User Referred</option>
                           <option value="flat_total" <?php selected($settings['referrer_reward_applies_to'], 'flat_total'); ?>>Flat Total</option>
                        </select>
                     </td>
                  </tr>
                  <tr>
                     <th colspan="2"><h3>Referee (New User) Rewards</h3></th>
                  </tr>
                  <tr>
                     <th scope="row">
                        <label for="referee_reward_type">Reward Type</label>
                     </th>
                     <td>
                        <select name="referee_reward_type" id="referee_reward_type">
                           <option value="percentage" <?php selected($settings['referee_reward_type'], 'percentage'); ?>>Percentage</option>
                           <option value="fixed" <?php selected($settings['referee_reward_type'], 'fixed'); ?>>Fixed Amount</option>
                        </select>
                     </td>
                  </tr>
                  <tr>
                     <th scope="row">
                        <label for="referee_reward_amount">Reward Amount</label>
                     </th>
                     <td>
                        <input type="number"
                              name="referee_reward_amount"
                              id="referee_reward_amount"
                              value="<?= esc_attr($settings['referee_reward_amount']) ?>"
                              step="0.01"
                              min="0">
                        <p class="description">Amount in dollars or percentage</p>
                     </td>
                  </tr>
                  <tr>
                     <th scope="row">
                        <label for="referee_reward_applies_to">Applies To</label>
                     </th>
                     <td>
                        <select name="referee_reward_applies_to" id="referee_reward_applies_to">
                           <option value="first_order" <?php selected($settings['referee_reward_applies_to'], 'first_order'); ?>>First Order Only</option>
                           <option value="all_orders" <?php selected($settings['referee_reward_applies_to'], 'all_orders'); ?>>All Orders</option>
                        </select>
                     </td>
                  </tr>
               </table>
            </div>
            <p class="submit">
               <button type="submit" name="submit" class="button button-primary">Save Settings</button>
            </p>
         </form>
         <?= $this->renderReferralStats(true) ?>
      </div>
      <?php
      return ob_get_clean();
   }
   /**
    * Render referral statistics
    */
   protected function renderReferralStats(bool $wrapCard = false):string
   {
      ob_start();
      global $wpdb;
      $total_referrals = $wpdb->get_var("SELECT COUNT(*) FROM {$this->referrals_table}");
      $pending_referrals = $wpdb->get_var("SELECT COUNT(*) FROM {$this->referrals_table} WHERE status = 'pending'");
      $treated_referrals = $wpdb->get_var("SELECT COUNT(*) FROM {$this->referrals_table} WHERE status = 'treated'");
      ?>
      <table class="widefat">
         <tr>
            <th>Total Referrals</th>
            <td><?= esc_html($total_referrals) ?></td>
         </tr>
         <tr>
            <th>Pending</th>
            <td><?= esc_html($pending_referrals) ?></td>
         </tr>
         <tr>
            <th>Treated</th>
            <td><?= esc_html($treated_referrals) ?></td>
         </tr>
      </table>
      <?php
      $table = ob_get_clean();
      if ($wrapCard) {
         $table = '<div class="card">
            <h2>Referral Statistics</h2>
            '.$table.'
         </div>';
      }
      return $table;
   }
   /**
    * Add "Referral Page" label to admin bar
    *
    * @param WP_Admin_Bar $wp_admin_bar
    */
   public function addReferralPageLabel($wp_admin_bar): void
   {
      if (!is_admin()) {
         return;
      }
      $referral_page_id = $this->getReferralPageId();
      if (!$referral_page_id) {
         return;
      }
      global $pagenow, $post;
      // Check if we're editing the referral page
      if ('post.php' === $pagenow && $post && $post->ID === $referral_page_id) {
         $wp_admin_bar->add_node([
            'id' => 'referral-page',
            'parent' => 'top-secondary',
            'title' => __('Referral Page', 'jvbase'),
            'meta' => [
               'class' => 'referral-page-notice'
            ]
         ]);
      }
   }
   /**
    * Get the referral page ID
    *
    * @return int|null
    */
   public function getReferralPageId(): ?int
   {
      $page_id = get_option(BASE . 'referral_page_id');
      return $page_id ? (int) $page_id : null;
   }
   /**
    * Show admin notice on referral page edit screen
    */
   public function showReferralPageNotice(): void
   {
      global $pagenow, $post;
      if ('post.php' !== $pagenow || !$post) {
         return;
      }
      $referral_page_id = $this->getReferralPageId();
      if ($post->ID === $referral_page_id) {
         echo '<div class="notice notice-info">';
         echo '<p>' . __('This page is designated as the <strong>Referral Page</strong>.', 'jvbase') . '</p>';
         echo '</div>';
      }
   }
   public function renderDashPage(string $content, string $page):string
   {
      if ($page !== 'referrals') {
         return $content;
      }
      $out = '';
      if (current_user_can('manage_options')) {
         $out .= $this->renderAdminHTML();
      } else {
         $out .= $this->renderReferralStats(true);
      }
      return ($out === '') ? $content : '<form id="referrals" class="col" data-save="referrals">'.$out.'</form>';
   }
}