PluginProbe
HurryTimer – An Scarcity and Urgency Countdown Timer for WordPress & WooCommerce / 2.10.0
HurryTimer – An Scarcity and Urgency Countdown Timer for WordPress & WooCommerce v2.10.0
2.15.0 trunk 1.0.0 1.0.1 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.1.2 2.1.3 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 All 62 releases
hurrytimer / includes / Campaign.php

Campaign.php in HurryTimer – An Scarcity and Urgency Countdown Timer for WordPress & WooCommerce 2.10.0, at includes/Campaign.php

1,968 lines 46.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Hurrytimer;
4
5 use DateInterval;
6 use DatePeriod;
7 use DateTime;
8 use Hurrytimer\Dependencies\Carbon\Carbon;
9 use Hurrytimer\Dependencies\Carbon\CarbonPeriod;
10 use Hurrytimer\Utils\Helpers;
11
12 class Campaign
13 {
14
15 /**
16 * Campaign custom post ID
17 *
18 * @var int
19 */
20 private $id;
21
22 /**
23 * Campaign mode.
24 *
25 * @see C.php
26 *
27 * @var int
28 */
29 public $mode = C::MODE_REGULAR;
30
31 /**
32 * Evergreen duration array.
33 *
34 * @see getDuration()
35 *
36 * @var array
37 */
38 public $duration;
39
40 /**
41 * Recurrence duration
42 *
43 * @var int
44 */
45 public $recurringDuration;
46 public $recurringPauseDuration = ['days' => 0, 'hours' => 0, 'minutes' => 0, 'seconds' => 0];
47
48 public $recurringDurationOption = 'none';
49
50 /**
51 * Recurrence start date/time
52 *
53 * @var string
54 */
55 public $recurringStartTime;
56
57 /**
58 * Recurrence end option
59 *
60 * @var int
61 */
62 public $recurringEnd = C::RECURRING_END_NEVER;
63
64 /**
65 * Recurrence frequency
66 *
67 * @see C
68 * @var string
69 */
70 public $recurringFrequency = C::RECURRING_DAILY;
71
72 /**
73 * Recurrence interval
74 *
75 * @var int
76 */
77 public $recurringInterval = 1;
78
79 /**
80 * Recurrence count
81 *
82 * @var int
83 */
84 public $recurringCount = 2;
85
86 /**
87 * Recurrence end date/time
88 *
89 * @var
90 */
91 public $recurringUntil;
92
93 /**
94 * Recurrence allowed days
95 *
96 * @var array
97 */
98 public $recurringDays = [0, 1, 2, 3, 4, 5, 6];
99
100 /**
101 * Restart option after expiration.
102 *
103 * @see \Hurrytimer\CampaignRestart
104 *
105 * @var int
106 */
107 public $restart;
108 public $restartDuration = ['days' => 0, 'hours' => 0, 'minutes' => 0, 'seconds' => 0];
109
110 /**
111 * Headline text.
112 *
113 * @var string
114 */
115 public $headline = "Hurry Up!";
116
117 /**
118 * Headline color.
119 *
120 * @var string
121 */
122 public $headlineColor = "#000";
123
124 /**
125 * Headline size.
126 *
127 * @var int
128 */
129 public $headlineSize = 30;
130
131 /**
132 * Headline position.
133 *
134 * @var int
135 */
136 public $headlinePosition = C::HEADLINE_POSITION_ABOVE_TIMER;
137
138 /**
139 * Headline visibility.
140 *
141 * @var boolean
142 */
143 public $headlineVisibility = C::YES;
144
145 public $headlineSpacing = 5;
146
147 /**
148 * Control labels visibility.
149 *
150 * @var string
151 */
152 public $labelVisibility = C::YES;
153
154 /**
155 * Show/hide days block.
156 *
157 * @var string
158 */
159 public $daysVisibility = C::YES;
160
161 public $monthsVisibility = C::NO;
162
163 /**
164 * Show/hide hours block.
165 *
166 * @var string
167 */
168 public $hoursVisibility = C::YES;
169
170 /**
171 * Show/hide minutes block.
172 *
173 * @var string
174 */
175 public $minutesVisibility = C::YES;
176
177 /**
178 * Show/hide seconds block.
179 *
180 * @var string
181 */
182 public $secondsVisibility = C::YES;
183
184 /**
185 * Regular campaign end date/time.
186 *
187 * @var string
188 */
189 public $endDatetime;
190
191 /**
192 * Labels texts.
193 *
194 * @var array
195 */
196 public $labels
197 = [
198 'months' => 'months',
199 'days' => 'days',
200 'hours' => 'hrs',
201 'minutes' => 'mins',
202 'seconds' => 'secs',
203 ];
204
205 /**
206 * Digit color.
207 *
208 * @var string
209 */
210 public $digitColor = "#000";
211
212 /**
213 * Digit size.
214 *
215 * @var int
216 */
217 public $digitSize = 35;
218
219 /**
220 * Redirect action url.
221 *
222 * @var string
223 */
224 public $redirectUrl;
225
226 /**
227 * Label size.
228 *
229 * @var int
230 */
231 public $labelSize = 12;
232
233 /**
234 * Label color.
235 *
236 * @var string
237 */
238 public $labelColor = "#000";
239
240 /**
241 * End action.
242 *
243 * @var array
244 */
245 public $actions = [];
246
247 /**
248 * WooCommerce compaign position in product page.
249 *
250 * @var int
251 */
252 public $wcPosition = C::WC_POSITION_ABOVE_TITLE;
253
254 /**
255 * Enable/disable woocommerce integration.
256 *
257 * @var string
258 */
259 public $wcEnable = C::NO;
260
261 /**
262 * WooCommerce products selection.
263 *
264 * @var array
265 */
266 public $wcProductsSelection;
267
268 /**
269 * WooCommerce products selection type.
270 *
271 * @var int
272 */
273 public $wcProductsSelectionType;
274
275 /**
276 * WooCommerce conditions.
277 * @var array $wcConditions
278 */
279 public $wcConditions;
280
281 /**
282 * Timer block border color.
283 *
284 * @var string
285 */
286 public $blockBorderColor = "";
287
288 /**
289 * Timer Block border width.
290 *
291 * @var int
292 */
293
294 public $blockBorderWidth = 0;
295
296 /**
297 * Timer block radius.
298 *
299 * @var int
300 */
301 public $blockBorderRadius = 0;
302
303 /**
304 * Block size.
305 *
306 * @var int
307 */
308
309 public $blockSize = 'auto';
310
311 /**
312 * Block background color.
313 *
314 * @var string
315 */
316 public $blockBgColor = '';
317
318 /**
319 * Block spacing.
320 *
321 * @var int
322 */
323 public $blockSpacing = 5;
324
325 /**
326 * Block padding.
327 *
328 * @var int
329 */
330 public $blockPadding = 0;
331
332 /**
333 * Block spearator visibility.
334 *
335 * @var boolean
336 */
337 public $blockSeparatorVisibility = C::YES;
338
339 /**
340 * Label case
341 *
342 * @var string
343 */
344 public $labelCase = C::TRANSFORM_UPPERCASE;
345
346 /**
347 * Custom CSS
348 *
349 * @var string
350 */
351 public $customCss = '';
352
353 /**
354 * Block elements display
355 * Values: block, inline
356 *
357 * @var string
358 */
359 public $blockDisplay = 'block';
360
361 /**
362 * Enable sticky bar.
363 */
364 public $enableSticky = C::NO;
365
366 /**
367 * Sticky bar background color.
368 *
369 * @var string
370 */
371 public $stickyBarBgColor = '#eee';
372
373 /**
374 * Sticky bar close button color.
375 *
376 * @var string
377 */
378 public $stickyBarCloseBtnColor = '#fff';
379
380 /**
381 * Sticky bar position.
382 * Values: top, bottom
383 *
384 * @var string
385 */
386 public $stickyBarPosition = 'top';
387
388 /**
389 * Sticky bar padding.
390 *
391 * @var integer
392 */
393 public $stickyBarPadding = 5;
394
395 /**
396 * Sticky bar display pages.
397 *
398 * @var array
399 */
400 public $stickyBarPages = [];
401 public $stickyIncludeUrls = [];
402 public $stickyExcludeUrls = [];
403
404 /**
405 * Sticky exclude pages.
406 *
407 * @var array
408 */
409 public $stickyExcludePages = [];
410
411 /**
412 * Where to display the sticky bar option
413 *
414 * @var string
415 */
416 public $stickyBarDisplayOn = 'all_pages';
417
418 /**
419 * Show sticky bar close button?
420 *
421 * @var string
422 */
423 public $stickyBarDismissible = C::YES;
424
425
426 /**
427 * If dismissed, re-open sticky bar after x days.
428 * @var int
429 */
430 public $stickyBarDismissTimeout = 7;
431
432 /**
433 * CTA settings.
434 *
435 * @var array
436 */
437 public $callToAction
438 = [
439 'enabled' => C::NO,
440 'new_tab' => C::NO,
441 'url' => '',
442 'text' => 'Learn More',
443 'text_size' => 15,
444 'text_color' => '#fff',
445 'bg_color' => '#000',
446 'y_padding' => 10,
447 'x_padding' => 15,
448 'border_radius' => 3,
449 'spacing' => 5,
450
451 ];
452
453 /**
454 * Campaign elements display
455 * values: block,inline
456 *
457 * @var string
458 */
459 public $campaignDisplay = 'block';
460
461 /**
462 * Campaign aligments
463 * values: center,left,right
464 *
465 * @var string
466 */
467 public $campaignAlign = 'center';
468
469 /**
470 * Campaign spacing.
471 *
472 * @var integer
473 */
474 public $campaignSpacing = 10;
475
476 /**
477 * Campaign horizontal padding.
478 *
479 * @var integer
480 */
481 public $campaignXPadding = 10;
482
483 /**
484 * Campaign vertical padding.
485 *
486 * @var integer
487 */
488 public $campaignYPadding = 10;
489
490 /**
491 * Force evergreen timer to reset on reload.
492 */
493 public $reloadReset = false;
494
495
496 /**
497 *
498 */
499
500 public $detectionMethods = [
501 C::DETECTION_METHOD_COOKIE,
502 C::DETECTION_METHOD_IP,
503 ];
504
505
506 public $recurringMonthlyDayType = C::RECURRING_MONTHLY_DAY_OF_MONTH;
507
508
509 public $recurringUnselectedDaysAction = 'skip';
510
511 public function __construct($id)
512 {
513 $this->recurringStartTime = Carbon::now(hurryt_tz())->format('Y-m-d h:i A');
514 $this->id = $id;
515 }
516
517 /**
518 * Returns compaign post iD.
519 *
520 * @return int
521 */
522 public function get_id()
523 {
524 return $this->id;
525 }
526
527
528 /**
529 * Returns true if the current sticky bar can be displayed on the given page.
530 *
531 * @param $pageId
532 *
533 * @return bool
534 * @throws \Exception
535 */
536 public function show_sticky_on_page($pageId)
537 {
538 if ($this->enableSticky === C::NO) {
539 return true;
540 }
541
542 switch ($this->getStickyBarDisplayOn()):
543
544 case 'wc_products_pages':
545 if (!empty($pageId) && function_exists('is_product') && is_product()) {
546
547 $wc_campaign = new WCCampaign();
548 if (($wc_campaign->has_campaign($this, $pageId))
549 && $wc_campaign->met_conditions($this, $pageId)
550 ) {
551 return apply_filters('hurryt_show_sticky_bar', true, $this->get_id());
552 }
553 }
554
555 return apply_filters('hurryt_show_sticky_bar', false, $this->get_id());
556
557 case 'specific_pages':
558 $pageIds = $this->getStickyBarPages();
559
560 if (!empty($pageId) && !empty($pageIds) && in_array($pageId, $pageIds, true)) {
561 return apply_filters('hurryt_show_sticky_bar', true, $this->get_id());
562 }
563
564 foreach ($this->stickyIncludeUrls as $url) {
565 $current_url = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/';
566
567 if (Helpers::are_urls_match($url, $current_url)) {
568 return apply_filters('hurryt_show_sticky_bar', true, $this->get_id());
569 break;
570 }
571 }
572 return apply_filters('hurryt_show_sticky_bar', false, $this->get_id());
573
574 case 'exclude_pages':
575 $pageIds = $this->getStickyExcludePages();
576
577 if (!empty($pageId) && !empty($pageIds) && in_array($pageId, $pageIds, true)) {
578 return apply_filters('hurryt_show_sticky_bar', false, $this->get_id());
579 }
580
581 foreach ($this->stickyExcludeUrls as $url) {
582 $current_url = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/';
583 if (Helpers::are_urls_match($current_url, $url)) {
584 return apply_filters('hurryt_show_sticky_bar', false, $this->get_id());
585 break;
586 }
587 }
588
589 return apply_filters('hurryt_show_sticky_bar', true, $this->get_id());
590 case 'all_pages':
591 return apply_filters('hurryt_show_sticky_bar', true, $this->get_id());
592 default:
593 return apply_filters('hurryt_show_sticky_bar', false, $this->get_id());
594 endswitch;
595 }
596
597 /**
598 * Returns sticky bar pages.
599 *
600 * @return array
601 */
602 public function getStickyBarPages()
603 {
604 $pagesIds = $this->get_prop('sticky_bar_pages');
605
606 return array_filter(array_map('intval', $pagesIds));
607 }
608
609 public function getStickyExcludePages()
610 {
611 $page_ids = $this->get_prop('sticky_exclude_pages');
612
613 return array_filter(array_map('intval', $page_ids));
614 }
615
616 /**
617 * Set sticky bar pages.
618 *
619 * @param $value
620 */
621 public function setStickyBarPages($value)
622 {
623 $this->set_prop('sticky_bar_pages', $value);
624 }
625
626 public function setStickyExcludePages($value)
627 {
628 $this->set_prop('sticky_exclude_pages', $value);
629 }
630
631 public function setStickyBarDismissTimeout($value)
632 {
633 $this->set_prop('sticky_bar_dismiss_timeout', intval($value));
634 }
635
636 public function getStickyBarDismissTimeout()
637 {
638 return intval($this->get_prop('sticky_bar_dismiss_timeout'));
639 }
640
641 public function getStickyBarDisplayOn()
642 {
643
644 // backward compat.
645 $all_pages = $this->get_prop('sticky_bar_show_on_all_pages', false);
646
647 if ($all_pages === C::YES) {
648 $this->setStickyBarDisplayOn('all_pages');
649 }
650
651 $this->delete_prop('sticky_bar_show_on_all_pages');
652
653 $value = $this->get_prop('_hurryt_sticky_bar_display_on', false);
654
655 return !empty($value) ? $value : $this->stickyBarDisplayOn;
656 }
657
658 public function setStickyBarDisplayOn($value)
659 {
660 $this->set_prop('_hurryt_sticky_bar_display_on', $value);
661 }
662
663 /**
664 * Get raw setting.
665 *
666 * @param string $name
667 * @param boolean
668 *
669 * @return mixed
670 */
671 public function get_prop($name, $useDefault = true)
672 {
673
674 $value = get_post_meta($this->id, $name, true);
675 if (!empty($value)) {
676 return $value;
677 }
678 if ($useDefault) {
679 $name = str_replace('_hurryt_', '', $name);
680 return $this->{Helpers::snakeToCamelCase($name)};
681 }
682
683 return $value;
684 }
685
686 public function set_prop($name, $value)
687 {
688 $value = !empty($value) ? $value : '';
689 $_name = str_replace('_hurryt_', '', $name);
690 $getterMethod = Helpers::snakeToCamelCase($_name);
691 if (empty($value) && method_exists($this, $getterMethod)) {
692 $value = $this->{$getterMethod}();
693 }
694
695 update_post_meta($this->id, $name, $value);
696 }
697
698 /**
699 * Bulk save for compaign settings.
700 *
701 * @param $data
702 */
703 public function storeSettings($data)
704 {
705
706 if (!hurrytimer_allow_unfiltered_html()) {
707 $data = wp_kses_post_deep($data);
708 }
709
710 foreach ($data as $prop => $value) {
711 $method = Helpers::snakeToCamelCase("set_{$prop}");
712 if (method_exists($this, $method)) {
713 $this->$method($value ?: $this->$prop);
714 } elseif (property_exists(__CLASS__, Helpers::snakeToCamelCase($prop))) {
715 $this->set_prop($prop, $value);
716 }
717 }
718 if (!isset($data['wc_conditions'])) {
719 $this->setWcConditions([]);
720 }
721 if (!isset($data['sticky_bar_pages'])) {
722 $this->setStickyBarPages([]);
723 }
724
725 CSS_Builder::get_instance()->generate_css();
726 }
727
728 //removeIf(pro)
729
730 /**
731 * @param int $mode
732 * ::PROP
733 */
734 public function setMode($mode)
735 {
736 // if ($mode == C::MODE_RECURRING) {
737 // return;
738 // }
739 $this->set_prop('mode', $mode);
740 }
741 //endRemoveIf(pro)
742
743 /**
744 * TODO: Settings should load automatically upon instance creation.
745 */
746 public function loadSettings()
747 {
748
749 $reflection = new \ReflectionObject($this);
750 // TODO: Refactor prop loading to `$this->get_{prop}()`
751 foreach ($reflection->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) {
752 $name = $prop->getName();
753 $method = 'get' . ucfirst($name);
754 if (method_exists($this, $method)) {
755 $this->{$name} = $this->$method();
756 } else {
757 $this->{$name} = $this->get_prop(Helpers::camelToSnakeCase($name));
758 }
759 }
760 }
761
762
763 public function getHeadline()
764 {
765 if (empty($this->id)) {
766 return $this->headline;
767 }
768 if (metadata_exists('post', $this->id, '_hurryt_headline')) {
769 return $this->get_prop('_hurryt_headline');
770 }
771
772 return get_the_title($this->id);
773 }
774
775 public function setHeadline($value)
776 {
777 $this->set_prop('_hurryt_headline', $value);
778 }
779
780 public function is_published()
781 {
782 return get_post_status($this->id) === "publish";
783 }
784
785 /**
786 * Check if WooCommerce is enabled for this campaign.
787 *
788 * @return bool
789 */
790 public function is_wc_enabled()
791 {
792 return $this->getWcEnable() === C::YES;
793 }
794
795 /**
796 * Check current countdown timer mode
797 * ::PROP
798 *
799 * @return bool
800 */
801 public function is_evergreen()
802 {
803 return $this->get_prop('mode') == C::MODE_EVERGREEN;
804 }
805
806 public function is_one_time()
807 {
808 return $this->get_prop('mode') == C::MODE_REGULAR;
809 }
810
811 public function is_recurring()
812 {
813 return $this->get_prop('mode') == C::MODE_RECURRING;
814 }
815
816 /**
817 * Save compaign endtime for regular mode.
818 *
819 * @param $date
820 */
821 public function setEndDatetime($date)
822 {
823 $this->set_prop('end_datetime', $date ?: $this->defaultEndDatetime());
824 }
825
826 /**
827 * Returns default end datetime for regular mode.
828 * ::PROP
829 *
830 * @return false|string
831 */
832 private function defaultEndDatetime()
833 {
834 return date('Y-m-d h:i A', strtotime('+1 week'));
835 }
836
837 /**
838 * Save digit color.
839 * ::PROP
840 *
841 * @param $color
842 */
843 public function setDigitColor($color)
844 {
845 $this->set_prop('digit_color', $color);
846 }
847
848 /**
849 * Returns headline visibility.
850 * ::PROP
851 *
852 * @return mixed
853 */
854
855 public function getHeadlineVisibility()
856 {
857 $meta = 'headline_visibility';
858
859 $value = $this->get_prop($meta, false);
860 if ($value === C::NO || $value === C::YES) {
861 return $value;
862 }
863
864 $legacyMeta = 'display_headline';
865 $legacyValue = filter_var($this->get_prop_legacy($legacyMeta), FILTER_VALIDATE_BOOLEAN);
866 $legacyValue = $legacyValue ? C::YES : C::NO;
867
868 $this->set_prop($meta, $legacyValue);
869
870 $this->delete_prop($legacyMeta);
871
872 return $this->get_prop($meta);
873 }
874
875 /**
876 * Returns digit color.
877 * Backward compat with older versions.
878 * ::PROP
879 *
880 * @return mixed
881 */
882 public function getDigitColor()
883 {
884 $value = $this->get_prop('digit_color', false);
885 if ($value) {
886 return $value;
887 }
888
889 $legacy = $this->get_prop_legacy('text_color');
890 if (!$legacy) {
891 return $this->digitColor;
892 }
893
894 $this->setDigitColor($legacy);
895 if (!$this->get_prop('label_color', false)) {
896 $this->setLabelColor($legacy);
897 }
898
899 $this->delete_prop('text_color');
900
901 return $this->get_prop('digit_color');
902 }
903
904 /**
905 * ::PROP
906 *
907 * @param $color
908 */
909 public function setLabelColor($color)
910 {
911 $this->set_prop('label_color', $color);
912 }
913
914 /**
915 * Get label color
916 * ::PROP
917 *
918 * @return mixed
919 */
920 public function getLabelColor()
921 {
922 $value = $this->get_prop('label_color', false);
923 if ($value) {
924 return $value;
925 }
926
927 $legacy = $this->get_prop_legacy('text_color');
928 if (!$legacy) {
929 return $this->labelColor;
930 }
931
932 $this->setLabelColor($legacy);
933 if (!$this->get_prop('digit_color', false)) {
934 $this->setDigitColor($legacy);
935 }
936
937 $this->delete_prop('text_color');
938
939 return $this->get_prop('label_color');
940 }
941
942 /**
943 *
944 * Return timer digit size.
945 * Backward comapt. with older versions.
946 * ::PROP
947 *
948 * @return int
949 * @since 1.2.4
950 */
951 public function getDigitSize()
952 {
953 $meta = 'digit_size';
954 $value = $this->get_prop($meta, false);
955 if (!empty($value)) {
956 return $value;
957 }
958 $legacy = $this->get_prop_legacy('text_size');
959
960 if (empty($legacy)) {
961 return $this->digitSize;
962 }
963
964 $this->setDigitSize($legacy);
965
966 $this->delete_prop('text_size');
967
968 return $this->get_prop('digit_size');
969 }
970
971 /**
972 * Save timer digit size.
973 * ::PROP
974 *
975 * @param $size
976 */
977 public function setDigitSize($size)
978 {
979 $this->set_prop('digit_size', $size);
980 }
981
982 /**
983 * Save timer label size.
984 * ::PROP
985 *
986 * @param $size
987 */
988 public function setLabelSize($size)
989 {
990 $this->set_prop('label_size', $size);
991 }
992
993
994 /**
995 * ::PROP
996 *
997 * @param $size
998 */
999 public function setHeadlineSize($size)
1000 {
1001 $this->set_prop('headline_size', $size);
1002 }
1003
1004 /**
1005 * Returns evergreen duration.
1006 * ::PROP
1007 *
1008 * @return array
1009 */
1010 public function getDuration()
1011 {
1012 $duration = (array)$this->get_prop('duration');
1013 return array_pad(array_map('intval', $duration), 4, 0);
1014 }
1015
1016
1017
1018 public function getRestartDuration($asSeconds = false)
1019 {
1020 $duration = (array)$this->get_prop('hurryt_restart_duration', false);
1021
1022 $duration = wp_parse_args($duration, $this->restartDuration);
1023 foreach ($duration as $unit => $value) {
1024 $duration[$unit] = (int)$value;
1025 }
1026
1027 if ($asSeconds) {
1028 $duration = $duration['days'] * DAY_IN_SECONDS +
1029 $duration['hours'] * HOUR_IN_SECONDS +
1030 $duration['minutes'] * MINUTE_IN_SECONDS +
1031 $duration['seconds'];
1032 }
1033 return $duration;
1034 }
1035
1036
1037 public function getRecurringPauseDuration($asSeconds = false)
1038 {
1039 $duration = (array)$this->get_prop('_hurryt_recurring_pause_duration', false);
1040
1041 $duration = wp_parse_args($duration, $this->recurringPauseDuration);
1042 foreach ($duration as $unit => $value) {
1043 $duration[$unit] = (int)$value;
1044 }
1045
1046 if ($asSeconds) {
1047 $duration = $duration['days'] * DAY_IN_SECONDS +
1048 $duration['hours'] * HOUR_IN_SECONDS +
1049 $duration['minutes'] * MINUTE_IN_SECONDS +
1050 $duration['seconds'];
1051 }
1052 return $duration;
1053 }
1054
1055 public function setRestartDuration($duration_array)
1056 {
1057 $this->set_prop('hurryt_restart_duration', $duration_array);
1058 }
1059 /**
1060 * ::PROP
1061 *
1062 * @param $value
1063 */
1064 public function setRecurringDuration($value)
1065 {
1066 $this->set_prop('_hurryt_recurring_duration', $value);
1067 }
1068 public function setRecurringPauseDuration($value)
1069 {
1070 $this->set_prop('_hurryt_recurring_pause_duration', $value);
1071 }
1072
1073 /**
1074 * Returns evergreen duration.
1075 *
1076 * @return array
1077 */
1078 public function getRecurringDuration()
1079 {
1080
1081 $duration = (array)$this->get_prop('_hurryt_recurring_duration', false);
1082 return array_pad(array_map('intval', $duration), 4, 0);
1083 }
1084
1085 /**
1086 * Returns actions array.
1087 *
1088 * @return array
1089 */
1090 public function getActions()
1091 {
1092 $legacy = $this->get_prop_legacy('end_action');
1093 if ($legacy) {
1094 $redirectUrl = $this->get_prop_legacy('redirect_url');
1095 $actions = [
1096 [
1097 'id' => intval($legacy),
1098 'redirectUrl' => $redirectUrl,
1099 ],
1100 ];
1101 $this->set_prop('actions', $actions);
1102 $this->delete_prop('end_action');
1103 $this->delete_prop('redirect_url');
1104
1105 return $this->mergeActions($actions);
1106 }
1107
1108 return $this->mergeActions($this->get_prop('actions'));
1109 }
1110
1111 private function mergeActions($actions)
1112 {
1113 $defaults = [
1114 [
1115 'id' => C::ACTION_NONE,
1116 'redirectUrl' => '',
1117 'message' => '',
1118 'coupon' => '',
1119 'wcStockStatus' => '',
1120 ],
1121 ];
1122
1123 if (count($actions) === 0) {
1124 return $defaults;
1125 }
1126
1127 return array_map(function ($action) use ($defaults) {
1128 $action['id'] = (int)$action['id'];
1129
1130 $action['message'] = preg_replace_callback('#<style(\s=?[\S]*)?>([\s\S]*)?<\/style>#', function ($matches) {
1131 return '<style' . $matches[1] . '>' . preg_replace('/\<br(\s*)?\/?\>/i', '', $matches[2]) . '</style>';
1132 }, $action['message']);
1133
1134 return array_merge($defaults[0], $action);
1135 }, $actions);
1136 }
1137
1138
1139 public function get_action($needle)
1140 {
1141 $result = array_filter($this->actions, function ($action) use ($needle) {
1142 return $needle === (int)$action['id'];
1143 });
1144
1145 if (empty($result)) {
1146 return false;
1147 }
1148
1149 return array_shift($result);
1150 }
1151
1152 /**
1153 * Returns evergreen duration in seconds.
1154 *
1155 * @param array $duration
1156 *
1157 * @return int
1158 */
1159 public function durationInSeconds($duration = [])
1160 {
1161 list($d, $h, $m, $s) = empty($duration) ? $this->getDuration() : $duration;
1162
1163 return
1164 $d * DAY_IN_SECONDS +
1165 $h * HOUR_IN_SECONDS +
1166 $m * MINUTE_IN_SECONDS +
1167 $s;
1168 }
1169
1170 /**
1171 * Returns end datetime.
1172 *
1173 * @return string
1174 */
1175 public function getEndDatetime()
1176 {
1177 return $this->get_prop('end_datetime') ?: $this->defaultEndDatetime();
1178 }
1179
1180 /**
1181 * Return true if the recurrence is expired.
1182 *
1183 * @return bool
1184 */
1185 public function is_recurring_expired()
1186 {
1187 $endDate = $this->getRecurrenceEndDate();
1188
1189 if (!($endDate instanceof Carbon)) {
1190 return false;
1191 }
1192
1193 $now = Carbon::now(hurryt_tz());
1194
1195 return $now->greaterThan($endDate);
1196 }
1197
1198 /**
1199 * Calculate next recurrence.
1200 *
1201 * @return mixed
1202 * @throws \Exception
1203 */
1204 function timeToNextRecurrence()
1205 {
1206 $this->loadSettings();
1207
1208 if ($this->isMonthlyRecurring()) {
1209 $current = $this->getRecurrenceEndDate();
1210
1211 $next = $this->getRecurrenceEndDate(true);
1212
1213 $duration = $this->durationInSeconds($this->getRecurringDuration());
1214 $use_custom = $this->recurringDurationOption === 'custom' && $duration > 0;
1215
1216 if ($use_custom) {
1217 $time_remaining = $next->diffInSeconds($current);
1218 } else {
1219 $time_remaining = $this->getRecurringPauseDuration(true);
1220 }
1221 return $time_remaining;
1222 }
1223
1224 list($duration, $pause, $period) = $this->getRecurringDurationInSeconds();
1225
1226 $t = $pause ?: 0;
1227
1228 $waitBeforeRestart = $this->getRecurringPauseDuration(true);
1229
1230 $t += $waitBeforeRestart;
1231
1232 if (!$this->has_skipped_days()) {
1233 return $t;
1234 }
1235
1236 if ($this->isWeeklyRecurring()) {
1237 return $t;
1238 }
1239
1240 if ($this->recurringUnselectedDaysAction === 'hide') {
1241 return $t;
1242 }
1243
1244 return $waitBeforeRestart;
1245 }
1246
1247 /**
1248 * Return true if the current campaign can recur today.
1249 *
1250 * @return bool
1251 */
1252 public function can_recur_today()
1253 {
1254 $this->loadSettings();
1255
1256 $day = absint(Carbon::now(hurryt_tz())->format('w'));
1257
1258 $recur = in_array($day, array_map('absint', $this->recurringDays));
1259
1260 return apply_filters('hurryt_recur_today', $recur, $this->get_id());
1261 }
1262
1263 public function isMonthlyRecurring()
1264 {
1265 return $this->recurringFrequency === C::RECURRING_MONTHLY;
1266 }
1267
1268 public function isDayOfWeekRecurring()
1269 {
1270
1271 return $this->recurringMonthlyDayType === C::RECURRING_MONTHLY_DAY_OF_WEEK;
1272 }
1273
1274 public function isDayOfMonthRecurring()
1275 {
1276 return $this->recurringMonthlyDayType === C::RECURRING_MONTHLY_DAY_OF_MONTH;
1277 }
1278
1279 public function shouldEndRecurringByDate()
1280 {
1281 return absint($this->recurringEnd) === C::RECURRING_END_TIME;
1282 }
1283 public function shouldEndRecurringByRecurrences()
1284 {
1285 return (int)$this->recurringEnd === C::RECURRING_END_OCCURRENCES;
1286 }
1287
1288 public function shouldRecurForever()
1289 {
1290 return (int)$this->recurringEnd === C::RECURRING_END_NEVER;
1291 }
1292
1293 public function getRecurringRecurrences()
1294 {
1295 $num = (int)$this->recurringCount;
1296 return ++$num;
1297 }
1298
1299
1300 public function getRecurringPeriodEndDate()
1301 {
1302 list($d, $h, $m, $s) = $this->getRecurringDuration();
1303 $now = Carbon::now(hurryt_tz());
1304 $startDate = Carbon::parse($this->recurringStartTime, hurryt_tz());
1305 $interval = (int)$this->recurringInterval;
1306 $endDate = $now->copy();
1307
1308 switch ($this->recurringFrequency) {
1309 case C::RECURRING_DAILY:
1310 $endDate->minute = $startDate->minute;
1311 $endDate->addDays(max($interval, $d))->addHours($interval)->addMinutes($m)->addSeconds($s);
1312 break;
1313 case C::RECURRING_WEEKLY:
1314 $endDate->minute = $startDate->minute;
1315 $endDate->addWeeks($interval)->addHours($h)->addMinutes($m)->addSeconds($s);
1316 break;
1317 case C::RECURRING_HOURLY:
1318 $endDate->minute = $startDate->minute;
1319 $endDate->addHours(max($interval, $h))->addMinutes($m)->addSeconds($s);
1320 break;
1321 case C::RECURRING_MINUTELY:
1322 $minutes = max($interval, $m);
1323 $endDate->addMinutes($minutes)->addSeconds($s);
1324 break;
1325 }
1326
1327 return $endDate;
1328 }
1329
1330 public function getRecurringFrequencyInSeconds()
1331 {
1332 $freq = 0;
1333 switch ($this->recurringFrequency) {
1334 case C::RECURRING_WEEKLY:
1335 $freq = WEEK_IN_SECONDS;
1336 break;
1337 case C::RECURRING_DAILY:
1338 $freq = DAY_IN_SECONDS;
1339 break;
1340 case C::RECURRING_HOURLY:
1341 $freq = HOUR_IN_SECONDS;
1342 break;
1343 case C::RECURRING_MINUTELY:
1344 $freq = MINUTE_IN_SECONDS;
1345 break;
1346 }
1347
1348 return $freq * (int)$this->recurringInterval;
1349 }
1350 /**
1351 * @return array [duration, pause, period] in seconds
1352 */
1353 public function getRecurringDurationInSeconds()
1354 {
1355 $duration = $this->durationInSeconds($this->getRecurringDuration());
1356 $period = $this->getRecurringFrequencyInSeconds();
1357 $pause = $period - $duration;
1358 return [$duration, max(0, $pause), $period];
1359 }
1360
1361 /**
1362 * Returns the recurrence end date based on the current date/time.
1363 *
1364 * @param bool $next Return the next recurrence end date.
1365 *
1366 * @return Carbon
1367 */
1368
1369 public function getRecurrenceEndDate($next = false)
1370 {
1371
1372 $cached_key = $next ? 'recur_end_date__next' : 'recur_end_date';
1373 $cached = wp_cache_get($cached_key, 'hurrytimer');
1374 if ($cached instanceof Carbon) {
1375 return $cached;
1376 }
1377
1378 try {
1379
1380 $this->loadSettings();
1381 $now = Carbon::now(hurryt_tz());
1382 $startDate = Carbon::parse($this->recurringStartTime, hurryt_tz());
1383 $interval = (int)$this->recurringInterval;
1384
1385
1386 // Handle monthly recurring
1387 if ($this->isMonthlyRecurring()) {
1388 $start_date_modified = $startDate->copy();
1389
1390 if ($startDate->day >= 28) {
1391 $start_date_modified->startOfMonth();
1392 }
1393
1394 $endDate = $now->copy()->addMonths($interval);
1395
1396 if ($next) {
1397 $endDate->addMonths($interval);
1398 }
1399
1400 if ($this->shouldEndRecurringByDate()) {
1401 $endDate = Carbon::parse($this->recurringUntil, hurryt_tz());
1402 }
1403
1404 if ($this->isDayOfWeekRecurring()) {
1405 $endDate = $endDate->addMonths($interval);
1406 }
1407
1408 $period = CarbonPeriod::create($start_date_modified, 'P' . $interval . 'M', $endDate);
1409
1410 if ($this->shouldEndRecurringByRecurrences()) {
1411 $period->setRecurrences($this->getRecurringRecurrences());
1412 }
1413
1414 if ($period->count() === 0) {
1415 return $period->getEndDate();
1416 }
1417
1418 $dates = iterator_to_array($period);
1419
1420 $dates = array_map(function ($date) use ($startDate) {
1421 $is_overflow = $startDate->day >= $date->daysInMonth;
1422 if ($this->isDayOfMonthRecurring() && $is_overflow) {
1423 $date->endOfMonth();
1424 }
1425 if ($this->isDayOfWeekRecurring()) {
1426 $date->modifyWeekOfMonth($startDate);
1427 }
1428 $date->setTimeFrom($startDate);
1429
1430 return $date;
1431 }, $dates);
1432
1433
1434 $out_date = end($dates) ?: $period->getEndDate();
1435
1436 reset($dates);
1437
1438 foreach ($dates as $i => $date) {
1439 $duration = $this->durationInSeconds($this->getRecurringDuration());
1440 $custom = $this->recurringDurationOption === 'custom' && $duration > 0;
1441
1442 if ($custom && !$next) {
1443 $custom_end_date = $date->copy()->addSeconds($duration);
1444
1445 if ($custom_end_date->greaterThan($now)) {
1446 $out_date = $custom_end_date;
1447
1448 break;
1449 }
1450
1451 $next_date = isset($dates[$i + 1]) ? $dates[$i + 1] : $period->getEndDate();
1452
1453 if ($now->lessThan($next_date)) {
1454 $out_date = $custom_end_date;
1455 break;
1456 }
1457
1458 continue;
1459 }
1460
1461 if ($date->greaterThan($now)) {
1462 $pause_duration = $this->getRecurringPauseDuration(true);
1463
1464 if ($next && !$custom) {
1465 $out_date = isset($dates[$i + 1]) ? $dates[$i + 1] : $out_date;
1466
1467 if ($pause_duration > 0) {
1468 $out_date = $date;
1469 }
1470 } else {
1471 $out_date = $date;
1472 $prev_end_date = isset($dates[$i - 1]) ? $dates[$i - 1] : null;
1473 if ($prev_end_date && $prev_end_date->copy()->diffInSeconds($now) < $pause_duration) {
1474 $out_date = $prev_end_date;
1475 }
1476 }
1477
1478 break;
1479 }
1480 }
1481 if ($this->shouldEndRecurringByDate() && $out_date->lessThan($now)) {
1482 // TODO: Use the last recurrence instead of `getEndDate()`
1483 $out_date = $period->getEndDate();
1484 }
1485
1486 wp_cache_set($cached_key, $out_date, 'hurrytimer');
1487
1488 return $out_date;
1489 } // Monthly recurring
1490
1491
1492 // Prevent minutely recurring from affecting performance
1493 // by updating the start date year and month to current ones.
1494 if ($this->isMinutelyRecurring()) {
1495 $startDate->year = $now->year;
1496 $startDate->month = $now->month;
1497 $startDate->day = $now->day;
1498 }
1499
1500
1501 list($duration, $pause) = $this->getRecurringDurationInSeconds();
1502
1503 $period = CarbonPeriod::start($startDate, true);
1504
1505 $period->seconds($duration + $pause);
1506
1507 if ($this->shouldEndRecurringByRecurrences()) {
1508 $period->setRecurrences($this->getRecurringRecurrences());
1509 } else {
1510 $endDate = $this->getRecurringPeriodEndDate();
1511 $dateperiod_interval = new DateInterval('PT' .($duration + $pause) . 'S');
1512 $period = new DatePeriod($startDate->toDateTime(), $dateperiod_interval, $endDate->addDays(7 * $interval)->toDateTime());
1513 // $period->until($endDate->addDays(7 * $interval));
1514
1515 }
1516
1517 $date = null;
1518
1519 $i = 0;
1520
1521 $pause_duration = $this->getRecurringPauseDuration(true);
1522
1523 foreach ($period as $start) {
1524
1525 $start = Carbon::instance($start);
1526
1527 $end = $start->copy()->addSeconds($this->getRecurringFrequencyInSeconds() - 1);
1528
1529 if ($now->isBetween($start, $end->copy()->addSeconds($pause_duration))) {
1530 $date = $start->copy()->addSeconds($duration - 1);
1531 if (!in_array($date->format('w'), $this->recurringDays)) {
1532 continue;
1533 }
1534 break;
1535 }
1536
1537 if ($now->isBefore($end->copy()->addSeconds($pause_duration))) {
1538 $date = $start;
1539 if (!in_array($date->format('w'), $this->recurringDays)) {
1540 continue;
1541 }
1542 break;
1543 }
1544 }
1545
1546 if (empty($date)) {
1547 return $period->getEndDate();
1548 }
1549
1550 $stop_date = Carbon::parse($this->recurringUntil, hurryt_tz());
1551
1552 if ($this->shouldEndRecurringByDate() && $stop_date->lessThan($date)) {
1553 return $stop_date;
1554 }
1555
1556 return $date;
1557 } catch (\Exception $e) {
1558 return false;
1559 }
1560 }
1561
1562
1563 function should_hide_today($date, $now)
1564 {
1565 return ($date->format('w') === $now->format('w')) && ($this->isWeeklyRecurring() || $this->recurringUnselectedDaysAction === 'hide');
1566 }
1567 function has_skipped_days()
1568 {
1569 $recur_days = array_map('intval', $this->recurringDays);
1570 return count($recur_days) < 7;
1571 }
1572 function can_recur_on($date)
1573 {
1574 $recur_days = array_map('intval', $this->recurringDays);
1575
1576 if (in_array($date->format('w'), $recur_days)) {
1577 return true;
1578 }
1579
1580 if (($date->isStartOfDay() && in_array($this->get_previous_day($date->format('w')), $recur_days))) {
1581 return true;
1582 }
1583
1584 return false;
1585 }
1586 private function get_previous_day($current_day)
1587 {
1588 $current_day === 0 ? 6 : ($current_day - 1);
1589 }
1590
1591 /**
1592 * Returns compaign publish datetime.
1593 *
1594 * @return mixed
1595 */
1596 public function getStartTimestamp()
1597 {
1598 return get_the_date($this->id);
1599 }
1600
1601 /**
1602 * Returns position in WooCommerce product page.
1603 * ::PROP
1604 *
1605 * @return mixed
1606 */
1607 public function getWcPosition()
1608 {
1609 $legacy = $this->get_prop_legacy('position');
1610
1611 if (!$legacy) {
1612 return $this->get_prop('wc_position');
1613 }
1614 $this->set_prop('wc_position', $legacy);
1615 $this->delete_prop('position');
1616
1617 return $legacy;
1618 }
1619
1620 private function get_prop_legacy($name)
1621 {
1622 return get_post_meta($this->id, $name, true);
1623 }
1624
1625 /**
1626 * Returns true if WooCommerce integration is enabled.
1627 * ::PROP
1628 *
1629 * @return mixed
1630 */
1631 public function getWcEnable()
1632 {
1633 $value = $this->get_prop('wc_enable', false);
1634
1635 if ($value === C::YES || $value === C::NO) {
1636 return $value;
1637 }
1638
1639 $legacy = filter_var($value, FILTER_VALIDATE_BOOLEAN);
1640 if ($legacy) {
1641 $this->set_prop('wc_enable', C::YES);
1642 } else {
1643 $this->set_prop('wc_enable', C::NO);
1644 }
1645
1646 return $this->get_prop('wc_enable');
1647 }
1648
1649 /**
1650 * Returns true if label should be displayed.
1651 *
1652 * @return mixed
1653 */
1654 public function getLabelVisibility()
1655 {
1656 $meta = 'label_visibility';
1657 $value = $this->get_prop($meta, false);
1658 if ($value === C::NO || $value === C::YES) {
1659 return $value;
1660 }
1661
1662 $legacy = filter_var(
1663 $this->get_prop_legacy('display_labels'),
1664 FILTER_VALIDATE_BOOLEAN
1665 );
1666 $legacy = $legacy ? C::YES : C::NO;
1667
1668 $this->set_prop($meta, $legacy);
1669
1670 $this->delete_prop('display_labels');
1671
1672 return $this->get_prop($meta);
1673 }
1674
1675 /**
1676 *
1677 * Returns restart type.
1678 *
1679 * @return int
1680 */
1681 public function getRestart()
1682 {
1683 return $this->get_prop('restart') ?: C::RESTART_NONE;
1684 }
1685
1686 // removeIf(pro)
1687 public function setRestart($value)
1688 {
1689 if ($value == C::RESTART_AFTER_DURATION) {
1690 return;
1691 }
1692 $this->set_prop('restart', $value);
1693 }
1694 // endRemoveIf(pro)
1695 /**
1696 * Returns WooCommerce products selection type.
1697 *
1698 * @return string
1699 */
1700 public function getWcProductsSelectionType()
1701 {
1702 $legacy = $this->get_prop_legacy('products_type');
1703 if (!$legacy) {
1704 return $this->get_prop('wc_products_selection_type');
1705 }
1706 $this->set_prop('wc_products_selection_type', $legacy);
1707 $this->delete_prop('products_type');
1708
1709 return $legacy;
1710 }
1711
1712 /**
1713 * Delete setting item.
1714 *
1715 * @param $name
1716 */
1717 public function delete_prop($name)
1718 {
1719 delete_post_meta($this->id, $name);
1720 }
1721
1722 /**
1723 * Returns products selection IDs.
1724 * ::PROP
1725 *
1726 * @return array
1727 */
1728 public function getWcProductsSelection()
1729 {
1730 $result = $this->get_prop_legacy('products');
1731 if (!$result) {
1732 $result = $this->get_prop('wc_products_selection');
1733 } else {
1734 $this->set_prop('wc_products_selection', $result);
1735 $this->delete_prop('products');
1736 }
1737
1738 return is_array($result) ? $result : [];
1739 }
1740
1741 /**
1742 * Store custom labels.
1743 * ::PROP
1744 *
1745 * @param $labels
1746 */
1747 public function setLabels($labels)
1748 {
1749 $labels = wp_parse_args($labels, $this->labels);
1750 update_post_meta($this->id, 'labels', $labels);
1751 }
1752
1753 public function getLabels()
1754 {
1755 return wp_parse_args($this->get_prop('labels'), $this->labels);
1756 }
1757
1758 /**
1759 * Returns true if compaign can be published.
1760 *
1761 * @return bool
1762 */
1763 public function is_active()
1764 {
1765 return get_post_status($this->id) === "publish"
1766 || get_post_status($this->id) === "future";
1767 }
1768
1769 /**
1770 * Returns trus if the compaign is scheduled.
1771 *
1772 * @return bool
1773 */
1774 public function is_scheduled()
1775 {
1776 $scheduled = get_post_status($this->get_id()) === "future";
1777 if ($scheduled) {
1778 return true;
1779 }
1780
1781 if ($this->is_recurring()) {
1782 $start_date = Carbon::parse($this->recurringStartTime, hurryt_tz());
1783 $now = Carbon::now(hurryt_tz());
1784 $now->second = $start_date->second;
1785 if ($now->lessThan($start_date)) {
1786
1787 return true;
1788 }
1789 }
1790
1791 return $scheduled;
1792 }
1793
1794 /**
1795 * Returns true if fixed campaign datetime is expired.
1796 *
1797 * @param string|null $date
1798 *
1799 * @return bool
1800 */
1801 public function is_one_time_expired($date = null)
1802 {
1803 $endDate = $date === null ? date_create($this->endDatetime) : $date;
1804 $today = date_create(current_time("mysql"));
1805
1806 return $endDate < $today;
1807 }
1808
1809 public function is_sticky_dismissed()
1810 {
1811 return isset($_COOKIE[Cookie_Detection::COOKIE_PREFIX . $this->get_id() . '_dismissed'])
1812 && $this->stickyBarDismissible === C::YES
1813 && $this->enableSticky === C::YES;
1814 }
1815
1816 /**
1817 * Returns compaign template wrapper.
1818 *
1819 * @param string
1820 *
1821 * @return string
1822 */
1823 public function wrap_template($content, $options = [])
1824 {
1825 $campaignBuilder = new CampaignBuilder($this);
1826
1827 return apply_filters('hurryt_campaign_content', $campaignBuilder->build($content, $options), $this->get_id());
1828 }
1829
1830 /*
1831 * Returns campaign template content.
1832 */
1833 public function build_template()
1834 {
1835 $campaignBuilder = new CampaignBuilder($this);
1836
1837 return $campaignBuilder->template();
1838 }
1839
1840 /**
1841 * ::PROP
1842 *
1843 * @param $value
1844 */
1845 public function setWcConditions($value)
1846 {
1847 $this->set_prop('_hurryt_wc_conditions', !empty($value) ? $value : []);
1848 }
1849
1850 /**
1851 * ::PROP
1852 *
1853 * @return mixed
1854 */
1855 public function getWcConditions()
1856 {
1857 return $this->get_prop('_hurryt_wc_conditions', false);
1858 }
1859
1860
1861 public function setRecurringUnselectedDaysAction($value)
1862 {
1863 $this->set_prop('_hurryt_recurring_unselected_days_action', $value);
1864 }
1865
1866 public function getRecurringUnselectedDaysAction()
1867 {
1868 return $this->get_prop('_hurryt_recurring_unselected_days_action');
1869 }
1870
1871 public function is_running()
1872 {
1873 // TODO: add support for weekly campaigns.
1874 if (
1875 $this->is_recurring()
1876 && !$this->can_recur_today()
1877 && ($this->recurringUnselectedDaysAction === 'hide' || $this->isWeeklyRecurring())
1878 ) {
1879 return false;
1880 }
1881
1882 $not_running = !$this->is_active() || $this->is_scheduled()
1883 || ($this->is_recurring() && empty($this->getRecurrenceEndDate()));
1884
1885
1886 return !$not_running;
1887 }
1888
1889 /**
1890 * Check if recurring or onetime campaign is expired.
1891 *
1892 * @return bool
1893 */
1894 public function is_expired()
1895 {
1896 return ($this->is_one_time() && $this->is_one_time_expired())
1897 || ($this->is_recurring() && $this->is_recurring_expired());
1898 }
1899
1900 public function get_mode_slug()
1901 {
1902 switch ($this->mode) {
1903 case C::MODE_EVERGREEN:
1904 return 'evergreen';
1905 case C::MODE_RECURRING:
1906 return 'recurring';
1907 case C::MODE_REGULAR:
1908 return 'one_time';
1909 }
1910 }
1911
1912 public function getReloadReset()
1913 {
1914 return filter_var($this->get_prop('reload_reset'), FILTER_VALIDATE_BOOLEAN);
1915 }
1916
1917 public function getDetectionMethods()
1918 {
1919 return array_map('intval', $this->get_prop('_hurryt_detection_methods'));
1920 }
1921
1922 public function setDetectionMethods($methods)
1923 {
1924 // removeIf(pro)
1925 if (is_array($methods)) {
1926 $methods = array_filter($methods, function ($m) {
1927 return (int)$m !== C::DETECTION_METHOD_USER_SESSION;
1928 });
1929 }
1930 // endRemoveIf(pro)
1931 $this->set_prop('_hurryt_detection_methods', $methods);
1932 }
1933
1934
1935
1936 /**
1937 * @return bool
1938 */
1939 private function isDailyRecurring()
1940 {
1941 return $this->recurringFrequency === C::RECURRING_DAILY;
1942 }
1943
1944 /**
1945 * @return bool
1946 */
1947 private function isWeeklyRecurring()
1948 {
1949 return $this->recurringFrequency === C::RECURRING_WEEKLY;
1950 }
1951
1952 /**
1953 * @return bool
1954 */
1955 private function isHourlyRecurring()
1956 {
1957 return $this->recurringFrequency === C::RECURRING_HOURLY;
1958 }
1959
1960 /**
1961 * @return bool
1962 */
1963 private function isMinutelyRecurring()
1964 {
1965 return $this->recurringFrequency === C::RECURRING_MINUTELY;
1966 }
1967 }
1968