PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 3.18.1
MailPoet – Newsletters, Email Marketing, and Automation v3.18.1
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 / Scheduler.php
mailpoet / lib / Newsletter / Scheduler Last commit date
Scheduler.php 7 years ago index.php 9 years ago
Scheduler.php
281 lines
1 <?php
2
3 namespace MailPoet\Newsletter\Scheduler;
4
5 use Carbon\Carbon;
6 use MailPoet\Logging\Logger;
7 use MailPoet\Models\Newsletter;
8 use MailPoet\Models\NewsletterOption;
9 use MailPoet\Models\NewsletterOptionField;
10 use MailPoet\Models\NewsletterPost;
11 use MailPoet\Models\ScheduledTask;
12 use MailPoet\Models\SendingQueue;
13 use MailPoet\Tasks\Sending as SendingTask;
14 use MailPoet\WP\Functions as WPFunctions;
15 use MailPoet\WP\Posts;
16
17 class Scheduler {
18 const SECONDS_IN_HOUR = 3600;
19 const LAST_WEEKDAY_FORMAT = 'L';
20 const WORDPRESS_ALL_ROLES = 'mailpoet_all';
21 const INTERVAL_IMMEDIATELY = 'immediately';
22 const INTERVAL_IMMEDIATE = 'immediate';
23 const INTERVAL_DAILY = 'daily';
24 const INTERVAL_WEEKLY = 'weekly';
25 const INTERVAL_MONTHLY = 'monthly';
26 const INTERVAL_NTHWEEKDAY = 'nthWeekDay';
27
28 static function transitionHook($new_status, $old_status, $post) {
29 Logger::getLogger('post-notifications')->addInfo(
30 'transition post notification hook initiated',
31 [
32 'post_id' => $post->ID,
33 'new_status' => $new_status,
34 'old_status' => $old_status,
35 ]
36 );
37 $types = Posts::getTypes();
38 if(($new_status !== 'publish') || !isset($types[$post->post_type])) {
39 return;
40 }
41 self::schedulePostNotification($post->ID);
42 }
43
44 static function schedulePostNotification($post_id) {
45 Logger::getLogger('post-notifications')->addInfo(
46 'schedule post notification hook',
47 ['post_id' => $post_id]
48 );
49 $newsletters = self::getNewsletters(Newsletter::TYPE_NOTIFICATION);
50 if(!count($newsletters)) return false;
51 foreach($newsletters as $newsletter) {
52 $post = NewsletterPost::where('newsletter_id', $newsletter->id)
53 ->where('post_id', $post_id)
54 ->findOne();
55 if($post === false) {
56 self::createPostNotificationSendingTask($newsletter);
57 }
58 }
59 }
60
61 static function scheduleSubscriberWelcomeNotification($subscriber_id, $segments) {
62 $newsletters = self::getNewsletters(Newsletter::TYPE_WELCOME);
63 if(empty($newsletters)) return false;
64 $result = array();
65 foreach($newsletters as $newsletter) {
66 if($newsletter->event === 'segment' &&
67 in_array($newsletter->segment, $segments)
68 ) {
69 $result[] = self::createWelcomeNotificationSendingTask($newsletter, $subscriber_id);
70 }
71 }
72 return $result;
73 }
74
75 static function scheduleAutomaticEmail($group, $event, $scheduling_condition = false, $subscriber_id = false, $meta = false) {
76 $newsletters = self::getNewsletters(Newsletter::TYPE_AUTOMATIC, $group);
77 if(empty($newsletters)) return false;
78 foreach($newsletters as $newsletter) {
79 if($newsletter->event !== $event) continue;
80 if(is_callable($scheduling_condition) && !$scheduling_condition($newsletter)) continue;
81 self::createAutomaticEmailSendingTask($newsletter, $subscriber_id, $meta);
82 }
83 }
84
85 static function scheduleWPUserWelcomeNotification(
86 $subscriber_id,
87 $wp_user,
88 $old_user_data = false
89 ) {
90 $newsletters = self::getNewsletters(Newsletter::TYPE_WELCOME);
91 if(empty($newsletters)) return false;
92 foreach($newsletters as $newsletter) {
93 if($newsletter->event === 'user') {
94 if(!empty($old_user_data['roles'])) {
95 // do not schedule welcome newsletter if roles have not changed
96 $old_role = $old_user_data['roles'];
97 $new_role = $wp_user['roles'];
98 if($newsletter->role === self::WORDPRESS_ALL_ROLES ||
99 !array_diff($old_role, $new_role)
100 ) {
101 continue;
102 }
103 }
104 if($newsletter->role === self::WORDPRESS_ALL_ROLES ||
105 in_array($newsletter->role, $wp_user['roles'])
106 ) {
107 self::createWelcomeNotificationSendingTask($newsletter, $subscriber_id);
108 }
109 }
110 }
111 }
112
113 static function createWelcomeNotificationSendingTask($newsletter, $subscriber_id) {
114 $previously_scheduled_notification = SendingQueue::joinWithSubscribers()
115 ->where('queues.newsletter_id', $newsletter->id)
116 ->where('subscribers.subscriber_id', $subscriber_id)
117 ->findOne();
118 if(!empty($previously_scheduled_notification)) return;
119 $sending_task = SendingTask::create();
120 $sending_task->newsletter_id = $newsletter->id;
121 $sending_task->setSubscribers(array($subscriber_id));
122 $sending_task->status = SendingQueue::STATUS_SCHEDULED;
123 $sending_task->priority = SendingQueue::PRIORITY_HIGH;
124 $sending_task->scheduled_at = self::getScheduledTimeWithDelay(
125 $newsletter->afterTimeType,
126 $newsletter->afterTimeNumber
127 );
128 return $sending_task->save();
129 }
130
131 static function createAutomaticEmailSendingTask($newsletter, $subscriber_id, $meta) {
132 $sending_task = SendingTask::create();
133 $sending_task->newsletter_id = $newsletter->id;
134 if($newsletter->sendTo === 'user' && $subscriber_id) {
135 $sending_task->setSubscribers(array($subscriber_id));
136 }
137 if($meta) {
138 $sending_task->__set('meta', $meta);
139 }
140 $sending_task->status = SendingQueue::STATUS_SCHEDULED;
141 $sending_task->priority = SendingQueue::PRIORITY_MEDIUM;
142 $sending_task->scheduled_at = self::getScheduledTimeWithDelay(
143 $newsletter->afterTimeType,
144 $newsletter->afterTimeNumber
145 );
146 return $sending_task->save();
147 }
148
149 static function createPostNotificationSendingTask($newsletter) {
150 $existing_notification_history = Newsletter::table_alias('newsletters')
151 ->where('newsletters.parent_id', $newsletter->id)
152 ->where('newsletters.type', Newsletter::TYPE_NOTIFICATION_HISTORY)
153 ->where('newsletters.status', Newsletter::STATUS_SENDING)
154 ->join(
155 MP_SENDING_QUEUES_TABLE,
156 'queues.newsletter_id = newsletters.id',
157 'queues'
158 )
159 ->join(
160 MP_SCHEDULED_TASKS_TABLE,
161 'queues.task_id = tasks.id',
162 'tasks'
163 )
164 ->whereNotEqual('tasks.status', ScheduledTask::STATUS_PAUSED)
165 ->findOne();
166 if($existing_notification_history) {
167 return;
168 }
169 $next_run_date = self::getNextRunDate($newsletter->schedule);
170 if(!$next_run_date) return;
171 // do not schedule duplicate queues for the same time
172 $existing_queue = SendingQueue::findTaskByNewsletterId($newsletter->id)
173 ->where('tasks.scheduled_at', $next_run_date)
174 ->findOne();
175 if($existing_queue) return;
176 $sending_task = SendingTask::create();
177 $sending_task->newsletter_id = $newsletter->id;
178 $sending_task->status = SendingQueue::STATUS_SCHEDULED;
179 $sending_task->scheduled_at = $next_run_date;
180 $sending_task->save();
181 Logger::getLogger('post-notifications')->addInfo(
182 'schedule post notification',
183 ['sending_task' => $sending_task->id(), 'scheduled_at' => $next_run_date]
184 );
185 return $sending_task;
186 }
187
188 static function processPostNotificationSchedule($newsletter) {
189 $interval_type = $newsletter->intervalType;
190 $hour = (int)$newsletter->timeOfDay / self::SECONDS_IN_HOUR;
191 $week_day = $newsletter->weekDay;
192 $month_day = $newsletter->monthDay;
193 $nth_week_day = ($newsletter->nthWeekDay === self::LAST_WEEKDAY_FORMAT) ?
194 $newsletter->nthWeekDay :
195 '#' . $newsletter->nthWeekDay;
196 switch($interval_type) {
197 case self::INTERVAL_IMMEDIATELY:
198 $schedule = '* * * * *';
199 break;
200 case self::INTERVAL_IMMEDIATE:
201 case self::INTERVAL_DAILY:
202 $schedule = sprintf('0 %s * * *', $hour);
203 break;
204 case self::INTERVAL_WEEKLY:
205 $schedule = sprintf('0 %s * * %s', $hour, $week_day);
206 break;
207 case self::INTERVAL_NTHWEEKDAY:
208 $schedule = sprintf('0 %s ? * %s%s', $hour, $week_day, $nth_week_day);
209 break;
210 case self::INTERVAL_MONTHLY:
211 $schedule = sprintf('0 %s %s * *', $hour, $month_day);
212 break;
213 }
214 $option_field = NewsletterOptionField::where('name', 'schedule')->findOne();
215 $relation = NewsletterOption::where('newsletter_id', $newsletter->id)
216 ->where('option_field_id', $option_field->id)
217 ->findOne();
218 if(!$relation) {
219 $relation = NewsletterOption::create();
220 $relation->newsletter_id = $newsletter->id;
221 $relation->option_field_id = $option_field->id;
222 }
223 $relation->value = $schedule;
224 $relation->save();
225 return $relation->value;
226 }
227
228 static function getNextRunDate($schedule, $from_timestamp = false) {
229 $wp = new WPFunctions();
230 $from_timestamp = ($from_timestamp) ? $from_timestamp : $wp->currentTime('timestamp');
231 try {
232 $schedule = \Cron\CronExpression::factory($schedule);
233 $next_run_date = $schedule->getNextRunDate(Carbon::createFromTimestamp($from_timestamp))
234 ->format('Y-m-d H:i:s');
235 } catch(\Exception $e) {
236 $next_run_date = false;
237 }
238 return $next_run_date;
239 }
240
241 static function getPreviousRunDate($schedule, $from_timestamp = false) {
242 $wp = new WPFunctions();
243 $from_timestamp = ($from_timestamp) ? $from_timestamp : $wp->currentTime('timestamp');
244 try {
245 $schedule = \Cron\CronExpression::factory($schedule);
246 $previous_run_date = $schedule->getPreviousRunDate(Carbon::createFromTimestamp($from_timestamp))
247 ->format('Y-m-d H:i:s');
248 } catch(\Exception $e) {
249 $previous_run_date = false;
250 }
251 return $previous_run_date;
252 }
253
254 static function getScheduledTimeWithDelay($after_time_type, $after_time_number) {
255 $wp = new WPFunctions();
256 $current_time = Carbon::createFromTimestamp($wp->currentTime('timestamp'));
257 switch($after_time_type) {
258 case 'hours':
259 return $current_time->addHours($after_time_number);
260 case 'days':
261 return $current_time->addDays($after_time_number);
262 case 'weeks':
263 return $current_time->addWeeks($after_time_number);
264 default:
265 return $current_time;
266 }
267 }
268
269 static function getNewsletters($type, $group = false) {
270 return Newsletter::getPublished()
271 ->filter('filterType', $type, $group)
272 ->filter('filterStatus', Newsletter::STATUS_ACTIVE)
273 ->filter('filterWithOptions', $type)
274 ->findMany();
275 }
276
277 static function formatDatetimeString($datetime_string) {
278 return Carbon::parse($datetime_string)->format('Y-m-d H:i:s');
279 }
280 }
281