PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
acymailing / back / dynamics / time / TimeAutomationTriggers.php

TimeAutomationTriggers.php in AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress 11.1.0, at back/dynamics/time/TimeAutomationTriggers.php

501 lines 19.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 trait TimeAutomationTriggers
4 {
5 protected function initAutomationTriggers(): void
6 {
7 $this->automationTriggers['classic'] = [
8 'asap' => acym_translation('ACYM_EACH_TIME'),
9 'day' => acym_translation('ACYM_EVERY_DAY_AT'),
10 'weeks_on' => acym_translation('ACYM_EVERY_WEEK_ON'),
11 'on_day_month' => acym_translation('ACYM_ONTHE'),
12 'every' => acym_translation('ACYM_EVERY'),
13 ];
14 }
15
16 public function displayTriggerOptions_asap(string $fieldName): void
17 {
18 echo '<input type="hidden" name="'.esc_attr($fieldName).'" value="y">';
19 }
20
21 public function displayTriggerOptions_day(string $fieldName, array $defaultValues): void
22 {
23 ?>
24 <div class="grid-x grid-margin-x" style="height: 40px;">
25 <div class="cell medium-shrink">
26 <?php
27 acym_select(
28 $this->getTriggerHours(),
29 $fieldName.'[hour]',
30 empty($defaultValues['day']) ? acym_date('now', 'H') : $defaultValues['day']['hour'],
31 ['data-class' => 'intext_select acym__select'],
32 'value',
33 'text',
34 null,
35 false,
36 true
37 );
38 ?>
39 </div>
40 <div class="cell medium-shrink acym_vcenter">:</div>
41 <div class="cell medium-auto">
42 <?php
43 acym_select(
44 $this->getTriggerMinutes(),
45 $fieldName.'[minutes]',
46 empty($defaultValues['day']) ? acym_date('now', 'i') : $defaultValues['day']['minutes'],
47 ['data-class' => 'intext_select acym__select'],
48 'value',
49 'text',
50 null,
51 false,
52 true
53 );
54 ?>
55 </div>
56 </div>
57 <?php
58 }
59
60 public function displayTriggerOptions_weeks_on(string $fieldName, array $defaultValues): void
61 {
62 ?>
63 <div class="grid-x">
64 <div class="cell">
65 <?php acym_selectMultiple(
66 $this->getTriggerDays(),
67 $fieldName.'[day]',
68 empty($defaultValues['weeks_on']) ? ['monday'] : $defaultValues['weeks_on']['day'],
69 ['data-class' => 'acym__select'],
70 'value',
71 'text',
72 true
73 ); ?>
74 </div>
75 <div class="cell margin-top-1 acym_vcenter">
76 <?php $this->displayTriggerTimeSentence($fieldName, empty($defaultValues['weeks_on']) ? [] : $defaultValues['weeks_on']); ?>
77 </div>
78 </div>
79 <?php
80 }
81
82 public function displayTriggerOptions_on_day_month(string $fieldName, array $defaultValues): void
83 {
84 $numbers = [
85 'first' => acym_translation('ACYM_FIRST'),
86 'second' => acym_translation('ACYM_SECOND'),
87 'third' => acym_translation('ACYM_THIRD'),
88 'fourth' => acym_translation('ACYM_FOURTH'),
89 'last' => acym_translation('ACYM_LAST'),
90 ];
91 ?>
92 <div class="grid-x grid-margin-x margin-y">
93 <div class="cell medium-4">
94 <?php acym_select(
95 $numbers,
96 $fieldName.'[number]',
97 empty($defaultValues['on_day_month']) ? null : $defaultValues['on_day_month']['number'],
98 ['data-class' => 'acym__select'],
99 'value',
100 'text',
101 null,
102 false,
103 true
104 ); ?>
105 </div>
106 <div class="cell medium-4">
107 <?php acym_select(
108 $this->getTriggerDays(),
109 $fieldName.'[day]',
110 empty($defaultValues['on_day_month']) ? null : $defaultValues['on_day_month']['day'],
111 [
112 'data-class' => 'acym__select',
113 'style' => 'margin: 0 10px;',
114 ],
115 'value',
116 'text',
117 null,
118 false,
119 true
120 ); ?>
121 </div>
122 <div class="cell medium-4 acym_vcenter"><?php echo esc_html(acym_translation('ACYM_DAYOFMONTH')); ?></div>
123 <div class="cell acym_vcenter">
124 <?php $this->displayTriggerTimeSentence($fieldName, empty($defaultValues['on_day_month']) ? [] : $defaultValues['on_day_month']); ?>
125 </div>
126 </div>
127 <?php
128 }
129
130 public function displayTriggerOptions_every(string $fieldName, array $defaultValues): void
131 {
132 $every = [
133 '3600' => acym_translation('ACYM_HOURS'),
134 '86400' => acym_translation('ACYM_DAYS'),
135 '604800' => acym_translation('ACYM_WEEKS'),
136 '2628000' => acym_translation('ACYM_MONTHS'),
137 ];
138
139 $defaultEvery = empty($defaultValues['every']['number']) ? '1' : $defaultValues['every']['number'];
140 ?>
141 <div class="grid-x grid-margin-x">
142 <div class="cell medium-shrink">
143 <input type="number"
144 min="1"
145 name="<?php echo esc_attr($fieldName.'[number]'); ?>"
146 class="intext_input"
147 value="<?php echo intval($defaultEvery); ?>">
148 </div>
149 <div class="cell medium-auto">
150 <?php acym_select(
151 $every,
152 $fieldName.'[type]',
153 empty($defaultValues['every']) ? '604800' : $defaultValues['every']['type'],
154 ['data-class' => 'intext_select acym__select'],
155 'value',
156 'text',
157 null,
158 false,
159 true
160 ); ?>
161 </div>
162 </div>
163 <?php
164 }
165
166 private function displayTriggerTimeSentence(string $fieldName, array $defaults): void
167 {
168 $hourSelect = '<div class="margin-left-1 margin-right-1">'.acym_select(
169 $this->getTriggerHours(),
170 $fieldName.'[hour]',
171 $defaults['hour'] ?? $this->config->get('daily_hour', '12'),
172 ['data-class' => 'intext_select acym__select']
173 ).'</div>';
174
175 $minuteSelect = '<div class="margin-left-1 margin-right-1">'.acym_select(
176 $this->getTriggerMinutes(),
177 $fieldName.'[minutes]',
178 $defaults['minutes'] ?? $this->config->get('daily_minute', '00'),
179 ['data-class' => 'intext_select acym__select']
180 ).'</div>';
181
182 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Both selects are built and escaped by acym_select just above, and the translation itself holds HTML entities on purpose.
183 echo acym_translationSprintf('ACYM_AT_DATE_TIME', $hourSelect, $minuteSelect);
184 }
185
186 private function getTriggerHours(): array
187 {
188 $hours = [];
189 for ($i = 0; $i <= 23; $i++) {
190 $hours[$i] = $i < 10 ? '0'.$i : $i;
191 }
192
193 return $hours;
194 }
195
196 private function getTriggerMinutes(): array
197 {
198 $minutes = [];
199 for ($i = 0; $i <= 59; $i++) {
200 $minutes[$i] = $i < 10 ? '0'.$i : $i;
201 }
202
203 return $minutes;
204 }
205
206 private function getTriggerDays(): array
207 {
208 return [
209 'monday' => acym_translation('ACYM_MONDAY'),
210 'tuesday' => acym_translation('ACYM_TUESDAY'),
211 'wednesday' => acym_translation('ACYM_WEDNESDAY'),
212 'thursday' => acym_translation('ACYM_THURSDAY'),
213 'friday' => acym_translation('ACYM_FRIDAY'),
214 'saturday' => acym_translation('ACYM_SATURDAY'),
215 'sunday' => acym_translation('ACYM_SUNDAY'),
216 ];
217 }
218
219 public function onAcymExecuteTrigger(&$step, &$execute, &$data)
220 {
221 if (!empty($step->is_scenario)) {
222 return;
223 }
224
225 $time = $data['time'];
226 $triggers = $step->triggers;
227
228 // For each trigger of the automation, we'll calculate the next execution date. In the end we take the closest one
229 $nextExecutionDate = [];
230
231 // Get the time the auto tasks should be triggered
232 $dailyHour = $this->config->get('daily_hour', '12');
233 $dailyMinute = $this->config->get('daily_minute', '00');
234
235
236 // Each time the cron is triggered
237 if (!empty($triggers['asap'])) {
238 $execute = true;
239 $nextExecutionDate[] = $time;
240 }
241
242 // Every day at xx:xx
243 if (!empty($triggers['day'])) {
244 // The day it is currently based on the timezone specified in the CMS configuration
245 $dayBasedOnCMSTimezone = acym_date('now', 'Y-m-d');
246
247 $hour = $triggers['day']['hour'];
248 $minutes = $triggers['day']['minutes'];
249
250 if (strlen($hour) < 2) $hour = '0'.$hour;
251 if (strlen($minutes) < 2) $minutes = '0'.$minutes;
252
253 // The UTC timestamp of the current day based on the CMS timezone, at the specified hour
254 $dayBasedOnCMSTimezoneAtSpecifiedHour = acym_getTimeFromCMSDate($dayBasedOnCMSTimezone.' '.$hour.':'.$minutes);
255
256 if ($time < $dayBasedOnCMSTimezoneAtSpecifiedHour) {
257 $nextExecutionDate[] = $dayBasedOnCMSTimezoneAtSpecifiedHour;
258 } else {
259 $nextExecutionDate[] = $dayBasedOnCMSTimezoneAtSpecifiedHour + 86400;
260
261 // First trigger: if the hour is passed we execute
262 if (empty($step->last_execution)) $execute = true;
263 }
264 }
265
266 // Each week on Mondays and Wednesdays for example
267 if (!empty($triggers['weeks_on'])) {
268 if (isset($triggers['weeks_on']['hour'])) {
269 $hour = $triggers['weeks_on']['hour'];
270 $minutes = $triggers['weeks_on']['minutes'];
271 } else {
272 $hour = $dailyHour;
273 $minutes = $dailyMinute;
274 }
275
276 if (strlen($hour) < 2) $hour = '0'.$hour;
277 if (strlen($minutes) < 2) $minutes = '0'.$minutes;
278
279 foreach ($triggers['weeks_on']['day'] as $day) {
280 // The day it is currently based on the timezone specified in the CMS configuration
281 $dayBasedOnCMSTimezone = acym_date('now', 'Y-m-d');
282
283 // The UTC timestamp of the current day based on the CMS timezone, at the specified hour
284 $dayBasedOnCMSTimezoneAtSpecifiedHour = acym_getTimeFromCMSDate($dayBasedOnCMSTimezone.' '.$hour.':'.$minutes);
285
286 // Only store the next Execution date if it's in the future
287 if ($day == strtolower(acym_date('now', 'l', true, false))) {
288 if ($time < $dayBasedOnCMSTimezoneAtSpecifiedHour) {
289 $nextExecutionDate[] = $dayBasedOnCMSTimezoneAtSpecifiedHour;
290 } else {
291 $nextExecutionDate[] = $dayBasedOnCMSTimezoneAtSpecifiedHour + 604800;
292
293 // Current day is selected, the time is passed, and it's the first trigger
294 $lastExecutionIsNotToday = acym_date($step->last_execution, 'Y-m-d') !== $dayBasedOnCMSTimezone;
295 $nextExecutionIsToday = acym_date($step->next_execution, 'Y-m-d') === $dayBasedOnCMSTimezone;
296 if (empty($step->last_execution) || ($lastExecutionIsNotToday && $nextExecutionIsToday)) $execute = true;
297 }
298 } else {
299 $days = [
300 'monday',
301 'tuesday',
302 'wednesday',
303 'thursday',
304 'friday',
305 'saturday',
306 'sunday',
307 ];
308 $currentDayOfWeek = acym_date('now', 'N') - 1;
309 $wantedDayOfWeek = array_search($day, $days);
310
311 $shift = $wantedDayOfWeek - $currentDayOfWeek;
312 if ($shift < 0) $shift += 7;
313
314 $nextExecutionDate[] = $dayBasedOnCMSTimezoneAtSpecifiedHour + 86400 * $shift;
315 }
316 }
317 }
318
319 // On first Friday of the month for example
320 if (!empty($triggers['on_day_month'])) {
321 if (isset($triggers['on_day_month']['hour'])) {
322 $hour = $triggers['on_day_month']['hour'];
323 $minutes = $triggers['on_day_month']['minutes'];
324 } else {
325 $hour = $dailyHour;
326 $minutes = $dailyMinute;
327 }
328
329 if (strlen($hour) < 2) $hour = '0'.$hour;
330 if (strlen($minutes) < 2) $minutes = '0'.$minutes;
331
332 $today = acym_getTime('today '.$hour.':'.$minutes);
333
334 // Get the current month's day
335 $execution = acym_getTime($triggers['on_day_month']['number'].' '.$triggers['on_day_month']['day'].' of this month '.$hour.':'.$minutes);
336
337 //If it's before today, get the next date
338 if ($execution < $today) {
339 $execution = acym_getTime($triggers['on_day_month']['number'].' '.$triggers['on_day_month']['day'].' of next month '.$hour.':'.$minutes);
340 }
341
342 // The next execution date is in the future
343 if ($execution > $time) {
344 $nextExecutionDate[] = $execution;
345 } else {
346 // The next execution is today and is passed
347
348
349 // If it's the first trigger we execute
350 if (empty($step->last_execution)) {
351 $execute = true;
352 }
353
354 // Set the next execution time: recompute the real "next weekday of next month" occurrence.
355 $nextExecutionDate[] = acym_getTime($triggers['on_day_month']['number'].' '.$triggers['on_day_month']['day'].' of next month '.$hour.':'.$minutes);
356 }
357 }
358
359 // WARNING : KEEP THIS TRIGGER AT THE END, ACTION PERFORMED IF WE EXECUTE
360 // Every X hours/days/weeks/months
361 if (!empty($triggers['every'])) {
362 // First trigger: we execute and set the next execution in X hours/days/weeks/months
363 if (empty($step->last_execution)) {
364 $execute = true;
365 } else {
366 if ($triggers['every']['type'] == 2628000) {
367 $nextDate = new \DateTime(acym_date($step->last_execution, 'Y-m-d H:i:s', false), new \DateTimeZone('UTC'));
368 $nextDate = $nextDate->add(new \DateInterval('P'.$triggers['every']['number'].'M'));
369 $nextDate = $nextDate->getTimestamp();
370 } else {
371 $nextDate = $step->last_execution + ($triggers['every']['number'] * $triggers['every']['type']);
372 }
373
374 if ($nextDate > $time) {
375 $nextExecutionDate[] = $nextDate;
376 } else {
377 $execute = true;
378 }
379 }
380
381 if ($execute) {
382 $nextExecutionDate[] = $time + ($triggers['every']['number'] * $triggers['every']['type']);
383 }
384 }
385
386 if (!empty($nextExecutionDate)) {
387 $step->next_execution = min($nextExecutionDate);
388 }
389 }
390
391 public function onAcymDeclareSummary_triggers(object $automation): void
392 {
393 if (!empty($automation->triggers['type_trigger'])) {
394 unset($automation->triggers['type_trigger']);
395 }
396
397 $days = $this->getTriggerDays();
398
399 $this->summaryAsap($automation);
400 $this->summaryDay($automation);
401 $this->summaryWeeksOn($automation, $days);
402 $this->summaryOnDayMonth($automation, $days);
403 $this->summaryEvery($automation);
404 }
405
406 private function summaryAsap(object $automation): void
407 {
408 if (!empty($automation->triggers['asap'])) {
409 $automation->triggers['asap'] = acym_translation('ACYM_EACH_TIME');
410 }
411 }
412
413 private function summaryDay(object $automation): void
414 {
415 if (empty($automation->triggers['day']) || !is_array($automation->triggers['day'])) {
416 return;
417 }
418
419 $hour = sprintf('%02d', $automation->triggers['day']['hour']);
420 $minutes = sprintf('%02d', $automation->triggers['day']['minutes']);
421
422 $automation->triggers['day'] = acym_translationSprintf('ACYM_TRIGGER_DAY_SUMMARY', $hour, $minutes);
423 }
424
425 private function summaryWeeksOn(object $automation, array $days): void
426 {
427 if (empty($automation->triggers['weeks_on']) || !is_array($automation->triggers['weeks_on'])) {
428 return;
429 }
430
431 foreach ($automation->triggers['weeks_on']['day'] as $i => $oneDay) {
432 $automation->triggers['weeks_on']['day'][$i] = $days[$oneDay];
433 }
434
435 if (isset($automation->triggers['weeks_on']['hour'])) {
436 $hour = $automation->triggers['weeks_on']['hour'];
437 $minutes = $automation->triggers['weeks_on']['minutes'];
438 } else {
439 $hour = $this->config->get('daily_hour', '12');
440 $minutes = $this->config->get('daily_minute', '00');
441 }
442
443 $hour = sprintf('%02d', $hour);
444 $minutes = sprintf('%02d', $minutes);
445
446 $automation->triggers['weeks_on'] = acym_translationSprintf(
447 'ACYM_TRIGGER_WEEKS_ON_SUMMARY',
448 implode(', ', $automation->triggers['weeks_on']['day'])
449 ).' '.acym_translationSprintf('ACYM_AT_DATE_TIME', $hour, $minutes);
450 }
451
452 private function summaryOnDayMonth(object $automation, array $days): void
453 {
454 if (empty($automation->triggers['on_day_month']) || !is_array($automation->triggers['on_day_month'])) {
455 return;
456 }
457
458 $numbers = [
459 'first' => acym_translation('ACYM_FIRST'),
460 'second' => acym_translation('ACYM_SECOND'),
461 'third' => acym_translation('ACYM_THIRD'),
462 'fourth' => acym_translation('ACYM_FOURTH'),
463 'last' => acym_translation('ACYM_LAST'),
464 ];
465
466 if (isset($automation->triggers['on_day_month']['hour'])) {
467 $hour = $automation->triggers['on_day_month']['hour'];
468 $minutes = $automation->triggers['on_day_month']['minutes'];
469 } else {
470 $hour = $this->config->get('daily_hour', '12');
471 $minutes = $this->config->get('daily_minute', '00');
472 }
473
474 $hour = sprintf('%02d', $hour);
475 $minutes = sprintf('%02d', $minutes);
476
477 $automation->triggers['on_day_month'] = acym_translationSprintf(
478 'ACYM_TRIGGER_ON_DAY_MONTH_SUMMARY',
479 $numbers[$automation->triggers['on_day_month']['number']],
480 $days[$automation->triggers['on_day_month']['day']]
481 ).' '.acym_translationSprintf('ACYM_AT_DATE_TIME', $hour, $minutes);
482 }
483
484 private function summaryEvery(object $automation): void
485 {
486 if (empty($automation->triggers['every']) || !is_array($automation->triggers['every'])) {
487 return;
488 }
489
490 if ($automation->triggers['every']['type'] == 3600) $automation->triggers['every']['type'] = acym_translation('ACYM_HOURS');
491 if ($automation->triggers['every']['type'] == 86400) $automation->triggers['every']['type'] = acym_translation('ACYM_DAYS');
492 if ($automation->triggers['every']['type'] == 604800) $automation->triggers['every']['type'] = acym_translation('ACYM_WEEKS');
493 if ($automation->triggers['every']['type'] == 2628000) $automation->triggers['every']['type'] = acym_translation('ACYM_MONTHS');
494 $automation->triggers['every'] = acym_translationSprintf(
495 'ACYM_TRIGGER_EVERY_SUMMARY',
496 $automation->triggers['every']['number'],
497 $automation->triggers['every']['type']
498 );
499 }
500 }
501