Jake Vanderwerf
2026-01-25 b38f03c0e7218762d90fa5092696b127f24f36db
inc/managers/NotificationManager.php
@@ -20,7 +20,11 @@
 */
class NotificationManager
{
    protected object $cache;
    protected Cache $userCache; //the individual notifications
    protected Cache $contentCache;  //the 'shared' notifications on new content that has been created
   protected Cache $artistsCache;
   protected Cache $favouritesCache;
   protected Cache $followerCache;
    protected string $campaign;
   protected string $table = BASE.'notifications';
   protected string $contentTable = BASE.'notifications_content';
@@ -139,7 +143,11 @@
     */
    public function __construct()
    {
        $this->cache = CacheManager::for('notifications', WEEK_IN_SECONDS);
        $this->userCache = Cache::for('userNotifications', WEEK_IN_SECONDS);
        $this->contentCache = Cache::for('contentNotifications', WEEK_IN_SECONDS)->connect('post', true)->connect('taxonomy', true);
        $this->artistsCache = Cache::for('artist', WEEK_IN_SECONDS)->connect('post');
        $this->favouritesCache = Cache::for('favouritedUsers', WEEK_IN_SECONDS)->connect('favourites');
        $this->followerCache = Cache::for('totalFollowers', WEEK_IN_SECONDS)->connect('favourites');
        // Add filter for bulk operation handling
        add_filter(BASE . 'handle_bulk_operation', [ $this, 'processOperation' ], 10, 3);
@@ -364,7 +372,7 @@
     */
    public function notifyVerifiedArtists(string $type, int|null $action_user_id = null, string $message = '', int|null $target_id = null, string|null $target_type = null, array|null $context = null):bool|WP_Error
    {
        $artists = $this->getVerifiedArtists();
        $artists = $this->getVerified('artist');
        return $this->addNotification($artists, $type, $action_user_id, $message, $target_id, $target_type, $context);
    }
    /**
@@ -381,7 +389,7 @@
     */
    public function notifyVerifiedPartners(string $type, int|null $action_user_id = null, string $message = '', int|null $target_id = null, string|null $target_type = null, array|null $context = null):bool|WP_Error
    {
        $artists = $this->getVerifiedPartners();
        $artists = $this->getVerified('partner');
        return $this->addNotification($artists, $type, $action_user_id, $message, $target_id, $target_type, $context);
    }
    /**
@@ -398,7 +406,7 @@
     */
    public function notifyEnthusiasts(string $type, int|null $action_user_id = null, string $message = '', int|null $target_id = null, string|null $target_type = null, array|null $context = null):bool|WP_Error
    {
        $artists = $this->getEnthusiasts();
        $artists = $this->getUserIDs('enthusiast');
        return $this->addNotification($artists, $type, $action_user_id, $message, $target_id, $target_type, $context);
    }
    /**
@@ -415,7 +423,7 @@
     */
    public function notifyEveryone(string $type, int|null $action_user_id = null, string $message = '', int|null $target_id = null, string|null $target_type = null, array|null $context = null):bool|WP_Error
    {
        $artists = $this->getEveryone();
        $artists = $this->getUserIDs(array_keys(JVB_USER));
        return $this->addNotification($artists, $type, $action_user_id, $message, $target_id, $target_type, $context);
    }
@@ -1100,7 +1108,7 @@
        }
        $content = '';
        $cache   = CacheManager::for('digest_content', HOUR_IN_SECONDS * 6); // Cache for 6 hours
        $cache   = Cache::for('digest_content', HOUR_IN_SECONDS * 6); // Cache for 6 hours
        // Group updates by artist
        $updates_by_artist = [];
@@ -1519,19 +1527,16 @@
    protected function getArtistData(int $user_id):array|false
    {
        // Try to get from cache
        $cache_key = "artist_data_{$user_id}";
        $cached = $this->cache->get($cache_key);
      $artist_id = get_user_meta($user_id, BASE . 'link', true);
      if (!$artist_id || $artist_id === '') {
         return false;
      }
        $cached = $this->artistsCache->get($artist_id);
        if ($cached !== false) {
            return $cached;
        }
        // Get artist post ID from user meta
        $artist_id = get_user_meta($user_id, BASE . 'link', true);
        if (!$artist_id) {
            return false;
        }
        // Get basic artist data
        $artist_post = get_post($artist_id);
        if (!$artist_post) {
@@ -1548,7 +1553,7 @@
        ];
        // Cache the result
        $this->cache->set($cache_key, $data, null,'artists');
        $this->artistsCache->set($artist_id, $data);
        return $data;
    }
@@ -1560,19 +1565,25 @@
     */
    protected function getFollowedArtists(int $user_id):array
    {
        global $wpdb;
        $favourites_table = $wpdb->prefix . BASE . 'favourites';
      return $this->favouritesCache->remember(
         $user_id,
         function() use ($user_id) {
            global $wpdb;
            $favourites_table = $wpdb->prefix . BASE . 'favourites';
        // Get artists this user has favourited
        return $wpdb->get_col($wpdb->prepare(
            "SELECT f.target_id
         FROM {$favourites_table} f
         JOIN {$wpdb->posts} p ON f.target_id = p.ID
         WHERE f.user_id = %d
         AND f.type = 'artist'
         AND p.post_status = 'publish'",
            $user_id
        ));
            // Get artists this user has favourited
            return $wpdb->get_col($wpdb->prepare(
            "SELECT f.target_id
                FROM {$favourites_table} f
                JOIN {$wpdb->posts} p ON f.target_id = p.ID
                WHERE f.user_id = %d
                AND f.type = 'artist'
                AND p.post_status = 'publish'",
               $user_id
            ));
         }
      );
    }
    /**
@@ -1582,15 +1593,21 @@
     */
    protected function getFollowerCount(int $artist_id):int
    {
        global $wpdb;
        $favourites_table = $wpdb->prefix . BASE . 'favourites';
      return $this->followerCache->remember(
         $artist_id,
         function() use ($artist_id) {
            global $wpdb;
            $favourites_table = $wpdb->prefix . BASE . 'favourites';
        return $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(DISTINCT user_id)
         FROM {$favourites_table}
         WHERE target_id = %d AND type = 'artist'",
            $artist_id
        ));
            return $wpdb->get_var($wpdb->prepare(
               "SELECT COUNT(DISTINCT user_id)
                FROM {$favourites_table}
                WHERE target_id = %d AND type = 'artist'",
               $artist_id
            ));
         }
      );
    }
    /**
@@ -1598,27 +1615,16 @@
     *
     * @return string
     */
    protected function pluralize(string $word):string
    protected function pluralize(string $content):string
    {
        $irregular = [
            'tattoo' => 'tattoos',
            'piercing' => 'piercings',
            'artwork' => 'artwork',
            'news' => 'news',
            'offer' => 'offers',
            'event' => 'events'
        ];
        if (isset($irregular[$word])) {
            return $irregular[$word];
        }
        // Simple pluralization rules
        if (str_ends_with($word, 'y')) {
            return substr($word, 0, -1) . 'ies';
        }
        return $word . 's';
        if (array_key_exists($content, JVB_CONTENT)) {
         return JVB_CONTENT[$content]['plural'];
      } elseif (array_key_exists($content, JVB_TAXONOMY)) {
         return JVB_TAXONOMY[$content]['plural'];
      } elseif (array_key_exists($content, JVB_USER)) {
         return JVB_USER[$content]['plural'];
      }
      return $content;
    }
    /**
@@ -1628,9 +1634,8 @@
     */
    protected function clearNotificationCache(int $user_id):void
    {
        $this->cache->delete("user_{$user_id}_notifications_", 'notifications_' . $user_id);
        $this->cache->delete("user_{$user_id}_content_notifications_", 'notifications_' . $user_id);
      $this->userCache->forget($user_id);
      $this->contentCache->forget($user_id);
    }
    /**
@@ -1697,78 +1702,56 @@
    /**
     * @return array
     */
    protected function getVerifiedArtists():array
    protected function getVerified(string|array $userRoles):array
    {
        $artists = $this->cache->get('verified_artists');
        if ($artists) {
            return $artists;
        }
      $userRoles = $this->checkRoles($userRoles);
        $artists = get_users([
            'role'          => BASE.'artist',
            'capability'    => 'skip_moderation',
            'fields'        => 'ID'
        ]);
        $this->cache->set('verified_artists', $artists);
        return $artists;
      if (empty($userRoles)) {
         return [];
      }
      $cache = Cache::for('verifiedUsers', DAY_IN_SECONDS)->connect('user',true);
      return $cache->remember(
         'verified',
         function() use ($userRoles) {
            return get_users([
               'role'          => $userRoles,
               'capability'    => 'skip_moderation',
               'fields'        => 'ID'
            ]);
         }
      );
    }
    /**
     * @return array
     */
    protected function getVerifiedPartners():array
    {
        $partners = $this->cache->get('verified_partners');
        if ($partners) {
            return $partners;
        }
   protected function getUserIDs(array|string $roles):array
   {
      $roles = $this->checkRoles($roles);
      if (empty($roles)) {
         return [];
      }
      $cache = Cache::for('everyone', DAY_IN_SECONDS)->connect('user', true);
      return $cache->remember(
         $cache->generateKey($roles),
         function() use ($roles) {
            return get_users([
               'role'   => $roles,
               'fields' => 'ID'
            ]);
         }
      );
   }
        $partners = get_users([
            'role'          => BASE.'partner',
            'capability'    => 'skip_moderation',
            'fields'        => 'ID'
        ]);
   protected function checkRoles(string|array $roles):array
   {
      if (!is_array($roles)) {
         $roles = explode(',',$roles);
      }
        $this->cache->set('verified_partners', $partners);
        return $partners;
    }
    /**
     * @return array
     */
    protected function getEnthusiasts():array
    {
        $enthusiasts = $this->cache->get('enthusiasts');
        if ($enthusiasts) {
            return $enthusiasts;
        }
        $enthusiasts = get_users([
            'role'          => BASE.'enthusiast',
            'fields'        => 'ID'
        ]);
        $this->cache->set('enthusiasts', $enthusiasts);
        return $enthusiasts;
    }
    /**
     * @return array
     */
    protected function getEveryone():array
    {
        $users = $this->cache->get('users');
        if ($users) {
            return $users;
        }
        $users = get_users([
            'role__in' => [BASE.'artist', BASE.'enthusiast', BASE.'partner'],
            'fields'    => 'ID'
        ]);
        $this->cache->set('users', $users);
        return $users;
    }
      return array_map(function ($r) {
         return jvbCheckBase(trim($r));
      }, array_filter($roles, function ($r) {
         return array_key_exists(trim($r), JVB_USER);
      }));
   }
    /**
     * @param int $userID
@@ -1777,13 +1760,12 @@
     */
    protected function checkUser(int $userID):bool
    {
        $checked = $this->cache->get($userID, 'checked_users');
        if ($checked) {
            return $checked;
        }
        $test = (bool)get_userdata($userID);
        $this->cache->set($userID, $test, null, 'checked_users');
        return $test;
      $cache = Cache::for('checked_users', DAY_IN_SECONDS)->connect('user', true);
      return $cache->remember(
         $userID,
         function() use ($userID) {
            return (bool)get_userdata($userID)?:null;
         }
      );
    }
}