PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.10.01
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.10.01
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
← All changes | app/Hooks/Handlers/Scheduler.php +28 -17 2.7.0 → 2.10.01 View file →
@@ -2,12 +2,13 @@
2 2
3 3 namespace FluentCommunity\App\Hooks\Handlers;
4 4
5 5 use FluentCommunity\App\Functions\Utility;
6 -use FluentCommunity\App\Models\NotificationSubscription;
7 6 use FluentCommunity\Framework\Support\Arr;
8 7 use FluentCommunity\Framework\Support\DateTime;
9 8 use FluentCommunity\App\Services\Helper;
9 +use FluentCommunity\App\Services\NotificationPref;
10 +use FluentCommunity\Database\Migrations\NotificationPrefMigrator;
10 11
11 12 class Scheduler
12 13 {
13 14 public function register()
@@ -20,8 +21,18 @@
20 21 add_action('fluent_community_send_daily_digest_init', function () {
21 22 do_action('fluent_community_send_daily_digest');
22 23 }, 10);
23 24
25 + /*
26 + * Continuation for a preference backfill that ran out of request budget.
27 + * Not reachable through DBMigrator: boot/app.php stamps the db-version
28 + * option as soon as that returns, which closes the gate on any further
29 + * migrator pass.
30 + */
31 + add_action(NotificationPrefMigrator::RESUME_HOOK, function () {
32 + NotificationPrefMigrator::continueBackfill();
33 + }, 10);
34 +
24 35 add_action('fluent_community_daily_jobs', function () {
25 36 // let's fire the old email notifications hook
26 37 do_action('fluent_community/remove_old_notifications');
27 38 $this->maybeRemoveOldScheuledActionLogs();
@@ -36,11 +47,12 @@
36 47
37 48 if ($globalStatus != 'yes') {
38 49 // Global Status is false
39 50 // Check if any user enabled that or not
40 - $isEnabled = NotificationSubscription::query()->where('notification_type', 'digest_mail')
41 - ->where('is_read', 1)
42 - ->exists();
51 + // Answered from a denormalized option refreshed on the preference
52 + // write path. This used to be an hourly unindexed scan of the
53 + // notification receipts table looking for a handful of pref rows.
54 + $isEnabled = NotificationPref::hasAnyEnabled('digest');
43 55
44 56 if (!$isEnabled) {
45 57 // unset the scheduled action
46 58 if (\as_next_scheduled_action('fluent_community_send_daily_digest_init')) {
@@ -107,11 +119,11 @@
107 119 // Safe to interpolate: every id is cast to an integer.
108 120 $ids = implode(',', array_map('intval', $actionIds));
109 121
110 122 // Remove the associated logs first, then the actions themselves.
111 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
123 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
112 124 $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
125 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
114 126 $totalDeleted += (int) $wpdb->query("DELETE FROM {$wpdb->prefix}actionscheduler_actions WHERE action_id IN ({$ids})");
115 127
116 128 $isFullBatch = count($actionIds) === $batchSize;
117 129 } while ($isFullBatch && (microtime(true) - FLUENT_COMMUNITY_START_TIME) < 30);
@@ -128,31 +140,30 @@
128 140 }
129 141
130 142 private function getNextOccurrenceTimestamp($dayname, $time)
131 143 {
132 - // Ensure dayname is lowercase and valid
133 144 $dayname = strtolower($dayname);
134 145 $valid_days = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
135 - if (!in_array($dayname, $valid_days)) {
146 + if (!in_array($dayname, $valid_days, true)) {
136 147 return false;
137 148 }
138 149
139 - // Get current time in WordPress timezone
140 150 $current = current_datetime();
151 + $currentDay = strtolower($current->format('l'));
152 + $target = new \DateTime($current->format('Y-m-d') . ' ' . $time, wp_timezone());
141 153
142 - // Create target DateTime with "next" modifier in WordPress timezone
143 - $target = new \DateTime('next ' . $dayname . ' ' . $time, wp_timezone());
154 + $currentDayIndex = array_search($currentDay, $valid_days, true);
155 + $targetDayIndex = array_search($dayname, $valid_days, true);
156 + $dayOffset = ($targetDayIndex - $currentDayIndex + 7) % 7;
144 157
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) {
158 + if ($dayOffset) {
159 + $target->modify('+' . $dayOffset . ' days');
160 + } elseif ($target <= $current) {
150 161 $target->modify('+7 days');
151 162 }
152 163
153 - // Switch to UTC timezone and get timestamp
154 164 $target->setTimezone(new \DateTimeZone('UTC'));
165 +
155 166 return $target->getTimestamp();
156 167 }
157 168
158 169 }