PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.7.5
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.7.5
2.11.0 2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 All 78 releases
fluent-community / app / Hooks / Handlers / Scheduler.php

Scheduler.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 2.7.5, at app/Hooks/Handlers/Scheduler.php

159 lines 6.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCommunity\App\Hooks\Handlers;
4
5 use FluentCommunity\App\Functions\Utility;
6 use FluentCommunity\App\Models\NotificationSubscription;
7 use FluentCommunity\Framework\Support\Arr;
8 use FluentCommunity\Framework\Support\DateTime;
9 use FluentCommunity\App\Services\Helper;
10
11 class Scheduler
12 {
13 public function register()
14 {
15 add_action('fluent_community_scheduled_hour_jobs', function () {
16 $this->checkDailyDigestSchedule();
17 do_action('fluent_community/maybe_delete_draft_medias');
18 }, 10);
19
20 add_action('fluent_community_send_daily_digest_init', function () {
21 do_action('fluent_community_send_daily_digest');
22 }, 10);
23
24 add_action('fluent_community_daily_jobs', function () {
25 // let's fire the old email notifications hook
26 do_action('fluent_community/remove_old_notifications');
27 $this->maybeRemoveOldScheuledActionLogs();
28 }, 10);
29
30 }
31
32 public function checkDailyDigestSchedule($willReset = false)
33 {
34 $notificationSettings = Utility::getEmailNotificationSettings();
35 $globalStatus = Arr::get($notificationSettings, 'digest_email_status', 'no');
36
37 if ($globalStatus != 'yes') {
38 // Global Status is false
39 // Check if any user enabled that or not
40 $isEnabled = NotificationSubscription::query()->where('notification_type', 'digest_mail')
41 ->where('is_read', 1)
42 ->exists();
43
44 if (!$isEnabled) {
45 // unset the scheduled action
46 if (\as_next_scheduled_action('fluent_community_send_daily_digest_init')) {
47 \as_unschedule_all_actions('fluent_community_send_daily_digest_init', [], 'fluent-community');
48 }
49 return;
50 }
51 }
52
53 $notificationDay = Arr::get($notificationSettings, 'digest_mail_day');
54 $digestTime = Arr::get($notificationSettings, 'daily_digest_time', '09:00');
55
56 // Let's check if we have the daily digest action scheduled or not
57 if (!\as_next_scheduled_action('fluent_community_send_daily_digest_init')) {
58 $timestamp = $this->getNextOccurrenceTimestamp(Helper::getFullDayName($notificationDay), $digestTime);
59 if ($timestamp) {
60 \as_schedule_single_action($timestamp, 'fluent_community_send_daily_digest_init', [], 'fluent-community', true);
61 }
62 }
63 }
64
65 private function maybeRemoveOldScheuledActionLogs($group_slug = 'fluent-community', $days_old = 7)
66 {
67 global $wpdb;
68
69 // Get the timestamp for $days_old days ago
70 $cutoff_date = gmdate('Y-m-d H:i:s', strtotime("-{$days_old} days"));
71
72 // Get the group ID
73 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
74 $group_id = $wpdb->get_var($wpdb->prepare(
75 "SELECT group_id FROM {$wpdb->prefix}actionscheduler_groups WHERE slug = %s",
76 $group_slug
77 ));
78
79 if (!$group_id) {
80 return false; // Group not found
81 }
82
83 // Delete old actions and their associated logs in bounded batches. Action
84 // Scheduler tables are read/written constantly by the queue runner, so a
85 // single unbounded multi-table DELETE could hold a large lock and bloat the
86 // transaction on busy sites. We loop while batches stay full and we are still
87 // within a safe time budget (mirrors the other cleanup jobs in this plugin).
88 $batchSize = 500;
89 $totalDeleted = 0;
90
91 do {
92 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
93 $actionIds = $wpdb->get_col($wpdb->prepare(
94 "SELECT action_id
95 FROM {$wpdb->prefix}actionscheduler_actions
96 WHERE group_id = %d
97 AND status IN ('complete', 'failed')
98 AND scheduled_date_gmt < %s
99 LIMIT %d",
100 $group_id, $cutoff_date, $batchSize
101 ));
102
103 if (!$actionIds) {
104 break;
105 }
106
107 // Safe to interpolate: every id is cast to an integer.
108 $ids = implode(',', array_map('intval', $actionIds));
109
110 // Remove the associated logs first, then the actions themselves.
111 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
112 $wpdb->query("DELETE FROM {$wpdb->prefix}actionscheduler_logs WHERE action_id IN ({$ids})");
113 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
114 $totalDeleted += (int) $wpdb->query("DELETE FROM {$wpdb->prefix}actionscheduler_actions WHERE action_id IN ({$ids})");
115
116 $isFullBatch = count($actionIds) === $batchSize;
117 } while ($isFullBatch && (microtime(true) - FLUENT_COMMUNITY_START_TIME) < 30);
118
119 // Clean up orphaned claims (claims whose actions no longer exist)
120 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
121 $wpdb->query("
122 DELETE c
123 FROM {$wpdb->prefix}actionscheduler_claims c
124 LEFT JOIN {$wpdb->prefix}actionscheduler_actions a ON c.claim_id = a.claim_id
125 WHERE a.action_id IS NULL");
126
127 return $totalDeleted;
128 }
129
130 private function getNextOccurrenceTimestamp($dayname, $time)
131 {
132 // Ensure dayname is lowercase and valid
133 $dayname = strtolower($dayname);
134 $valid_days = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
135 if (!in_array($dayname, $valid_days)) {
136 return false;
137 }
138
139 // Get current time in WordPress timezone
140 $current = current_datetime();
141
142 // Create target DateTime with "next" modifier in WordPress timezone
143 $target = new \DateTime('next ' . $dayname . ' ' . $time, wp_timezone());
144
145 $targetDate = $target->format('Ymd');
146 $currentDate = $current->format('Ymd');
147
148 // If it's the same day and time has passed, move to next week
149 if ($targetDate === $currentDate || $currentDate > $targetDate) {
150 $target->modify('+7 days');
151 }
152
153 // Switch to UTC timezone and get timestamp
154 $target->setTimezone(new \DateTimeZone('UTC'));
155 return $target->getTimestamp();
156 }
157
158 }
159