From 3d25ad7de4fdbb3eba2cde2a62422e6be5d79a0a Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Tue, 25 Aug 2026 22:57:22 +0000
Subject: [PATCH] =It's been a minute. I went through the Routes and associated Managers and ensured they played together well. Reworked the Cache.php, and I think I caught all the references. Moving away from JVBase() root class, to individuall classes that are Instanced. Double checked for the ABSPATH check in every file, and added index.php to every directory that didn't already have it. Also still working on the MenuBlock to work with WooCommerce for now for Northeh
---
inc/managers/NotificationManager.php | 1836 ++--------------------------------------------------------
1 files changed, 76 insertions(+), 1,760 deletions(-)
diff --git a/inc/managers/NotificationManager.php b/inc/managers/NotificationManager.php
index 5656303..9b12b4f 100644
--- a/inc/managers/NotificationManager.php
+++ b/inc/managers/NotificationManager.php
@@ -1,16 +1,17 @@
<?php
namespace JVBase\managers;
-use JVBase\JVB;
-use WP_Error;
-use Exception;
-use WP_Post;
-use WP_User;
+use JVBase\Instance;
+use JVBase\managers\Notifications\Content;
+use JVBase\managers\Notifications\EmailDigests;
+use JVBase\managers\Notifications\Notifications;
+use JVBase\managers\Notifications\Preferences;
+use JVBase\rest\Rest;
+use JVBase\rest\routes\NotificationsRoutes;
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 +21,85 @@
*/
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
- ]
- ];
+ use Instance;
+ protected Notifications $notifications;
+ protected Content $content;
+ protected EmailDigests $digest;
+ protected Preferences $preferences;
+ protected Rest $route;
+ private function __construct()
+ {
+ $this->route = NotificationsRoutes::getInstance();
- /**
- * Constructor
- */
- public function __construct()
- {
- $this->cache = CacheManager::for('notifications', WEEK_IN_SECONDS);
+ $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