PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / lib / Cron / Triggers / WordPress.php
mailpoet / lib / Cron / Triggers Last commit date
WordPress.php 2 months ago index.php 3 years ago
WordPress.php
281 lines
1 <?php declare(strict_types = 1);
2
3 namespace MailPoet\Cron\Triggers;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\Config\ServicesChecker;
9 use MailPoet\Cron\CronHelper;
10 use MailPoet\Cron\Supervisor;
11 use MailPoet\Cron\Workers\Bounce as BounceWorker;
12 use MailPoet\Cron\Workers\KeyCheck\PremiumKeyCheck as PremiumKeyCheckWorker;
13 use MailPoet\Cron\Workers\KeyCheck\SendingServiceKeyCheck as SendingServiceKeyCheckWorker;
14 use MailPoet\Cron\Workers\Scheduler as SchedulerWorker;
15 use MailPoet\Cron\Workers\SendingQueue\SendingQueue as SendingQueueWorker;
16 use MailPoet\Cron\Workers\SubscribersStatsReport;
17 use MailPoet\Cron\Workers\WorkersFactory;
18 use MailPoet\Entities\ScheduledTaskEntity;
19 use MailPoet\Mailer\MailerLog;
20 use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
21 use MailPoet\Services\Bridge;
22 use MailPoet\Settings\SettingsController;
23 use MailPoet\Util\Helpers;
24 use MailPoet\WP\Functions as WPFunctions;
25 use MailPoetVendor\Doctrine\ORM\EntityManager;
26
27 class WordPress {
28 const SCHEDULED_IN_THE_PAST = 'past';
29 const SCHEDULED_IN_THE_FUTURE = 'future';
30
31 const RUN_INTERVAL = -1; // seconds
32 const LAST_RUN_AT_SETTING = 'cron_trigger_wordpress.last_run_at';
33
34 /** @var array<string, array<string, array<string, int>>> */
35 private $tasksCounts = [];
36
37 /** @var CronHelper */
38 private $cronHelper;
39
40 /** @var Supervisor */
41 private $supervisor;
42
43 /** @var SettingsController */
44 private $settings;
45
46 /** @var WPFunctions */
47 private $wp;
48
49 /** @var ServicesChecker */
50 private $serviceChecker;
51
52 /** @var ScheduledTasksRepository */
53 private $scheduledTasksRepository;
54
55 /** @var EntityManager */
56 private $entityManager;
57
58 public function __construct(
59 CronHelper $cronHelper,
60 Supervisor $supervisor,
61 SettingsController $settings,
62 ServicesChecker $serviceChecker,
63 WPFunctions $wp,
64 ScheduledTasksRepository $scheduledTasksRepository,
65 EntityManager $entityManager
66 ) {
67 $this->supervisor = $supervisor;
68 $this->settings = $settings;
69 $this->wp = $wp;
70 $this->cronHelper = $cronHelper;
71 $this->serviceChecker = $serviceChecker;
72 $this->scheduledTasksRepository = $scheduledTasksRepository;
73 $this->entityManager = $entityManager;
74 }
75
76 public function run() {
77 try {
78 if (!$this->checkRunInterval()) {
79 return false;
80 }
81 if (!$this->checkExecutionRequirements()) {
82 $this->stop();
83 return;
84 }
85
86 $this->supervisor->init();
87 return $this->supervisor->checkDaemon();
88 } catch (\Exception $e) {
89 $mySqlGoneAwayMessage = Helpers::mySqlGoneAwayExceptionHandler($e);
90 if ($mySqlGoneAwayMessage) {
91 throw new \Exception($mySqlGoneAwayMessage, 0, $e);
92 }
93 throw $e;
94 }
95 }
96
97 private function checkRunInterval(): bool {
98 $runInterval = $this->wp->applyFilters('mailpoet_cron_trigger_wordpress_run_interval', self::RUN_INTERVAL);
99 if ($runInterval === -1) {
100 return true;
101 }
102 $lastRunAt = (int)$this->settings->get(self::LAST_RUN_AT_SETTING, 0);
103 $runIntervalElapsed = (time() - $lastRunAt) >= $runInterval;
104 if ($runIntervalElapsed) {
105 $this->settings->set(self::LAST_RUN_AT_SETTING, time());
106 return true;
107 }
108 return false;
109 }
110
111 public static function resetRunInterval(): void {
112 $settings = SettingsController::getInstance();
113 $settings->set(self::LAST_RUN_AT_SETTING, 0);
114 }
115
116 public function checkExecutionRequirements(): bool {
117 if ($this->wp->wpIsMaintenanceMode()) {
118 // Skip if WP is currently in maintenance mode
119 // The maintenance mode is activated when WP core or a plugin update is in progress
120 return false;
121 }
122
123 $this->loadTasksCounts();
124
125 // Because a lot of workers has the same pattern for check if it's active we can use a loop here
126 $isSimpleWorkerActive = false;
127 foreach (WorkersFactory::SIMPLE_WORKER_TYPES as $simpleWorkerType) {
128 $tasksCount = $this->getTasksCount([
129 'type' => $simpleWorkerType,
130 'scheduled_in' => [self::SCHEDULED_IN_THE_PAST],
131 'status' => ['null', ScheduledTaskEntity::STATUS_SCHEDULED],
132 ]);
133 if ($tasksCount) {
134 $isSimpleWorkerActive = true;
135 break;
136 }
137 }
138
139 return (
140 $this->isSendingQueueActive()
141 || $this->isBounceActive()
142 || $this->isSendingServiceKeyCheckActive()
143 || $this->isPremiumKeyCheckActive()
144 || $this->isSubscriberStatsReportActive()
145 || $isSimpleWorkerActive
146 );
147 }
148
149 public function stop() {
150 $cronDaemon = $this->cronHelper->getDaemon();
151 if ($cronDaemon) {
152 $this->cronHelper->deactivateDaemon($cronDaemon);
153 }
154 }
155
156 private function isSendingQueueActive(): bool {
157 $scheduledQueues = $this->scheduledTasksRepository->findScheduledSendingTasks(SchedulerWorker::TASK_BATCH_SIZE);
158 $runningQueues = $this->scheduledTasksRepository->findRunningSendingTasks(SendingQueueWorker::TASK_BATCH_SIZE);
159 $sendingLimitReached = MailerLog::isSendingLimitReached();
160 $sendingIsPaused = MailerLog::isSendingPaused();
161 $sendingWaitingForRetry = MailerLog::isSendingWaitingForRetry();
162
163 return (($scheduledQueues || $runningQueues) && !$sendingLimitReached && !$sendingIsPaused && !$sendingWaitingForRetry);
164 }
165
166 private function isBounceActive(): bool {
167 $mpSendingEnabled = Bridge::isMPSendingServiceEnabled();
168 $bounceDueTasks = $this->getTasksCount([
169 'type' => BounceWorker::TASK_TYPE,
170 'scheduled_in' => [self::SCHEDULED_IN_THE_PAST],
171 'status' => ['null', ScheduledTaskEntity::STATUS_SCHEDULED],
172 ]);
173 $bounceFutureTasks = $this->getTasksCount([
174 'type' => BounceWorker::TASK_TYPE,
175 'scheduled_in' => [self::SCHEDULED_IN_THE_FUTURE],
176 'status' => [ScheduledTaskEntity::STATUS_SCHEDULED],
177 ]);
178
179 return ($mpSendingEnabled && ($bounceDueTasks || !$bounceFutureTasks));
180 }
181
182 private function isSendingServiceKeyCheckActive(): bool {
183 $mpSendingEnabled = Bridge::isMPSendingServiceEnabled();
184 $msskeycheckDueTasks = $this->getTasksCount([
185 'type' => SendingServiceKeyCheckWorker::TASK_TYPE,
186 'scheduled_in' => [self::SCHEDULED_IN_THE_PAST],
187 'status' => ['null', ScheduledTaskEntity::STATUS_SCHEDULED],
188 ]);
189 $msskeycheckFutureTasks = $this->getTasksCount([
190 'type' => SendingServiceKeyCheckWorker::TASK_TYPE,
191 'scheduled_in' => [self::SCHEDULED_IN_THE_FUTURE],
192 'status' => [ScheduledTaskEntity::STATUS_SCHEDULED],
193 ]);
194
195 return ($mpSendingEnabled && ($msskeycheckDueTasks || !$msskeycheckFutureTasks));
196 }
197
198 private function isPremiumKeyCheckActive(): bool {
199 $premiumKeySpecified = Bridge::isPremiumKeySpecified();
200 $premiumKeycheckDueTasks = $this->getTasksCount([
201 'type' => PremiumKeyCheckWorker::TASK_TYPE,
202 'scheduled_in' => [self::SCHEDULED_IN_THE_PAST],
203 'status' => ['null', ScheduledTaskEntity::STATUS_SCHEDULED],
204 ]);
205 $premiumKeycheckFutureTasks = $this->getTasksCount([
206 'type' => PremiumKeyCheckWorker::TASK_TYPE,
207 'scheduled_in' => [self::SCHEDULED_IN_THE_FUTURE],
208 'status' => [ScheduledTaskEntity::STATUS_SCHEDULED],
209 ]);
210
211 return ($premiumKeySpecified && ($premiumKeycheckDueTasks || !$premiumKeycheckFutureTasks));
212 }
213
214 private function isSubscriberStatsReportActive(): bool {
215 $validAccountKey = $this->serviceChecker->getValidAccountKey();
216 $statsReportDueTasks = $this->getTasksCount([
217 'type' => SubscribersStatsReport::TASK_TYPE,
218 'scheduled_in' => [self::SCHEDULED_IN_THE_PAST],
219 'status' => ['null', ScheduledTaskEntity::STATUS_SCHEDULED],
220 ]);
221 $statsReportFutureTasks = $this->getTasksCount([
222 'type' => SubscribersStatsReport::TASK_TYPE,
223 'scheduled_in' => [self::SCHEDULED_IN_THE_FUTURE],
224 'status' => [ScheduledTaskEntity::STATUS_SCHEDULED],
225 ]);
226
227 return ($validAccountKey && ($statsReportDueTasks || !$statsReportFutureTasks));
228 }
229
230 private function loadTasksCounts(): void {
231 $scheduledTasksTableName = $this->entityManager->getClassMetadata(ScheduledTaskEntity::class)->getTableName();
232 $sql = "
233 SELECT
234 type,
235 status,
236 count(*) AS count,
237 CASE WHEN scheduled_at <= :now THEN :past ELSE :future END AS scheduled_in
238 FROM $scheduledTasksTableName
239 WHERE deleted_at IS NULL AND (status != :statusCompleted OR status IS NULL)
240 GROUP BY type, status, scheduled_in";
241
242 $stmt = $this->entityManager->getConnection()->prepare($sql);
243 $stmt->bindValue('now', date('Y-m-d H:i:s', $this->wp->currentTime('timestamp', true)));
244 $stmt->bindValue('past', self::SCHEDULED_IN_THE_PAST);
245 $stmt->bindValue('future', self::SCHEDULED_IN_THE_FUTURE);
246 $stmt->bindValue('statusCompleted', ScheduledTaskEntity::STATUS_COMPLETED);
247 $rows = $stmt->executeQuery()->fetchAllAssociative();
248
249 $this->tasksCounts = [];
250 foreach ($rows as $r) {
251 $type = is_string($r['type']) ? $r['type'] : '';
252 $scheduledIn = is_string($r['scheduled_in']) ? $r['scheduled_in'] : '';
253 $status = is_string($r['status']) && $r['status'] !== '' ? $r['status'] : 'null';
254 $count = is_numeric($r['count']) ? (int)$r['count'] : 0;
255 if (empty($this->tasksCounts[$type])) {
256 $this->tasksCounts[$type] = [];
257 }
258 if (empty($this->tasksCounts[$type][$scheduledIn])) {
259 $this->tasksCounts[$type][$scheduledIn] = [];
260 }
261 $this->tasksCounts[$type][$scheduledIn][$status] = $count;
262 }
263 }
264
265 /**
266 * @param array{type: string, scheduled_in: list<string>, status: list<string>} $options
267 */
268 private function getTasksCount(array $options): int {
269 $count = 0;
270 $type = $options['type'];
271 foreach ($options['scheduled_in'] as $scheduledIn) {
272 foreach ($options['status'] as $status) {
273 if (!empty($this->tasksCounts[$type][$scheduledIn][$status])) {
274 $count += $this->tasksCounts[$type][$scheduledIn][$status];
275 }
276 }
277 }
278 return $count;
279 }
280 }
281