From ba1e1ccf869b818f7a7a897264dfea05563a7796 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sun, 07 Jun 2026 20:10:20 +0000
Subject: [PATCH] =Major overhaul of Integrations. Playing around with adding fields to post types through Registrar from an integrations' class file.
---
inc/managers/NotificationManager.php | 1830 ++--------------------------------------------------------
1 files changed, 70 insertions(+), 1,760 deletions(-)
diff --git a/inc/managers/NotificationManager.php b/inc/managers/NotificationManager.php
index 5656303..99a771f 100644
--- a/inc/managers/NotificationManager.php
+++ b/inc/managers/NotificationManager.php
@@ -1,16 +1,14 @@
<?php
namespace JVBase\managers;
-use JVBase\JVB;
-use WP_Error;
-use Exception;
-use WP_Post;
-use WP_User;
+use JVBase\managers\Notifications\Content;
+use JVBase\managers\Notifications\EmailDigests;
+use JVBase\managers\Notifications\Notifications;
+use JVBase\managers\Notifications\Preferences;
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
-//TODO: Ensure this works with the constants setup
/**
* NotificationManager - Centralized notification system for edmonton.ink
*
@@ -20,1770 +18,82 @@
*/
class NotificationManager
{
- protected object $cache;
- protected string $campaign;
- protected string $table = BASE.'notifications';
- protected string $contentTable = BASE.'notifications_content';
- protected string $seenTable = BASE.'notifications_user_seen';
- protected string $preferencesTable = BASE.'notification_preferences';
- protected array $notification_types = [
- // System notifications
- 'new_favourite' => [
- 'icon' => 'heart',
- 'priority' => 'low',
- 'requires_action' => false,
- 'audience' => 'content_owner',
- 'email_digest' => true
- ],
- 'artist_approved' => [
- 'icon' => 'check',
- 'priority' => 'high',
- 'requires_action' => false,
- 'audience' => 'single',
- 'email_digest' => true
- ],
- 'artist_joined' => [
- 'icon' => 'artist',
- 'priority' => 'low',
- 'requires_action' => false,
- 'email_digest' => false,
- ],
- 'artist_rejected' => [
- 'icon' => 'x',
- 'priority' => 'high',
- 'requires_action' => false,
- 'audience' => 'single',
- 'email_digest' => true
- ],
- 'artist_invitation' => [
- 'icon' => 'invite',
- 'priority' => 'high',
- 'requires_action' => true,
- 'audience' => 'single',
- 'email_digest' => true
- ],
- 'artist_request' => [
- 'icon' => 'artist',
- 'priority' => 'high',
- 'requires_action' => true,
- 'audience' => 'single',
- 'email_digest' => true,
- ],
- 'shop_accepted' => [
- 'icon' => 'shop',
- 'priority' => 'high',
- 'requires_action' => false,
- 'audience' => 'single',
- 'email_digest' => true,
- ],
- 'shop_rejected' => [
- 'icon' => 'shop',
- 'priority' => 'high',
- 'requires_action' => false,
- 'audience' => 'single',
- 'email_digest' => true,
- ],
- 'new_term' => [
- 'icon' => 'style',
- 'priority' => 'medium',
- 'requires_action' => true,
- 'audience' => 'artists',
- 'email_digest' => false
- ],
- 'term_approved' => [
- 'icon' => 'check',
- 'priority' => 'high',
- 'requires_action' => false,
- 'audience' => 'single',
- 'email_digest' => true
- ],
- 'term_rejected' => [
- 'icon' => 'x',
- 'priority' => 'medium',
- 'requires_action' => false,
- 'audience' => 'single',
- 'email_digest' => true
- ],
- 'list_shared' => [
- 'icon' => 'share',
- 'priority' => 'medium',
- 'requires_action' => false,
- 'audience' => 'single',
- 'email_digest' => true
- ],
- 'list_share_accepted' => [
- 'icon' => 'check',
- 'priority' => 'low',
- 'requires_action' => false,
- 'audience' => 'single',
- 'email_digest' => true
- ],
- 'list_share_revoked' => [
- 'icon' => 'close',
- 'priority' => 'medium',
- 'requires_action' => false,
- 'audience' => 'single',
- 'email_digest' => true
- ],
- 'system_message' => [
- 'icon' => 'info',
- 'priority' => 'high',
- 'requires_action' => false,
- 'audience' => 'all',
- 'email_digest' => false
- ]
- ];
+ protected Notifications $notifications;
+ protected Content $content;
+ protected EmailDigests $digest;
+ protected Preferences $preferences;
- /**
- * Constructor
- */
- public function __construct()
- {
- $this->cache = CacheManager::for('notifications', WEEK_IN_SECONDS);
+ public function __construct()
+ {
+ $this->notifications = new Notifications();
+ $this->content = new Content();
+ $this->digest = new EmailDigests();
+ $this->preferences = new Preferences();
+ }
- // Add filter for bulk operation handling
- add_filter(BASE . 'handle_bulk_operation', [ $this, 'processOperation' ], 10, 3);
-
- add_action(BASE . 'cleanup_notifications', [$this, 'cleanupOldNotifications']);
-
- // Track content creation for notifications
- add_action('save_post', [ $this, 'trackContentCreation' ], 10, 3);
- add_action('saved_term', [ $this, 'track_shop_creation' ], 10, 3);
-
- // Generate content summaries when users log in
- add_action('wp_login', [ $this, 'generateUserContentNotifications' ], 10, 2);
-
- // Register digest cron jobs
- $this->registerCron();
- }
-
- /**
- * Registers the digest cron jobs
- * @return void
- */
- protected function registerCron():void
- {
- add_action(BASE . 'notification_digest_daily', [ $this, 'runDailyDigests' ]);
- add_action(BASE . 'notification_digest_weekly', [ $this, 'runWeeklyDigests' ]);
- add_action(BASE . 'notification_digest_monthly', [ $this, 'runMonthlyDigests' ]);
- }
-
- /************************************************************
- * Basic Notification Methods
- ************************************************************/
- /**
- * @return array
- */
- public function getNotificationTypes():array
- {
- return $this->notification_types;
- }
- /**
- * Add a new notification
- *
- * @param int|array $user_ids Recipient user ID(s)
- * @param string $type Notification type
- * @param int|null $action_user_id User who performed the action (optional)
- * @param string $message Notification message (optional)
- * @param int|null $target_id Related target ID (optional)
- * @param string|null $target_type Related target type (optional)
- * @param array|null $context Additional contextual data (optional)
- *
- * @return bool|WP_Error Success or error
- */
- public function addNotification(
- mixed $user_ids,
- 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 {
- // Validate notification type
- if (!isset($this->notification_types[$type])) {
- $this->logError("Invalid notification type: $type", [
- 'user_ids' => is_array($user_ids) ? implode(',', $user_ids) : $user_ids,
- 'message' => $message
- ], 'warning');
- return new WP_Error('invalid_type', 'Invalid notification type');
- }
-
- // Handle single user or array of users
- $user_ids = is_array($user_ids) ? $user_ids : [$user_ids];
-
- if (empty($user_ids)) {
- return false;
- }
- // Queue the bulk notification operation
- $queue = JVB()->queue();
- $queue->queueOperation(
- 'addNotification',
- $action_user_id,
- [
- 'user_ids' => $user_ids,
- 'type' => $type,
- 'action_user_id' => $action_user_id,
- 'message' => $message,
- 'target_id' => $target_id,
- 'target_type' => $target_type,
- 'context' => $context
- ],
- [
- 'count' => count($user_ids),
- 'priority' => 'normal',
- 'chunk_key' => 'user_ids',
- 'chunk_size'=> 50,
- 'operation_id' => 'notifications' . uniqid()
- ]
- );
-
- return true;
- }
-
- /**
- * Process notification operation
- *
- * @param int|array $user_ids Recipient user ID(s)
- * @param string $type Notification type
- * @param int|null $action_user_id User who performed the action (optional)
- * @param string $message Notification message (optional)
- * @param int|null $target_id Related target ID (optional)
- * @param string|null $target_type Related target type (optional)
- * @param array|null $context Additional contextual data (optional)
- *
- * @return bool|WP_Error Success or error
- */
- public function processNotification(
- int|array $user_ids,
- 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 {
- $config = $this->notification_types[$type];
- $notifications = [];
- $errors = [];
-
- $user_ids = is_array($user_ids) ? $user_ids : [$user_ids];
-
- global $wpdb;
- foreach ($user_ids as $user_id) {
- // Skip invalid users
- if (!$user_id || $user_id <= 0) {
- $errors[] = "Invalid user ID: $user_id";
- continue;
- }
-
- // Skip sending notifications to self if action_user_id == user_id
- if ($action_user_id && $action_user_id == $user_id && !($config['notify_self'] ?? false)) {
- continue;
- }
-
- try {
- // Prepare context data
- $context_json = null;
- if (!empty($context)) {
- $context_json = json_encode($context);
- }
-
- // Insert new notification
- $result = $wpdb->insert(
- $wpdb->prefix . $this->table,
- [
- 'owner_id' => $user_id,
- 'action_user_id' => $action_user_id,
- 'type' => $type,
- 'status' => 'unread',
- 'message' => $message,
- 'priority' => $config['priority'] ?? 'normal',
- 'target_id' => $target_id,
- 'target_type' => $target_type,
- 'context' => $context_json,
- 'requires_action' => !empty($config['requires_action']) ? 1 : 0,
- 'created_at' => current_time('mysql'),
- 'updated_at' => current_time('mysql')
- ]
- );
-
- if ($result) {
- $notification_id = $wpdb->insert_id;
- $notifications[] = $notification_id;
-
- // Clear cache for this user
- $this->clearNotificationCache($user_id);
- } else {
- $errors[] = "Database error for user $user_id: " . $wpdb->last_error;
- $this->logError("Failed to insert notification", [
- 'user_id' => $user_id,
- 'type' => $type,
- 'db_error' => $wpdb->last_error
- ]);
- }
- } catch (Exception $e) {
- $errors[] = "Exception for user $user_id: " . $e->getMessage();
- $this->logError("Error adding notification", [
- 'user_id' => $user_id,
- 'type' => $type,
- 'message' => $message,
- 'error' => $e->getMessage()
- ]);
- }
- }
-
- // Return results
- if (!empty($notifications) && !empty($errors)) {
- $this->logError("Some notifications failed", [
- 'successful' => count($notifications),
- 'errors' => $errors
- ], 'warning');
- }
-
- if (empty($notifications) && !empty($errors)) {
- return new WP_Error('notification_failed', 'All notifications failed', [
- 'errors' => $errors
- ]);
- }
-
- return !empty($notifications);
- }
-
- /**
- * Wrapper for notifying verified artists
- *
- * @param string $type Notification type
- * @param int|null $action_user_id User who performed the action (optional)
- * @param string $message Notification message (optional)
- * @param int|null $target_id Related target ID (optional)
- * @param string|null $target_type Related target type (optional)
- * @param array|null $context Additional contextual data (optional)
- *
- * @return bool|WP_Error Success or error
- */
- 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();
- return $this->addNotification($artists, $type, $action_user_id, $message, $target_id, $target_type, $context);
- }
- /**
- * Wrapper for notifying verified partners
- *
- * @param string $type Notification type
- * @param int|null $action_user_id User who performed the action (optional)
- * @param string $message Notification message (optional)
- * @param int|null $target_id Related target ID (optional)
- * @param string|null $target_type Related target type (optional)
- * @param array|null $context Additional contextual data (optional)
- *
- * @return bool|WP_Error Success or error
- */
- 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();
- return $this->addNotification($artists, $type, $action_user_id, $message, $target_id, $target_type, $context);
- }
- /**
- * Wrapper for notifying verified partners
- *
- * @param string $type Notification type
- * @param int|null $action_user_id User who performed the action (optional)
- * @param string $message Notification message (optional)
- * @param int|null $target_id Related target ID (optional)
- * @param string|null $target_type Related target type (optional)
- * @param array|null $context Additional contextual data (optional)
- *
- * @return bool|WP_Error Success or error
- */
- 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();
- return $this->addNotification($artists, $type, $action_user_id, $message, $target_id, $target_type, $context);
- }
- /**
- * Wrapper for notifying verified partners
- *
- * @param string $type Notification type
- * @param int|null $action_user_id User who performed the action (optional)
- * @param string $message Notification message (optional)
- * @param int|null $target_id Related target ID (optional)
- * @param string|null $target_type Related target type (optional)
- * @param array|null $context Additional contextual data (optional)
- *
- * @return bool|WP_Error Success or error
- */
- 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();
- return $this->addNotification($artists, $type, $action_user_id, $message, $target_id, $target_type, $context);
- }
-
-
-
- /************************************************************
- * Content Notification Methods
- ************************************************************/
-
- /**
- * Track content creation or updates for notification purposes
- *
- * @param int $post_id Post ID
- * @param WP_Post $post Post object
- * @param bool $update Whether this is an update
- * @return void
- */
- public function trackContentCreation(int $post_id, WP_POST $post, bool $update):void
- {
- // SAFETY: Skip attachments and other non-content post types
- if (in_array($post->post_type, jvbIgnoredPostTypes())) {
- return;
- }
- // Skip if not a published post
- if ($post->post_status !== 'publish') {
- return;
- }
-
- // Check if this is a relevant content type
- $content_types = jvbBasedFeedContent();
- if (!in_array($post->post_type, $content_types)) {
- return;
- }
-
- // Check if the artist has any followers before tracking
- $follower_count = $this->getFollowerCount($post->post_author);
- if ($follower_count === 0) {
- return; // No need to track if nobody follows this artist
- }
-
- // Get the clean content type for storing
- $content_type = str_replace(BASE, '', $post->post_type);
-
- // Update the artist's content notification records
- $this->updateContentNotificationRecord($post->post_author, $content_type, $post_id, $update);
- }
-
- /**
- * Update content notification record for an artist
- *
- * @param int $artist_id Artist user ID
- * @param string $content_type Content type (tattoo, artwork, etc)
- * @param int $content_id Content post ID
- * @param bool $is_update Whether this is an update to existing content
- *
- * @return bool Success or failure
- */
- protected function updateContentNotificationRecord(int $artist_id, string $content_type, int $content_id, bool $is_update = false):bool
- {
- global $wpdb;
- $table = $wpdb->prefix . $this->contentTable;
-
- // Start transaction
- $wpdb->query('START TRANSACTION');
- $success = false;
-
- try {
- // Get today's date
- $today = date('Y-m-d');
- $frequency_updates = [];
-
- // Update records for each frequency
- foreach (['daily', 'weekly', 'monthly'] as $frequency) {
- // Find or create a record for this artist, date and frequency
- $record = $wpdb->get_row($wpdb->prepare(
- "SELECT * FROM {$table}
- WHERE user_id = %d AND date = %s AND frequency = %s",
- $artist_id,
- $today,
- $frequency
- ));
-
- if ($record) {
- $frequency_updates[$frequency] = $this->updateExistingContentRecord(
- $record,
- $content_type,
- $content_id,
- $is_update
- );
- } else {
- $frequency_updates[$frequency] = $this->createNewContentRecord(
- $artist_id,
- $frequency,
- $content_type,
- $content_id,
- $is_update
- );
- }
- }
-
- // Check if all updates were successful
- $success = !in_array(false, $frequency_updates, true);
-
- if ($success) {
- $wpdb->query('COMMIT');
- return true;
- } else {
- // If any update failed, roll back
- $wpdb->query('ROLLBACK');
- $this->logError("Failed to update content notification records", [
- 'artist_id' => $artist_id,
- 'content_type' => $content_type,
- 'content_id' => $content_id,
- 'updates' => $frequency_updates
- ]);
- return false;
- }
- } catch (Exception $e) {
- $wpdb->query('ROLLBACK');
- $this->logError("Exception in content notification update", [
- 'artist_id' => $artist_id,
- 'content_type' => $content_type,
- 'content_id' => $content_id,
- 'error' => $e->getMessage()
- ]);
- return false;
- }
- }
-
- /**
- * Update an existing content notification record
- *
- * @param object $record Existing database record
- * @param string $content_type Content type
- * @param int $content_id Content ID
- * @param bool $is_update Whether this is an update
- *
- * @return bool Success or failure
- */
- protected function updateExistingContentRecord(object $record, string $content_type, int $content_id, bool $is_update):bool
- {
- global $wpdb;
- $table = $wpdb->prefix . $this->contentTable;
-
- // Decode existing JSON data
- $new_items = json_decode($record->new_items, true) ?: [];
- $updated_items = json_decode($record->updated_items, true) ?: [];
-
- // Initialize arrays if not present
- if (!isset($new_items[BASE.$content_type])) {
- $new_items[BASE.$content_type] = [];
- }
- if (!isset($updated_items[BASE.$content_type])) {
- $updated_items[BASE.$content_type] = [];
- }
-
- // Add ID to appropriate array
- if ($is_update) {
- // Add to updated array if not already there and not in new items
- if (!in_array($content_id, $updated_items[BASE.$content_type]) &&
- !in_array($content_id, $new_items[BASE.$content_type])) {
- $updated_items[BASE.$content_type][] = $content_id;
- }
- } else {
- // Add to new array if not already there
- if (!in_array($content_id, $new_items[BASE.$content_type])) {
- $new_items[BASE.$content_type][] = $content_id;
- }
- }
-
- // Prepare update data
- $update_data = [
- 'new_items' => json_encode($new_items),
- 'updated_items' => json_encode($updated_items),
- 'updated_at' => current_time('mysql')
- ];
-
- // Update appropriate count column
- $count_column = "{$content_type}_count";
- if (property_exists($record, $count_column)) {
- $update_data[ $count_column ] = $record->$count_column + ( $is_update ? 0 : 1 );
- }
-
- // Update total count
- $update_data['total_items'] = $record->total_items + ( $is_update ? 0 : 1 );
-
- // Update the record
- return $wpdb->update(
- $table,
- $update_data,
- [ 'id' => $record->id ]
- ) !== false;
- }
-
- /**
- * Create a new content notification record
- *
- * @param int $artist_id Artist user ID
- * @param string $frequency Frequency (daily, weekly, monthly)
- * @param string $content_type Content type
- * @param int $content_id Content ID
- * @param bool $is_update Whether this is an update
- *
- * @return bool Success or failure
- */
- protected function createNewContentRecord(int $artist_id, string $frequency, string $content_type, int $content_id, bool $is_update):bool
- {
- global $wpdb;
- $table = $wpdb->prefix . $this->contentTable;
-
- // Initialize arrays for new and updated items
- $new_items = [];
- $updated_items = [];
-
- if ($is_update) {
- $updated_items[BASE.$content_type] = [ $content_id ];
- } else {
- $new_items[BASE.$content_type] = [ $content_id ];
- }
-
- // Prepare insert data
- $insert_data = [
- 'user_id' => $artist_id,
- 'date' => date('Y-m-d'),
- 'frequency' => $frequency,
- 'total_items' => 1,
- 'new_items' => json_encode($new_items),
- 'updated_items' => json_encode($updated_items),
- 'created_at' => current_time('mysql'),
- 'updated_at' => current_time('mysql')
- ];
-
- // Set count column
- $insert_data["{$content_type}_count"] = $is_update ? 0 : 1;
-
- // Insert the record
- return $wpdb->insert($table, $insert_data) !== false;
- }
-
- /**
- * Generate content notifications for a user upon login
- *
- * @param string $username Username
- * @param WP_User $user User object
- * @return void
- */
- public function generateUserContentNotifications(string $username, WP_User $user):void
- {
- $this->createContentSeenRecords($user->ID);
- }
-
- /**
- * Create content seen records for a user's followed artists
- *
- * @param int $user_id User ID
- *
- * @return int Number of notifications created
- */
- protected function createContentSeenRecords(int $user_id):int
- {
- global $wpdb;
-
- try {
- // Get followed artists
- $followed_artists = $this->getFollowedArtists($user_id);
- if (empty($followed_artists)) {
- return 0;
- }
-
- // Get the last time notifications were checked
- $last_check = get_user_meta($user_id, BASE . 'last_content_check', true);
- $since_date = $last_check ? date('Y-m-d', strtotime($last_check)) : date('Y-m-d', strtotime('-7 days'));
-
- // Create placeholders for SQL query
- $placeholders = implode(',', array_fill(0, count($followed_artists), '%d'));
-
- // Get content notifications since last check
- $content_records = $wpdb->get_results(
- $wpdb->prepare(
- "SELECT * FROM {$wpdb->prefix}{$this->contentTable}
- WHERE user_id IN ($placeholders)
- AND date >= %s
- AND total_items > 0",
- array_merge($followed_artists, [ $since_date ])
- )
- );
-
- if (empty($content_records)) {
- return 0;
- }
-
- // Add user seen records for each content notification
- $count = 0;
- $user_seen_table = $wpdb->prefix . $this->seenTable;
-
- foreach ($content_records as $record) {
- // Check if record already exists
- $exists = $wpdb->get_var(
- $wpdb->prepare(
- "SELECT id FROM {$user_seen_table}
- WHERE user_id = %d AND content_notification_id = %d",
- $user_id,
- $record->id
- )
- );
-
- if (!$exists) {
- // Create new seen record
- $wpdb->insert(
- $user_seen_table,
- [
- 'user_id' => $user_id,
- 'content_notification_id' => $record->id,
- 'status' => 'unread',
- 'created_at' => current_time('mysql')
- ]
- );
- $count ++;
- }
- }
-
- // Update last check time
- update_user_meta($user_id, BASE . 'last_content_check', current_time('mysql'));
-
- // Clear cache
- $this->clearNotificationCache($user_id);
-
- return $count;
- } catch (Exception $e) {
- $this->logError("Error creating content seen records: " . $e->getMessage(), [
- 'user_id' => $user_id
- ]);
-
- return 0;
- }
- }
-
-
- /************************************************************
- * Notification Digest Methods
- ************************************************************/
-
- /**
- * Process daily notification digests
- */
- public function runDailyDigests():void
- {
- $this->campaign = 'daily_digest_' . date('Y-m-d');
- $this->processDigest('daily');
- }
-
- /**
- * Process weekly notification digests
- */
- public function runWeeklyDigests():void
- {
- $this->campaign = 'weekly_digest_' . date('Y-m-d');
- $this->processDigest('weekly');
- }
-
- /**
- * Process monthly notification digests
- */
- public function runMonthlyDigests():void
- {
- $this->campaign = 'monthly_digest_' . date('Y-m-d');
- $this->processDigest('monthly');
- }
-
- /**
- * Process digests for a specific frequency
- *
- * @param string $frequency Digest frequency (daily, weekly, monthly)
- *
- * @return bool Success or failure
- */
- protected function processDigest(string $frequency):bool
- {
- // Get users with this digest frequency preference
- $users = $this->getUsersForDigest($frequency);
-
- if (empty($users)) {
- return true; // No users to process
- }
-
- // Queue digest generation
- $queue = JVB()->queue();
- $queue->queueOperation(
- 'email_notification_digest',
- 0, // System user
- [
- 'frequency' => $frequency,
- 'users' => $users
- ],
- [
- 'count' => count($users),
- 'chunk_key' => 'users',
- 'chunk_size' => 20,
- 'priority' => 'normal',
- 'operation_id' => 'notification_digest_' . date('Y_m_d')
- ]
- );
-
- return true;
- }
-
- /**
- * Get users who have subscribed to a specific digest frequency
- *
- * @param string $frequency Digest frequency
- *
- * @return array Array of user IDs
- */
- protected function getUsersForDigest(string $frequency):array
- {
- global $wpdb;
- $table = $wpdb->prefix . $this->preferencesTable;
-
- // Get users with this frequency setting
- $users = $wpdb->get_col(
- $wpdb->prepare(
- "SELECT DISTINCT user_id FROM $table
- WHERE frequency = %s",
- $frequency
- )
- );
-
- return $users ?: [];
- }
-
- /**
- * Generate and send a digest email for a user
- *
- * @param int $user_id User ID
- * @param string $frequency Digest frequency
- *
- * @return bool Success status
- */
- public function generateUserDigest(int $user_id, string $frequency):bool
- {
- try {
- $user = get_userdata($user_id);
- if (!$user || !is_email($user->user_email)) {
- return false;
- }
-
- // Get date range based on frequency
- $today = date('Y-m-d');
- $since_date = $this->getSinceDate($frequency, $today);
-
- // Get regular notifications
- $notifications = $this->getDigestNotifications($user_id);
-
- // Get content updates from followed artists
- $content_updates = $this->getContentUpdatesForDigest($user_id, $since_date);
-
- if (empty($notifications) && empty($content_updates)) {
- return true; // Nothing to send
- }
-
- // Generate and send email
- $sent = $this->sendDigestEmail($user, $frequency, $notifications, $content_updates);
-
- if ($sent) {
- // Update preferences last_sent timestamp
- $this->updateDigestTimestamps($user_id, $frequency);
-
- return true;
- }
-
- return false;
- } catch (Exception $e) {
- $this->logError("Error generating digest for user $user_id: " . $e->getMessage());
-
- return false;
- }
- }
-
- /**
- * Get notifications for a digest
- *
- * @param int $user_id User ID
- *
- * @return array Notification objects
- */
- protected function getDigestNotifications(int $user_id):array
- {
- global $wpdb;
-
- // Get unread, non-emailed notifications
- return $wpdb->get_results(
- $wpdb->prepare(
- "SELECT * FROM {$wpdb->prefix}{$this->table}
- WHERE user_id = %d
- AND status = 'unread'
- AND emailed_at IS NULL
- ORDER BY priority DESC, created_at DESC",
- $user_id
- )
- );
- }
-
- /**
- * Get content updates for digest
- *
- * @param int $user_id User ID
- * @param string $since_date Date string (YYYY-MM-DD)
- *
- * @return array Content update records
- */
- protected function getContentUpdatesForDigest(int $user_id, string $since_date):array
- {
- // Get followed artists
- $followed_artists = $this->getFollowedArtists($user_id);
- if (empty($followed_artists)) {
- return [];
- }
-
- global $wpdb;
-
- // Create placeholders for SQL IN clause
- $placeholders = implode(',', array_fill(0, count($followed_artists), '%d'));
-
- // Get content records since the date
- return $wpdb->get_results(
- $wpdb->prepare(
- "SELECT * FROM {$wpdb->prefix}{$this->contentTable}
- WHERE user_id IN ($placeholders)
- AND date >= %s
- AND total_items > 0
- ORDER BY date DESC",
- array_merge($followed_artists, [ $since_date ])
- )
- );
- }
-
- /**
- * Get since date for a frequency
- *
- * @param string $frequency Digest frequency
- * @param string $today Today's date
- *
- * @return string Date string (YYYY-MM-DD)
- */
- protected function getSinceDate(string $frequency, string $today):string
- {
- switch ($frequency) {
- case 'daily':
- return date('Y-m-d', strtotime('-1 day', strtotime($today)));
- case 'weekly':
- return date('Y-m-d', strtotime('-1 week', strtotime($today)));
- case 'monthly':
- return date('Y-m-d', strtotime('-1 month', strtotime($today)));
- default:
- return '';
- }
- }
-
- /**
- * Send a digest email
- *
- * @param WP_User $user User object
- * @param string $frequency Digest frequency
- * @param array $notifications Regular notifications
- * @param array $content_updates Content update records
- *
- * @return bool Whether the email was sent
- */
- protected function sendDigestEmail(WP_User $user, string $frequency, array $notifications, array $content_updates):bool
- {
- // Generate subject based on frequency
- $subjects = [
- 'daily' => [
- "[edmonton.ink] Your " . date('l') . " Ink Update ♡",
- "[edmonton.ink] Fresh Ink Alert - Your " . date('l') . " Digest",
- "[edmonton.ink] What You Missed in Edmonton's Tattoo Scene Today"
- ],
- 'weekly' => [
- "[edmonton.ink] Your Weekly Roundup from edmonton.ink ♡",
- "[edmonton.ink] This Week in Edmonton's Tattoo Scene",
- "[edmonton.ink] Weekly Ink Update - Fresh From the Scene"
- ],
- 'monthly' => [
- "[edmonton.ink] Monthly Ink Roundup ♡",
- "[edmonton.ink] Your Monthly Scene Report: " . date('F') . " Edition",
- "[edmonton.ink] " . date('F') . " in Edmonton Tattoos"
- ]
- ];
-
- // Randomly select a subject for variety
- $subject_options = $subjects[ $frequency ] ?? [ "Your edmonton.ink Update" ];
- $subject = $subject_options[ array_rand($subject_options) ];
-
- // Generate email content
- $content = $this->generateDigestContent($user, $frequency, $notifications, $content_updates);
-
- // Add tracking pixel
- $tracking_code = sprintf(
- '<img src="%s/track-email.php?uid=%s&digest=%s" width="1" height="1" alt="" />',
- site_url(),
- base64_encode($user->ID),
- $frequency
- );
- $content .= $tracking_code;
-
- // Set header based on frequency
- $header = match ($frequency) {
- 'daily' => "TODAY'S INK DROP",
- 'weekly' => "THIS WEEK'S SCENE REPORT",
- 'monthly' => "MONTHLY INK ROUNDUP",
- default => "YOUR INK UPDATES",
- };
-
- // Send the email
- return JVB()->email()->sendEmail($user->user_email, $subject, $content, $header);
- }
-
- /**
- * Generate HTML content for digest email
- *
- * @param WP_User $user User object
- * @param string $frequency Digest frequency
- * @param array $notifications Regular notifications
- * @param array $content_updates Content update records
- *
- * @return string HTML email content
- */
- protected function generateDigestContent(WP_User $user, string $frequency, array $notifications, array $content_updates):string
+ /************************************************
+ * PREFERENCES
+ ************************************************/
+ public function getUsersByFrequency(string $frequency):array
{
- $content = sprintf('<p>Hey %s,</p>', $user->first_name ?: $user->display_name);
-
- // Intro text based on frequency
- switch ($frequency) {
- case 'daily':
- $content .= '<p>Here\'s what happened in Edmonton\'s tattoo scene today:</p>';
- break;
- case 'weekly':
- $content .= '<p>Here\'s what you missed in Edmonton\'s tattoo scene this week:</p>';
- break;
- case 'monthly':
- $content .= sprintf('<p>Here\'s your monthly roundup of what happened in %s in Edmonton\'s tattoo scene:</p>', date('F'));
- break;
- }
-
- // Process artist content updates - the most visually interesting part
- $content .= $this->generateContentUpdatesSection($content_updates);
-
- // Process regular notifications
- if (!empty($notifications)) {
- $content .= $this->generateNotificationsSection($notifications);
- }
-
- // Add footer content
- $content .= JVB()->email()->divider();
- $settings_url = add_query_arg([
- 'utm_source' => 'email',
- 'utm_medium' => 'digest',
- 'utm_campaign' => $this->campaign
- ], site_url('/dash/settings/'));
-
- $content .= sprintf(
- '<p>You\'re receiving this %s digest because you follow artists on edmonton.ink. You can %s at any time.</p>',
- $frequency,
- '<a href="' . esc_url($settings_url) . '">adjust your notification settings</a>'
- );
-
- return $content;
+ return $this->preferences->getUsersByFrequency($frequency);
}
- /**
- * Generate HTML section for content updates
- *
- * @param array $content_updates Content update records
- *
- * @return string HTML content
- * TODO: This needs some work
- */
- protected function generateContentUpdatesSection(array $content_updates):string
- {
- if (empty($content_updates)) {
- return '';
- }
-
- $content = '';
- $cache = CacheManager::for('digest_content', HOUR_IN_SECONDS * 6); // Cache for 6 hours
-
- // Group updates by artist
- $updates_by_artist = [];
- foreach ($content_updates as $update) {
- if (!isset($updates_by_artist[$update->user_id])) {
- $updates_by_artist[ $update->user_id ] = [];
- }
- $updates_by_artist[ $update->user_id ][] = $update;
- }
-
- // Process each artist's updates
- foreach ($updates_by_artist as $artist_id => $updates) {
- $artist_data = $this->getArtistData($artist_id);
- if (!$artist_data) {
- continue;
- }
-
- // Combine all content updates from this artist
- $combined_new_items = [];
-
- foreach ($updates as $update) {
- $new_items = json_decode($update->new_items, true) ?: [];
-
- foreach ($new_items as $type => $ids) {
- if (!isset($combined_new_items[ $type ])) {
- $combined_new_items[ $type ] = [];
- }
- $combined_new_items[ $type ] = array_merge($combined_new_items[ $type ], $ids);
- // Remove duplicates
- $combined_new_items[ $type ] = array_unique($combined_new_items[ $type ]);
- }
- }
-
- // Skip if no content to show
- if (empty($combined_new_items)) {
- continue;
- }
-
- // Add artist header
- $content .= sprintf(
- '<h3><a href="%s" class="text-link">%s</a></h3>',
- esc_url(add_query_arg([
- 'utm_source' => 'email',
- 'utm_medium' => 'digest',
- 'utm_campaign' => $this->campaign
- ], $artist_data['url'])),
- esc_html($artist_data['display_name'])
- );
-
- // Process each content type
- foreach ($combined_new_items as $type => $ids) {
- if (empty($ids)) {
- continue;
- }
-
- $clean_type = str_replace(BASE, '', $type);
- $type_label = $this->getContentTypeLabel($clean_type);
-
- // Add subheading for content type
- $content .= sprintf('<h4>%s</h4>', esc_html($type_label));
-
- // Display up to 3 items in a row
- $display_ids = array_slice($ids, 0, 3);
- $content .= '<table><tr>';
-
- foreach ($display_ids as $item_id) {
- // Get cached item data or fetch it
- $cache_key = "digest_{$type}_{$item_id}";
- $item_data = $cache->get($cache_key);
-
- if ($item_data === false) {
- $item_data = $this->getContentDetails($type, $item_id, $artist_id);
- if ($item_data) {
- $cache->set($cache_key, $item_data);
- }
- }
-
- if (!$item_data) {
- continue;
- }
-
- // Add item to email
- $content .= '<td style="padding: 10px; width: 33.3%; vertical-align: top; text-align: center;">';
- $content .= '<div style="margin-bottom: 10px;">';
- $content .= sprintf(
- '<a href="%s"><img src="%s" alt="%s" style="width: 100%%; max-width: 150px; height: auto; border-radius: 4px;"></a>',
- esc_url(add_query_arg([
- 'utm_source' => 'email',
- 'utm_medium' => 'digest',
- 'utm_campaign' => $this->campaign
- ], $item_data['url'])),
- esc_url($item_data['image']),
- esc_attr($item_data['title'])
- );
- $content .= '</div>';
- $content .= sprintf('<p style="margin: 5px 0; font-weight: bold;">%s</p>', esc_html($item_data['title']));
- $content .= '</td>';
- }
-
- // Fill empty cells if needed
- for ($i = count($display_ids); $i < 3; $i++) {
- $content .= '<td style="width: 33.3%;"></td>';
- }
-
- $content .= '</tr></table>';
-
- // Add "See all" link if there are more items
- if (count($ids) > 3) {
- $content .= sprintf(
- '<p style="text-align: right;"><a href="%s" class="text-link">See all %d %s →</a></p>',
- esc_url(add_query_arg([
- 'utm_source' => 'email',
- 'utm_medium' => 'digest',
- 'utm_campaign' => $this->campaign
- ], site_url('/dash/feed/?type=' . $clean_type . '&artist=' . $artist_id))),
- count($ids),
- $this->pluralize($clean_type)
- );
- }
- }
-
- $content .= '<div class="divider"></div>';
- }
-
- return $content;
- }
-
- /**
- * Generate HTML section for regular notifications
- *
- * @param array $notifications Notification objects
- *
- * @return string HTML content
- */
- protected function generateNotificationsSection(array $notifications):string
+ public function getUserSubscriptions(int $userID, string $frequency):array
{
- if (empty($notifications)) {
- return '';
- }
-
- $items = [];
-
- // Group notifications by type
- $by_type = [];
- foreach ($notifications as $notification) {
- if (!isset($by_type[$notification->type])) {
- $by_type[$notification->type] = [];
- }
- $by_type[$notification->type][] = $notification;
- }
-
- // Process each type
- foreach ($by_type as $type => $type_notifications) {
- foreach ($type_notifications as $notification) {
- $message = $notification->message;
- if (empty($message)) {
- $message = $this->generateNotificationMessage($notification);
- }
-
- if (!empty($message)) {
- $items[] = ['label' => '', 'value' => $message];
- }
- }
- }
-
- return JVB()->email()->table($items, 'Other Updates');
+ return $this->preferences->getUserSubscriptions($userID, $frequency);
}
- /**
- * Generate a message for a notification when none is provided
- *
- * @param object $notification Notification object
- *
- * @return string Formatted message
- */
- protected function generateNotificationMessage(object $notification):string
- {
- switch ($notification->type) {
- case 'new_favourite':
- return 'Someone favourited your content';
+ public function addUserPreference(int $userID, int $item_id, string $item_type, string $frequency):bool
+ {
+ return $this->preferences->addUserPreference($userID, $item_id, $item_type, $frequency);
+ }
- case 'artist_approved':
- return 'Your artist profile has been approved';
+ public function deleteUserPreference(int $userID, int $item_id, string $item_type):bool
+ {
+ return $this->preferences->deleteUserPreference($userID, $item_id, $item_type);
+ }
+ /************************************************
+ * NOTIFICATIONS
+ ************************************************/
+ public function notify(int|array $user_ids, string $notification_type, int $fromUser = 0, array $args = []):bool
+ {
+ return $this->notifications->notify($user_ids, $notification_type, $fromUser, $args);
+ }
+ public function unnotify(int|array $user_ids, string $notification_type, int $fromUser = 0, array $args = []):bool
+ {
+ return $this->notifications->unnotify($user_ids, $notification_type, $fromUser, $args);
+ }
+ public function getUserNotifications(int $user_id, array $args = []):array
+ {
+ return $this->notifications->getUserNotifications($user_id, $args);
+ }
- case 'artist_invitation':
- return 'You have a new invitation to join a shop';
+ public function markRead(int $userID, int|array $notification_id):bool
+ {
+ return $this->notifications->markRead($userID, $notification_id);
+ }
+ public function markDismissed(int $userID, int|array $notification_id):bool
+ {
+ return $this->notifications->markDismissed($userID, $notification_id);
+ }
+ public function markActioned(int $userID, int|array $notification_id, array $result = []):bool
+ {
+ return $this->notifications->markActioned($userID, $notification_id, $result);
+ }
- case 'new_term':
- return 'New term suggestion requires your approval';
+ public function getNotificationTypes(bool $all = false):array
+ {
+ return $this->notifications->getNotificationTypes($all);
+ }
- case 'term_approved':
- return 'Your term suggestion was approved';
-
- case 'term_rejected':
- return 'Your term suggestion was not approved';
-
- case 'list_shared':
- return 'Someone shared a list with you';
-
- default:
- return 'You have a new notification';
- }
- }
-
- /**
- * Get content details for digest
- *
- * @param string $type Content type (with jvb_ prefix)
- * @param int $content_id Content ID
- * @param int $artist_id Artist ID
- *
- * @return array|false Content details or false if not found
- */
- protected function getContentDetails(string $type, int $content_id, int $artist_id):array|false
- {
- // Build post type from content type
- $post_type = $type; // Already has jvb_ prefix
-
- // Get the post
- $post = get_post($content_id);
- if (!$post || $post->post_type !== $post_type || $post->post_status !== 'publish') {
- return false;
- }
-
- // Get artist data
- $artist_data = $this->getArtistData($artist_id);
- if (!$artist_data) {
- return false;
- }
-
- // Get featured image if available
- $image_url = get_the_post_thumbnail_url($content_id, 'medium');
- if (!$image_url) {
- // Try meta fields for image
- $meta_image_id = get_post_meta($content_id, BASE . 'image', true);
- if ($meta_image_id !== '') {
- $image_url = wp_get_attachment_image_url($meta_image_id, 'medium');
- }
- }
-
- if (!$image_url) {
- return false; // Skip items without images for digest
- }
-
- return [
- 'id' => $content_id,
- 'title' => $post->post_title,
- 'url' => get_permalink($content_id),
- 'image' => $image_url,
- 'date' => $post->post_date,
- 'artist_id' => $artist_id,
- 'artist_name' => $artist_data['display_name'],
- 'artist_url' => $artist_data['url'],
- 'type' => str_replace(BASE, '', $type)
- ];
- }
-
- /**
- * Get human-readable label for content type
- *
- * @param string $type Content type (without jvb_ prefix)
- *
- * @return string Label
- */
- protected function getContentTypeLabel(string $type):string
- {
- $labels = [
- 'tattoo' => 'New Tattoos',
- 'artwork' => 'New Artwork',
- 'piercing' => 'New Piercings',
- 'event' => 'Upcoming Events',
- 'news' => 'News & Updates',
- 'offer' => 'Special Offers'
- ];
-
- return $labels[$type] ?? ucfirst($type . 's');
- }
-
-
- /**
- * Update digest timestamps for notification preferences
- *
- * @param int $user_id User ID
- * @param string $frequency Digest frequency
- *
- * @return bool Success or failure
- */
- protected function updateDigestTimestamps(int $user_id, string $frequency):bool
- {
- global $wpdb;
- $table = $wpdb->prefix . $this->preferencesTable;
-
- $result = $wpdb->update(
- $table,
- [
- 'last_sent' => current_time('mysql')
- ],
- [
- 'user_id' => $user_id,
- 'frequency' => $frequency
- ]
- );
-
- return $result !== false;
- }
-
- /************************************************************
- * Bulk Operation Handlers
- ************************************************************/
-
- /**
- * Handle bulk operations for notifications
- *
- * @param WP_Error|array $result Default result
- * @param object $operation Operation object
- * @param array $data Current item
- *
- * @return WP_Error|array Operation result
- */
- public function processOperation(WP_Error|array $result, object $operation, array $data):WP_Error|array
- {
- switch ($operation->type) {
- case 'email_notification_digest':
- return $this->handleDigestBatch($operation, $data);
-
- case 'addNotification':
- return $this->handleAddNotificationOperation($operation, $data);
- default:
- return $result;
- }
- }
-
- /**
- * Handle digest batch operation
- *
- * @param object $operation Operation object
- * @param array $data
- *
- * @return WP_Error|array|bool Operation result
- */
- protected function handleDigestBatch(object $operation, array $data):WP_Error|array|bool
- {
- try {
-
- // Process one user at a time
- $user_id = $data['users'][ $operation->progress_count ] ?? null;
-
- if (!$user_id) {
- return [
- 'success' => false,
- 'message' => 'Invalid user ID'
- ];
- }
-
- $result = $this->generateUserDigest($user_id, $data['frequency']);
-
- return [
- 'success' => $result,
- 'result' => $result ? 'Digest sent successfully' : 'Failed to send digest',
- ];
- } catch (Exception $e) {
- $this->logError("Error processing digest batch: " . $e->getMessage(), [
- 'operation_id' => $operation->id
- ]);
-
- return false;
- }
- }
-
- /**
- * @param object $operation
- * @param array $data
- *
- * @return WP_Error|array|bool
- */
- protected function handleAddNotificationOperation(object $operation, array $data):WP_Error|array|bool
- {
- try {
- $user_ids = $data['user_ids'] ?? [];
- $type = $data['type'] ?? '';
- $message = $data['message'] ?? '';
- $target_id = $data['target_id'] ?? null;
- $target_type = $data['target_type'] ?? null;
-
- if (empty($user_ids) || empty($type)) {
- return new WP_Error('invalid_data', 'Missing required notification data');
- }
-
- foreach ($user_ids as $key => $user_id) {
- if (!$this->checkUser($user_id)) {
- unset($user_ids[$key]);
- }
- }
-
- // Add notification for this user
- $result = $this->processNotification($user_ids, $type, $message, $target_id, $target_type);
-
- return [
- 'success' => !is_wp_error($result),
- 'result' => is_wp_error($result) ? $result->get_error_message() : $result,
- ];
- } catch (Exception $e) {
- return [
- 'success' => false,
- 'result' => $e->getMessage()
- ];
- }
- }
-
-
- /**
- * @param int $user_id
- *
- * @return array|false|mixed
- */
- 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);
-
- 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) {
- return false;
- }
-
- $data = [
- 'id' => $artist_id,
- 'user_id' => $user_id,
- 'display_name' => get_the_title($artist_id),
- 'first_name' => get_post_meta($artist_id, BASE . 'first_name', true),
- 'url' => get_permalink($artist_id),
- 'image' => get_post_thumbnail_id($artist_id)
- ];
-
- // Cache the result
- $this->cache->set($cache_key, $data, null,'artists');
-
- return $data;
- }
-
- /**
- * @param int $user_id
- *
- * @return array
- */
- protected function getFollowedArtists(int $user_id):array
- {
- 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
- ));
- }
-
- /**
- * @param int $artist_id
- *
- * @return int
- */
- protected function getFollowerCount(int $artist_id):int
- {
- 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
- ));
- }
-
- /**
- * @param string $word
- *
- * @return string
- */
- protected function pluralize(string $word):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';
- }
-
- /**
- * @param int $user_id
- *
- * @return void
- */
- 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);
- }
-
- /**
- * Log errors with proper context using the error handler
- *
- * @param string $message Error message
- * @param array $context Additional context data
- * @param string $severity Error severity (debug, info, warning, error, critical)
- * @return void
- */
- protected function logError(string $message, array $context = [], string $severity = 'error'):void
- {
- try {
- // Use the ErrorHandler through the JVB singleton
- JVB()->error()->log(
- 'notifications', // component
- $message,
- $context,
- $severity
- );
- } catch (Exception $e) {
- // Fallback if error handler fails
- error_log("NotificationManager Error: $message - " . json_encode($context));
- }
- }
-
- /**
- * @return void
- */
- public function cleanupOldNotifications():void
- {
- global $wpdb;
- $notifications_table = $wpdb->prefix . $this->table;
- $seen_table = $wpdb->prefix . $this->seenTable;
-
- // Keep track of current time
- $current_time = current_time('mysql');
-
- // Delete regular notifications older than 3 months
- $wpdb->query($wpdb->prepare(
- "DELETE FROM {$notifications_table}
- WHERE created_at < DATE_SUB(%s, INTERVAL 3 MONTH)
- AND status IN ('read', 'actioned', 'dismissed')",
- $current_time
- ));
-
- // Delete dismissed content notifications older than 1 month
- $wpdb->query($wpdb->prepare(
- "DELETE FROM {$seen_table}
- WHERE status = 'dismissed'
- AND created_at < DATE_SUB(%s, INTERVAL 1 MONTH)",
- $current_time
- ));
-
- // Delete read content notifications older than 3 months
- $wpdb->query($wpdb->prepare(
- "DELETE FROM {$seen_table}
- WHERE status = 'read'
- AND created_at < DATE_SUB(%s, INTERVAL 3 MONTH)",
- $current_time
- ));
- }
-
- /**
- * @return array
- */
- protected function getVerifiedArtists():array
- {
- $artists = $this->cache->get('verified_artists');
- if ($artists) {
- return $artists;
- }
-
- $artists = get_users([
- 'role' => BASE.'artist',
- 'capability' => 'skip_moderation',
- 'fields' => 'ID'
- ]);
-
- $this->cache->set('verified_artists', $artists);
- return $artists;
- }
-
- /**
- * @return array
- */
- protected function getVerifiedPartners():array
- {
- $partners = $this->cache->get('verified_partners');
- if ($partners) {
- return $partners;
- }
-
- $partners = get_users([
- 'role' => BASE.'partner',
- 'capability' => 'skip_moderation',
- 'fields' => 'ID'
- ]);
-
- $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;
- }
-
- /**
- * @param int $userID
- *
- * @return bool|mixed
- */
- 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;
- }
+ /************************************************
+ * CONTENT NOTIFICATIONS
+ * These are pooled notifications of new content for:
+ * - a particular artist
+ * - a particular term
+ ************************************************/
+ /************************************************
+ * EMAIL DIGESTS
+ ************************************************/
}
--
Gitblit v1.10.0