PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.21.2
MailPoet – Newsletters, Email Marketing, and Automation v5.21.2
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 / Newsletter / Scheduler / PostNotificationScheduler.php
mailpoet / lib / Newsletter / Scheduler Last commit date
AutomaticEmailScheduler.php 2 years ago AutomationEmailScheduler.php 1 year ago PostNotificationScheduler.php 2 years ago ReEngagementScheduler.php 1 year ago Scheduler.php 1 year ago WelcomeScheduler.php 2 years ago index.php 3 years ago
PostNotificationScheduler.php
217 lines
1 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
2
3 namespace MailPoet\Newsletter\Scheduler;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\Cron\Workers\SendingQueue\SendingQueue;
9 use MailPoet\Entities\NewsletterEntity;
10 use MailPoet\Entities\NewsletterOptionEntity;
11 use MailPoet\Entities\NewsletterOptionFieldEntity;
12 use MailPoet\Entities\ScheduledTaskEntity;
13 use MailPoet\Entities\SendingQueueEntity;
14 use MailPoet\Logging\LoggerFactory;
15 use MailPoet\Newsletter\NewsletterPostsRepository;
16 use MailPoet\Newsletter\NewslettersRepository;
17 use MailPoet\Newsletter\Options\NewsletterOptionFieldsRepository;
18 use MailPoet\Newsletter\Options\NewsletterOptionsRepository;
19 use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
20 use MailPoet\Newsletter\Sending\SendingQueuesRepository;
21 use MailPoet\WP\DateTime;
22 use MailPoet\WP\Posts;
23
24 class PostNotificationScheduler {
25
26 const SECONDS_IN_MINUTE = 60;
27 const SECONDS_IN_HOUR = 3600;
28 const LAST_WEEKDAY_FORMAT = 'L';
29 const INTERVAL_DAILY = 'daily';
30 const INTERVAL_IMMEDIATELY = 'immediately';
31 const INTERVAL_NTHWEEKDAY = 'nthWeekDay';
32 const INTERVAL_WEEKLY = 'weekly';
33 const INTERVAL_IMMEDIATE = 'immediate';
34 const INTERVAL_MONTHLY = 'monthly';
35
36 /** @var LoggerFactory */
37 private $loggerFactory;
38
39 /** @var NewslettersRepository */
40 private $newslettersRepository;
41
42 /** @var NewsletterOptionsRepository */
43 private $newsletterOptionsRepository;
44
45 /** @var NewsletterOptionFieldsRepository */
46 private $newsletterOptionFieldsRepository;
47
48 /** @var NewsletterPostsRepository */
49 private $newsletterPostsRepository;
50
51 /** @var Scheduler */
52 private $scheduler;
53
54 /*** @var ScheduledTasksRepository */
55 private $scheduledTasksRepository;
56
57 /*** @var SendingQueuesRepository */
58 private $sendingQueuesRepository;
59
60 public function __construct(
61 NewslettersRepository $newslettersRepository,
62 NewsletterOptionsRepository $newsletterOptionsRepository,
63 NewsletterOptionFieldsRepository $newsletterOptionFieldsRepository,
64 NewsletterPostsRepository $newsletterPostsRepository,
65 Scheduler $scheduler,
66 ScheduledTasksRepository $scheduledTasksRepository,
67 SendingQueuesRepository $sendingQueuesRepository
68 ) {
69 $this->loggerFactory = LoggerFactory::getInstance();
70 $this->newslettersRepository = $newslettersRepository;
71 $this->newsletterOptionsRepository = $newsletterOptionsRepository;
72 $this->newsletterOptionFieldsRepository = $newsletterOptionFieldsRepository;
73 $this->newsletterPostsRepository = $newsletterPostsRepository;
74 $this->scheduler = $scheduler;
75 $this->scheduledTasksRepository = $scheduledTasksRepository;
76 $this->sendingQueuesRepository = $sendingQueuesRepository;
77 }
78
79 public function transitionHook($newStatus, $oldStatus, $post) {
80 $this->loggerFactory->getLogger(LoggerFactory::TOPIC_POST_NOTIFICATIONS)->info(
81 'transition post notification hook initiated',
82 [
83 'post_id' => $post->ID,
84 'new_status' => $newStatus,
85 'old_status' => $oldStatus,
86 ]
87 );
88 $types = Posts::getTypes();
89 if (($newStatus !== 'publish') || $oldStatus === 'publish' || !isset($types[$post->post_type])) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
90 return;
91 }
92 $this->schedulePostNotification($post->ID);
93 }
94
95 public function schedulePostNotification($postId) {
96 $this->loggerFactory->getLogger(LoggerFactory::TOPIC_POST_NOTIFICATIONS)->info(
97 'schedule post notification hook',
98 ['post_id' => $postId]
99 );
100 $newsletters = $this->newslettersRepository->findActiveByTypes([NewsletterEntity::TYPE_NOTIFICATION]);
101 $this->newslettersRepository->prefetchOptions($newsletters);
102 if (!count($newsletters)) {
103 return false;
104 }
105 foreach ($newsletters as $newsletter) {
106 $post = $this->newsletterPostsRepository->findOneBy([
107 'newsletter' => $newsletter,
108 'postId' => $postId,
109 ]);
110 if ($post === null) {
111 $this->createPostNotificationSendingTask($newsletter);
112 }
113 }
114 }
115
116 public function createPostNotificationSendingTask(NewsletterEntity $newsletter): ?ScheduledTaskEntity {
117 $notificationHistory = $this->newslettersRepository->findSendingNotificationHistoryWithoutPausedOrInvalidTask($newsletter);
118 if (count($notificationHistory) > 0) {
119 return null;
120 }
121
122 $scheduleOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_SCHEDULE);
123 if (!$scheduleOption) {
124 return null;
125 }
126 $nextRunDate = $this->scheduler->getNextRunDateTime($scheduleOption->getValue());
127 if (!$nextRunDate) {
128 return null;
129 }
130
131 // do not schedule duplicate queues for the same time
132 $lastQueue = $newsletter->getLatestQueue();
133 $task = $lastQueue !== null ? $lastQueue->getTask() : null;
134 $scheduledAt = $task !== null ? $task->getScheduledAt() : null;
135 if ($scheduledAt && $scheduledAt->format('Y-m-d H:i:s') === $nextRunDate->format('Y-m-d H:i:s')) {
136 return null;
137 }
138
139 $scheduledTask = new ScheduledTaskEntity();
140 $scheduledTask->setType(SendingQueue::TASK_TYPE);
141 $scheduledTask->setStatus(ScheduledTaskEntity::STATUS_SCHEDULED);
142 $scheduledTask->setScheduledAt($nextRunDate);
143 $scheduledTask->setPriority(ScheduledTaskEntity::PRIORITY_MEDIUM);
144 $this->scheduledTasksRepository->persist($scheduledTask);
145 $this->scheduledTasksRepository->flush();
146
147 $sendingQueue = new SendingQueueEntity();
148 $sendingQueue->setNewsletter($newsletter);
149 $sendingQueue->setTask($scheduledTask);
150 $this->sendingQueuesRepository->persist($sendingQueue);
151 $this->sendingQueuesRepository->flush();
152 $scheduledTask->setSendingQueue($sendingQueue);
153
154 $this->loggerFactory->getLogger(LoggerFactory::TOPIC_POST_NOTIFICATIONS)->info(
155 'schedule post notification',
156 [
157 'sending_task' => $scheduledTask->getId(),
158 'scheduled_at' => $nextRunDate->format(DateTime::DEFAULT_DATE_TIME_FORMAT),
159 ]
160 );
161 return $scheduledTask;
162 }
163
164 public function processPostNotificationSchedule(NewsletterEntity $newsletter) {
165 $intervalTypeOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_INTERVAL_TYPE);
166 $intervalType = $intervalTypeOption ? $intervalTypeOption->getValue() : null;
167
168 $timeOfDayOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_TIME_OF_DAY);
169 $hour = $timeOfDayOption ? (int)floor((int)$timeOfDayOption->getValue() / self::SECONDS_IN_HOUR) : null;
170 $minute = $timeOfDayOption ? ((int)$timeOfDayOption->getValue() - (int)($hour * self::SECONDS_IN_HOUR)) / self::SECONDS_IN_MINUTE : null;
171
172 $weekDayOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_WEEK_DAY);
173 $weekDay = $weekDayOption ? $weekDayOption->getValue() : null;
174
175 $monthDayOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_MONTH_DAY);
176 $monthDay = $monthDayOption ? $monthDayOption->getValue() : null;
177
178 $nthWeekDayOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_NTH_WEEK_DAY);
179 $nthWeekDay = $nthWeekDayOption ? $nthWeekDayOption->getValue() : null;
180 $nthWeekDay = ($nthWeekDay === self::LAST_WEEKDAY_FORMAT) ? $nthWeekDay : '#' . $nthWeekDay;
181 switch ($intervalType) {
182 case self::INTERVAL_IMMEDIATE:
183 case self::INTERVAL_DAILY:
184 $schedule = sprintf('%s %s * * *', $minute, $hour);
185 break;
186 case self::INTERVAL_WEEKLY:
187 $schedule = sprintf('%s %s * * %s', $minute, $hour, $weekDay);
188 break;
189 case self::INTERVAL_NTHWEEKDAY:
190 $schedule = sprintf('%s %s ? * %s%s', $minute, $hour, $weekDay, $nthWeekDay);
191 break;
192 case self::INTERVAL_MONTHLY:
193 $schedule = sprintf('%s %s %s * *', $minute, $hour, $monthDay);
194 break;
195 case self::INTERVAL_IMMEDIATELY:
196 default:
197 $schedule = '* * * * *';
198 break;
199 }
200 $optionField = $this->newsletterOptionFieldsRepository->findOneBy([
201 'name' => NewsletterOptionFieldEntity::NAME_SCHEDULE,
202 ]);
203 if (!$optionField instanceof NewsletterOptionFieldEntity) {
204 throw new \Exception('NewsletterOptionField for schedule doesn’t exist.');
205 }
206 $scheduleOption = $newsletter->getOption(NewsletterOptionFieldEntity::NAME_SCHEDULE);
207 if ($scheduleOption === null) {
208 $scheduleOption = new NewsletterOptionEntity($newsletter, $optionField);
209 $newsletter->getOptions()->add($scheduleOption);
210 }
211 $scheduleOption->setValue($schedule);
212 $this->newsletterOptionsRepository->persist($scheduleOption);
213 $this->newsletterOptionsRepository->flush();
214 return $scheduleOption->getValue();
215 }
216 }
217