| | |
| | | */ |
| | | 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'; |
| | |
| | | */ |
| | | 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); |
| | |
| | | */ |
| | | 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); |
| | | } |
| | | /** |
| | |
| | | */ |
| | | 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); |
| | | } |
| | | /** |
| | |
| | | */ |
| | | 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); |
| | | } |
| | | /** |
| | |
| | | */ |
| | | 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); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | $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 = []; |
| | |
| | | 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) { |
| | |
| | | ]; |
| | | |
| | | // Cache the result |
| | | $this->cache->set($cache_key, $data, null,'artists'); |
| | | $this->artistsCache->set($artist_id, $data); |
| | | |
| | | return $data; |
| | | } |
| | |
| | | */ |
| | | 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 |
| | | )); |
| | | } |
| | | ); |
| | | |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | 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 |
| | | )); |
| | | } |
| | | ); |
| | | |
| | | } |
| | | |
| | | /** |
| | |
| | | * |
| | | * @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; |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | 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); |
| | | } |
| | | |
| | | /** |
| | |
| | | /** |
| | | * @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 |
| | |
| | | */ |
| | | 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; |
| | | } |
| | | ); |
| | | } |
| | | } |