PluginProbe
HurryTimer – An Scarcity and Urgency Countdown Timer for WordPress & WooCommerce / 2.11.0
HurryTimer – An Scarcity and Urgency Countdown Timer for WordPress & WooCommerce v2.11.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.11.0, at includes/Campaign.php

1,967 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 if (!hurrytimer_allow_unfiltered_html()) {
706 $data = wp_kses_post_deep($data);
707 }
708
709 foreach ($data as $prop => $value) {
710 $method = Helpers::snakeToCamelCase("set_{$prop}");
711 if (method_exists($this, $method)) {
712 $this->$method($value ?: $this->$prop);
713 } elseif (property_exists(__CLASS__, Helpers::snakeToCamelCase($prop))) {
714 $this->set_prop($prop, $value);
715 }
716 }
717 if (!isset($data['wc_conditions'])) {
718 $this->setWcConditions([]);
719 }
720 if (!isset($data['sticky_bar_pages'])) {
721 $this->setStickyBarPages([]);
722 }
723
724 CSS_Builder::get_instance()->generate_css();
725 }
726
727 //removeIf(pro)
728
729 /**
730 * @param int $mode
731 * ::PROP
732 */
733 public function setMode($mode)
734 {
735 // if ($mode == C::MODE_RECURRING) {
736 // return;
737 // }
738 $this->set_prop('mode', $mode);
739 }
740 //endRemoveIf(pro)
741
742 /**
743 * TODO: Settings should load automatically upon instance creation.
744 */
745 public function loadSettings()
746 {
747
748 $reflection = new \ReflectionObject($this);
749 // TODO: Refactor prop loading to `$this->get_{prop}()`
750 foreach ($reflection->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) {
751 $name = $prop->getName();
752 $method = 'get' . ucfirst($name);
753 if (method_exists($this, $method)) {
754 $this->{$name} = $this->$method();
755 } else {
756 $this->{$name} = $this->get_prop(Helpers::camelToSnakeCase($name));
757 }
758 }
759 }
760
761
762 public function getHeadline()
763 {
764 if (empty($this->id)) {
765 return $this->headline;
766 }
767 if (metadata_exists('post', $this->id, '_hurryt_headline')) {
768 return $this->get_prop('_hurryt_headline');
769 }
770
771 return get_the_title($this->id);
772 }
773
774 public function setHeadline($value)
775 {
776 $this->set_prop('_hurryt_headline', $value);
777 }
778
779 public function is_published()
780 {
781 return get_post_status($this->id) === "publish";
782 }
783
784 /**
785 * Check if WooCommerce is enabled for this campaign.
786 *
787 * @return bool
788 */
789 public function is_wc_enabled()
790 {
791 return $this->getWcEnable() === C::YES;
792 }
793
794 /**
795 * Check current countdown timer mode
796 * ::PROP
797 *
798 * @return bool
799 */
800 public function is_evergreen()
801 {
802 return $this->get_prop('mode') == C::MODE_EVERGREEN;
803 }
804
805 public function is_one_time()
806 {
807 return $this->get_prop('mode') == C::MODE_REGULAR;
808 }
809
810 public function is_recurring()
811 {
812 return $this->get_prop('mode') == C::MODE_RECURRING;
813 }
814
815 /**
816 * Save compaign endtime for regular mode.
817 *
818 * @param $date
819 */
820 public function setEndDatetime($date)
821 {
822 $this->set_prop('end_datetime', $date ?: $this->defaultEndDatetime());
823 }
824
825 /**
826 * Returns default end datetime for regular mode.
827 * ::PROP
828 *
829 * @return false|string
830 */
831 private function defaultEndDatetime()
832 {
833 return date('Y-m-d h:i A', strtotime('+1 week'));
834 }
835
836 /**
837 * Save digit color.
838 * ::PROP
839 *
840 * @param $color
841 */
842 public function setDigitColor($color)
843 {
844 $this->set_prop('digit_color', $color);
845 }
846
847 /**
848 * Returns headline visibility.
849 * ::PROP
850 *
851 * @return mixed
852 */
853
854 public function getHeadlineVisibility()
855 {
856 $meta = 'headline_visibility';
857
858 $value = $this->get_prop($meta, false);
859 if ($value === C::NO || $value === C::YES) {
860 return $value;
861 }
862
863 $legacyMeta = 'display_headline';
864 $legacyValue = filter_var($this->get_prop_legacy($legacyMeta), FILTER_VALIDATE_BOOLEAN);
865 $legacyValue = $legacyValue ? C::YES : C::NO;
866
867 $this->set_prop($meta, $legacyValue);
868
869 $this->delete_prop($legacyMeta);
870
871 return $this->get_prop($meta);
872 }
873
874 /**
875 * Returns digit color.
876 * Backward compat with older versions.
877 * ::PROP
878 *
879 * @return mixed
880 */
881 public function getDigitColor()
882 {
883 $value = $this->get_prop('digit_color', false);
884 if ($value) {
885 return $value;
886 }
887
888 $legacy = $this->get_prop_legacy('text_color');
889 if (!$legacy) {
890 return $this->digitColor;
891 }
892
893 $this->setDigitColor($legacy);
894 if (!$this->get_prop('label_color', false)) {
895 $this->setLabelColor($legacy);
896 }
897
898 $this->delete_prop('text_color');
899
900 return $this->get_prop('digit_color');
901 }
902
903 /**
904 * ::PROP
905 *
906 * @param $color
907 */
908 public function setLabelColor($color)
909 {
910 $this->set_prop('label_color', $color);
911 }
912
913 /**
914 * Get label color
915 * ::PROP
916 *
917 * @return mixed
918 */
919 public function getLabelColor()
920 {
921 $value = $this->get_prop('label_color', false);
922 if ($value) {
923 return $value;
924 }
925
926 $legacy = $this->get_prop_legacy('text_color');
927 if (!$legacy) {
928 return $this->labelColor;
929 }
930
931 $this->setLabelColor($legacy);
932 if (!$this->get_prop('digit_color', false)) {
933 $this->setDigitColor($legacy);
934 }
935
936 $this->delete_prop('text_color');
937
938 return $this->get_prop('label_color');
939 }
940
941 /**
942 *
943 * Return timer digit size.
944 * Backward comapt. with older versions.
945 * ::PROP
946 *
947 * @return int
948 * @since 1.2.4
949 */
950 public function getDigitSize()
951 {
952 $meta = 'digit_size';
953 $value = $this->get_prop($meta, false);
954 if (!empty($value)) {
955 return $value;
956 }
957 $legacy = $this->get_prop_legacy('text_size');
958
959 if (empty($legacy)) {
960 return $this->digitSize;
961 }
962
963 $this->setDigitSize($legacy);
964
965 $this->delete_prop('text_size');
966
967 return $this->get_prop('digit_size');
968 }
969
970 /**
971 * Save timer digit size.
972 * ::PROP
973 *
974 * @param $size
975 */
976 public function setDigitSize($size)
977 {
978 $this->set_prop('digit_size', $size);
979 }
980
981 /**
982 * Save timer label size.
983 * ::PROP
984 *
985 * @param $size
986 */
987 public function setLabelSize($size)
988 {
989 $this->set_prop('label_size', $size);
990 }
991
992
993 /**
994 * ::PROP
995 *
996 * @param $size
997 */
998 public function setHeadlineSize($size)
999 {
1000 $this->set_prop('headline_size', $size);
1001 }
1002
1003 /**
1004 * Returns evergreen duration.
1005 * ::PROP
1006 *
1007 * @return array
1008 */
1009 public function getDuration()
1010 {
1011 $duration = (array)$this->get_prop('duration');
1012 return array_pad(array_map('intval', $duration), 4, 0);
1013 }
1014
1015
1016
1017 public function getRestartDuration($asSeconds = false)
1018 {
1019 $duration = (array)$this->get_prop('hurryt_restart_duration', false);
1020
1021 $duration = wp_parse_args($duration, $this->restartDuration);
1022 foreach ($duration as $unit => $value) {
1023 $duration[$unit] = (int)$value;
1024 }
1025
1026 if ($asSeconds) {
1027 $duration = $duration['days'] * DAY_IN_SECONDS +
1028 $duration['hours'] * HOUR_IN_SECONDS +
1029 $duration['minutes'] * MINUTE_IN_SECONDS +
1030 $duration['seconds'];
1031 }
1032 return $duration;
1033 }
1034
1035
1036 public function getRecurringPauseDuration($asSeconds = false)
1037 {
1038 $duration = (array)$this->get_prop('_hurryt_recurring_pause_duration', false);
1039
1040 $duration = wp_parse_args($duration, $this->recurringPauseDuration);
1041 foreach ($duration as $unit => $value) {
1042 $duration[$unit] = (int)$value;
1043 }
1044
1045 if ($asSeconds) {
1046 $duration = $duration['days'] * DAY_IN_SECONDS +
1047 $duration['hours'] * HOUR_IN_SECONDS +
1048 $duration['minutes'] * MINUTE_IN_SECONDS +
1049 $duration['seconds'];
1050 }
1051 return $duration;
1052 }
1053
1054 public function setRestartDuration($duration_array)
1055 {
1056 $this->set_prop('hurryt_restart_duration', $duration_array);
1057 }
1058 /**
1059 * ::PROP
1060 *
1061 * @param $value
1062 */
1063 public function setRecurringDuration($value)
1064 {
1065 $this->set_prop('_hurryt_recurring_duration', $value);
1066 }
1067 public function setRecurringPauseDuration($value)
1068 {
1069 $this->set_prop('_hurryt_recurring_pause_duration', $value);
1070 }
1071
1072 /**
1073 * Returns evergreen duration.
1074 *
1075 * @return array
1076 */
1077 public function getRecurringDuration()
1078 {
1079
1080 $duration = (array)$this->get_prop('_hurryt_recurring_duration', false);
1081 return array_pad(array_map('intval', $duration), 4, 0);
1082 }
1083
1084 /**
1085 * Returns actions array.
1086 *
1087 * @return array
1088 */
1089 public function getActions()
1090 {
1091 $legacy = $this->get_prop_legacy('end_action');
1092 if ($legacy) {
1093 $redirectUrl = $this->get_prop_legacy('redirect_url');
1094 $actions = [
1095 [
1096 'id' => intval($legacy),
1097 'redirectUrl' => $redirectUrl,
1098 ],
1099 ];
1100 $this->set_prop('actions', $actions);
1101 $this->delete_prop('end_action');
1102 $this->delete_prop('redirect_url');
1103
1104 return $this->mergeActions($actions);
1105 }
1106
1107 return $this->mergeActions($this->get_prop('actions'));
1108 }
1109
1110 private function mergeActions($actions)
1111 {
1112 $defaults = [
1113 [
1114 'id' => C::ACTION_NONE,
1115 'redirectUrl' => '',
1116 'message' => '',
1117 'coupon' => '',
1118 'wcStockStatus' => '',
1119 ],
1120 ];
1121
1122 if (count($actions) === 0) {
1123 return $defaults;
1124 }
1125
1126 return array_map(function ($action) use ($defaults) {
1127 $action['id'] = (int)$action['id'];
1128
1129 $action['message'] = preg_replace_callback('#<style(\s=?[\S]*)?>([\s\S]*)?<\/style>#', function ($matches) {
1130 return '<style' . $matches[1] . '>' . preg_replace('/\<br(\s*)?\/?\>/i', '', $matches[2]) . '</style>';
1131 }, $action['message']);
1132
1133 return array_merge($defaults[0], $action);
1134 }, $actions);
1135 }
1136
1137
1138 public function get_action($needle)
1139 {
1140 $result = array_filter($this->actions, function ($action) use ($needle) {
1141 return $needle === (int)$action['id'];
1142 });
1143
1144 if (empty($result)) {
1145 return false;
1146 }
1147
1148 return array_shift($result);
1149 }
1150
1151 /**
1152 * Returns evergreen duration in seconds.
1153 *
1154 * @param array $duration
1155 *
1156 * @return int
1157 */
1158 public function durationInSeconds($duration = [])
1159 {
1160 list($d, $h, $m, $s) = empty($duration) ? $this->getDuration() : $duration;
1161
1162 return
1163 $d * DAY_IN_SECONDS +
1164 $h * HOUR_IN_SECONDS +
1165 $m * MINUTE_IN_SECONDS +
1166 $s;
1167 }
1168
1169 /**
1170 * Returns end datetime.
1171 *
1172 * @return string
1173 */
1174 public function getEndDatetime()
1175 {
1176 return $this->get_prop('end_datetime') ?: $this->defaultEndDatetime();
1177 }
1178
1179 /**
1180 * Return true if the recurrence is expired.
1181 *
1182 * @return bool
1183 */
1184 public function is_recurring_expired()
1185 {
1186 $endDate = $this->getRecurrenceEndDate();
1187
1188 if (!($endDate instanceof Carbon)) {
1189 return false;
1190 }
1191
1192 $now = Carbon::now(hurryt_tz());
1193
1194 return $now->greaterThan($endDate);
1195 }
1196
1197 /**
1198 * Calculate next recurrence.
1199 *
1200 * @return mixed
1201 * @throws \Exception
1202 */
1203 function timeToNextRecurrence()
1204 {
1205 $this->loadSettings();
1206
1207 if ($this->isMonthlyRecurring()) {
1208 $current = $this->getRecurrenceEndDate();
1209
1210 $next = $this->getRecurrenceEndDate(true);
1211
1212 $duration = $this->durationInSeconds($this->getRecurringDuration());
1213 $use_custom = $this->recurringDurationOption === 'custom' && $duration > 0;
1214
1215 if ($use_custom) {
1216 $time_remaining = $next->diffInSeconds($current);
1217 } else {
1218 $time_remaining = $this->getRecurringPauseDuration(true);
1219 }
1220 return $time_remaining;
1221 }
1222
1223 list($duration, $pause, $period) = $this->getRecurringDurationInSeconds();
1224
1225 $t = $pause ?: 0;
1226
1227 $waitBeforeRestart = $this->getRecurringPauseDuration(true);
1228
1229 $t += $waitBeforeRestart;
1230
1231 if (!$this->has_skipped_days()) {
1232 return $t;
1233 }
1234
1235 if ($this->isWeeklyRecurring()) {
1236 return $t;
1237 }
1238
1239 if ($this->recurringUnselectedDaysAction === 'hide') {
1240 return $t;
1241 }
1242
1243 return $waitBeforeRestart;
1244 }
1245
1246 /**
1247 * Return true if the current campaign can recur today.
1248 *
1249 * @return bool
1250 */
1251 public function can_recur_today()
1252 {
1253 $this->loadSettings();
1254
1255 $day = absint(Carbon::now(hurryt_tz())->format('w'));
1256
1257 $recur = in_array($day, array_map('absint', $this->recurringDays));
1258
1259 return apply_filters('hurryt_recur_today', $recur, $this->get_id());
1260 }
1261
1262 public function isMonthlyRecurring()
1263 {
1264 return $this->recurringFrequency === C::RECURRING_MONTHLY;
1265 }
1266
1267 public function isDayOfWeekRecurring()
1268 {
1269
1270 return $this->recurringMonthlyDayType === C::RECURRING_MONTHLY_DAY_OF_WEEK;
1271 }
1272
1273 public function isDayOfMonthRecurring()
1274 {
1275 return $this->recurringMonthlyDayType === C::RECURRING_MONTHLY_DAY_OF_MONTH;
1276 }
1277
1278 public function shouldEndRecurringByDate()
1279 {
1280 return absint($this->recurringEnd) === C::RECURRING_END_TIME;
1281 }
1282 public function shouldEndRecurringByRecurrences()
1283 {
1284 return (int)$this->recurringEnd === C::RECURRING_END_OCCURRENCES;
1285 }
1286
1287 public function shouldRecurForever()
1288 {
1289 return (int)$this->recurringEnd === C::RECURRING_END_NEVER;
1290 }
1291
1292 public function getRecurringRecurrences()
1293 {
1294 $num = (int)$this->recurringCount;
1295 return ++$num;
1296 }
1297
1298
1299 public function getRecurringPeriodEndDate()
1300 {
1301 list($d, $h, $m, $s) = $this->getRecurringDuration();
1302 $now = Carbon::now(hurryt_tz());
1303 $startDate = Carbon::parse($this->recurringStartTime, hurryt_tz());
1304 $interval = (int)$this->recurringInterval;
1305 $endDate = $now->copy();
1306
1307 switch ($this->recurringFrequency) {
1308 case C::RECURRING_DAILY:
1309 $endDate->minute = $startDate->minute;
1310 $endDate->addDays(max($interval, $d))->addHours($interval)->addMinutes($m)->addSeconds($s);
1311 break;
1312 case C::RECURRING_WEEKLY:
1313 $endDate->minute = $startDate->minute;
1314 $endDate->addWeeks($interval)->addHours($h)->addMinutes($m)->addSeconds($s);
1315 break;
1316 case C::RECURRING_HOURLY:
1317 $endDate->minute = $startDate->minute;
1318 $endDate->addHours(max($interval, $h))->addMinutes($m)->addSeconds($s);
1319 break;
1320 case C::RECURRING_MINUTELY:
1321 $minutes = max($interval, $m);
1322 $endDate->addMinutes($minutes)->addSeconds($s);
1323 break;
1324 }
1325
1326 return $endDate;
1327 }
1328
1329 public function getRecurringFrequencyInSeconds()
1330 {
1331 $freq = 0;
1332 switch ($this->recurringFrequency) {
1333 case C::RECURRING_WEEKLY:
1334 $freq = WEEK_IN_SECONDS;
1335 break;
1336 case C::RECURRING_DAILY:
1337 $freq = DAY_IN_SECONDS;
1338 break;
1339 case C::RECURRING_HOURLY:
1340 $freq = HOUR_IN_SECONDS;
1341 break;
1342 case C::RECURRING_MINUTELY:
1343 $freq = MINUTE_IN_SECONDS;
1344 break;
1345 }
1346
1347 return $freq * (int)$this->recurringInterval;
1348 }
1349 /**
1350 * @return array [duration, pause, period] in seconds
1351 */
1352 public function getRecurringDurationInSeconds()
1353 {
1354 $duration = $this->durationInSeconds($this->getRecurringDuration());
1355 $period = $this->getRecurringFrequencyInSeconds();
1356 $pause = $period - $duration;
1357 return [$duration, max(0, $pause), $period];
1358 }
1359
1360 /**
1361 * Returns the recurrence end date based on the current date/time.
1362 *
1363 * @param bool $next Return the next recurrence end date.
1364 *
1365 * @return Carbon
1366 */
1367
1368 public function getRecurrenceEndDate($next = false)
1369 {
1370
1371 $cached_key = $next ? 'recur_end_date__next' : 'recur_end_date';
1372 $cached = wp_cache_get($cached_key, 'hurrytimer');
1373 if ($cached instanceof Carbon) {
1374 return $cached;
1375 }
1376
1377 try {
1378
1379 $this->loadSettings();
1380 $now = Carbon::now(hurryt_tz());
1381 $startDate = Carbon::parse($this->recurringStartTime, hurryt_tz());
1382 $interval = (int)$this->recurringInterval;
1383
1384
1385 // Handle monthly recurring
1386 if ($this->isMonthlyRecurring()) {
1387 $start_date_modified = $startDate->copy();
1388
1389 if ($startDate->day >= 28) {
1390 $start_date_modified->startOfMonth();
1391 }
1392
1393 $endDate = $now->copy()->addMonths($interval);
1394
1395 if ($next) {
1396 $endDate->addMonths($interval);
1397 }
1398
1399 if ($this->shouldEndRecurringByDate()) {
1400 $endDate = Carbon::parse($this->recurringUntil, hurryt_tz());
1401 }
1402
1403 if ($this->isDayOfWeekRecurring()) {
1404 $endDate = $endDate->addMonths($interval);
1405 }
1406
1407 $period = CarbonPeriod::create($start_date_modified, 'P' . $interval . 'M', $endDate);
1408
1409 if ($this->shouldEndRecurringByRecurrences()) {
1410 $period->setRecurrences($this->getRecurringRecurrences());
1411 }
1412
1413 if ($period->count() === 0) {
1414 return $period->getEndDate();
1415 }
1416
1417 $dates = iterator_to_array($period);
1418
1419 $dates = array_map(function ($date) use ($startDate) {
1420 $is_overflow = $startDate->day >= $date->daysInMonth;
1421 if ($this->isDayOfMonthRecurring() && $is_overflow) {
1422 $date->endOfMonth();
1423 }
1424 if ($this->isDayOfWeekRecurring()) {
1425 $date->modifyWeekOfMonth($startDate);
1426 }
1427 $date->setTimeFrom($startDate);
1428
1429 return $date;
1430 }, $dates);
1431
1432
1433 $out_date = end($dates) ?: $period->getEndDate();
1434
1435 reset($dates);
1436
1437 foreach ($dates as $i => $date) {
1438 $duration = $this->durationInSeconds($this->getRecurringDuration());
1439 $custom = $this->recurringDurationOption === 'custom' && $duration > 0;
1440
1441 if ($custom && !$next) {
1442 $custom_end_date = $date->copy()->addSeconds($duration);
1443
1444 if ($custom_end_date->greaterThan($now)) {
1445 $out_date = $custom_end_date;
1446
1447 break;
1448 }
1449
1450 $next_date = isset($dates[$i + 1]) ? $dates[$i + 1] : $period->getEndDate();
1451
1452 if ($now->lessThan($next_date)) {
1453 $out_date = $custom_end_date;
1454 break;
1455 }
1456
1457 continue;
1458 }
1459
1460 if ($date->greaterThan($now)) {
1461 $pause_duration = $this->getRecurringPauseDuration(true);
1462
1463 if ($next && !$custom) {
1464 $out_date = isset($dates[$i + 1]) ? $dates[$i + 1] : $out_date;
1465
1466 if ($pause_duration > 0) {
1467 $out_date = $date;
1468 }
1469 } else {
1470 $out_date = $date;
1471 $prev_end_date = isset($dates[$i - 1]) ? $dates[$i - 1] : null;
1472 if ($prev_end_date && $prev_end_date->copy()->diffInSeconds($now) < $pause_duration) {
1473 $out_date = $prev_end_date;
1474 }
1475 }
1476
1477 break;
1478 }
1479 }
1480 if ($this->shouldEndRecurringByDate() && $out_date->lessThan($now)) {
1481 // TODO: Use the last recurrence instead of `getEndDate()`
1482 $out_date = $period->getEndDate();
1483 }
1484
1485 wp_cache_set($cached_key, $out_date, 'hurrytimer');
1486
1487 return $out_date;
1488 } // Monthly recurring
1489
1490
1491 // Prevent minutely recurring from affecting performance
1492 // by updating the start date year and month to current ones.
1493 if ($this->isMinutelyRecurring()) {
1494 $startDate->year = $now->year;
1495 $startDate->month = $now->month;
1496 $startDate->day = $now->day;
1497 }
1498
1499
1500 list($duration, $pause) = $this->getRecurringDurationInSeconds();
1501
1502 $period = CarbonPeriod::start($startDate, true);
1503
1504 $period->seconds($duration + $pause);
1505
1506 if ($this->shouldEndRecurringByRecurrences()) {
1507 $period->setRecurrences($this->getRecurringRecurrences());
1508 } else {
1509 $endDate = $this->getRecurringPeriodEndDate();
1510 $dateperiod_interval = new DateInterval('PT' .($duration + $pause) . 'S');
1511 $period = new DatePeriod($startDate->toDateTime(), $dateperiod_interval, $endDate->addDays(7 * $interval)->toDateTime());
1512 // $period->until($endDate->addDays(7 * $interval));
1513
1514 }
1515
1516 $date = null;
1517
1518 $i = 0;
1519
1520 $pause_duration = $this->getRecurringPauseDuration(true);
1521
1522 foreach ($period as $start) {
1523
1524 $start = Carbon::instance($start);
1525
1526 $end = $start->copy()->addSeconds($this->getRecurringFrequencyInSeconds() - 1);
1527
1528 if ($now->isBetween($start, $end->copy()->addSeconds($pause_duration))) {
1529 $date = $start->copy()->addSeconds($duration - 1);
1530 if (!in_array($date->format('w'), $this->recurringDays)) {
1531 continue;
1532 }
1533 break;
1534 }
1535
1536 if ($now->isBefore($end->copy()->addSeconds($pause_duration))) {
1537 $date = $start;
1538 if (!in_array($date->format('w'), $this->recurringDays)) {
1539 continue;
1540 }
1541 break;
1542 }
1543 }
1544
1545 if (empty($date)) {
1546 return $period->getEndDate();
1547 }
1548
1549 $stop_date = Carbon::parse($this->recurringUntil, hurryt_tz());
1550
1551 if ($this->shouldEndRecurringByDate() && $stop_date->lessThan($date)) {
1552 return $stop_date;
1553 }
1554
1555 return $date;
1556 } catch (\Exception $e) {
1557 return false;
1558 }
1559 }
1560
1561
1562 function should_hide_today($date, $now)
1563 {
1564 return ($date->format('w') === $now->format('w')) && ($this->isWeeklyRecurring() || $this->recurringUnselectedDaysAction === 'hide');
1565 }
1566 function has_skipped_days()
1567 {
1568 $recur_days = array_map('intval', $this->recurringDays);
1569 return count($recur_days) < 7;
1570 }
1571 function can_recur_on($date)
1572 {
1573 $recur_days = array_map('intval', $this->recurringDays);
1574
1575 if (in_array($date->format('w'), $recur_days)) {
1576 return true;
1577 }
1578
1579 if (($date->isStartOfDay() && in_array($this->get_previous_day($date->format('w')), $recur_days))) {
1580 return true;
1581 }
1582
1583 return false;
1584 }
1585 private function get_previous_day($current_day)
1586 {
1587 $current_day === 0 ? 6 : ($current_day - 1);
1588 }
1589
1590 /**
1591 * Returns compaign publish datetime.
1592 *
1593 * @return mixed
1594 */
1595 public function getStartTimestamp()
1596 {
1597 return get_the_date($this->id);
1598 }
1599
1600 /**
1601 * Returns position in WooCommerce product page.
1602 * ::PROP
1603 *
1604 * @return mixed
1605 */
1606 public function getWcPosition()
1607 {
1608 $legacy = $this->get_prop_legacy('position');
1609
1610 if (!$legacy) {
1611 return $this->get_prop('wc_position');
1612 }
1613 $this->set_prop('wc_position', $legacy);
1614 $this->delete_prop('position');
1615
1616 return $legacy;
1617 }
1618
1619 private function get_prop_legacy($name)
1620 {
1621 return get_post_meta($this->id, $name, true);
1622 }
1623
1624 /**
1625 * Returns true if WooCommerce integration is enabled.
1626 * ::PROP
1627 *
1628 * @return mixed
1629 */
1630 public function getWcEnable()
1631 {
1632 $value = $this->get_prop('wc_enable', false);
1633
1634 if ($value === C::YES || $value === C::NO) {
1635 return $value;
1636 }
1637
1638 $legacy = filter_var($value, FILTER_VALIDATE_BOOLEAN);
1639 if ($legacy) {
1640 $this->set_prop('wc_enable', C::YES);
1641 } else {
1642 $this->set_prop('wc_enable', C::NO);
1643 }
1644
1645 return $this->get_prop('wc_enable');
1646 }
1647
1648 /**
1649 * Returns true if label should be displayed.
1650 *
1651 * @return mixed
1652 */
1653 public function getLabelVisibility()
1654 {
1655 $meta = 'label_visibility';
1656 $value = $this->get_prop($meta, false);
1657 if ($value === C::NO || $value === C::YES) {
1658 return $value;
1659 }
1660
1661 $legacy = filter_var(
1662 $this->get_prop_legacy('display_labels'),
1663 FILTER_VALIDATE_BOOLEAN
1664 );
1665 $legacy = $legacy ? C::YES : C::NO;
1666
1667 $this->set_prop($meta, $legacy);
1668
1669 $this->delete_prop('display_labels');
1670
1671 return $this->get_prop($meta);
1672 }
1673
1674 /**
1675 *
1676 * Returns restart type.
1677 *
1678 * @return int
1679 */
1680 public function getRestart()
1681 {
1682 return $this->get_prop('restart') ?: C::RESTART_NONE;
1683 }
1684
1685 // removeIf(pro)
1686 public function setRestart($value)
1687 {
1688 if ($value == C::RESTART_AFTER_DURATION) {
1689 return;
1690 }
1691 $this->set_prop('restart', $value);
1692 }
1693 // endRemoveIf(pro)
1694 /**
1695 * Returns WooCommerce products selection type.
1696 *
1697 * @return string
1698 */
1699 public function getWcProductsSelectionType()
1700 {
1701 $legacy = $this->get_prop_legacy('products_type');
1702 if (!$legacy) {
1703 return $this->get_prop('wc_products_selection_type');
1704 }
1705 $this->set_prop('wc_products_selection_type', $legacy);
1706 $this->delete_prop('products_type');
1707
1708 return $legacy;
1709 }
1710
1711 /**
1712 * Delete setting item.
1713 *
1714 * @param $name
1715 */
1716 public function delete_prop($name)
1717 {
1718 delete_post_meta($this->id, $name);
1719 }
1720
1721 /**
1722 * Returns products selection IDs.
1723 * ::PROP
1724 *
1725 * @return array
1726 */
1727 public function getWcProductsSelection()
1728 {
1729 $result = $this->get_prop_legacy('products');
1730 if (!$result) {
1731 $result = $this->get_prop('wc_products_selection');
1732 } else {
1733 $this->set_prop('wc_products_selection', $result);
1734 $this->delete_prop('products');
1735 }
1736
1737 return is_array($result) ? $result : [];
1738 }
1739
1740 /**
1741 * Store custom labels.
1742 * ::PROP
1743 *
1744 * @param $labels
1745 */
1746 public function setLabels($labels)
1747 {
1748 $labels = wp_parse_args($labels, $this->labels);
1749 update_post_meta($this->id, 'labels', $labels);
1750 }
1751
1752 public function getLabels()
1753 {
1754 return wp_parse_args($this->get_prop('labels'), $this->labels);
1755 }
1756
1757 /**
1758 * Returns true if compaign can be published.
1759 *
1760 * @return bool
1761 */
1762 public function is_active()
1763 {
1764 return get_post_status($this->id) === "publish"
1765 || get_post_status($this->id) === "future";
1766 }
1767
1768 /**
1769 * Returns trus if the compaign is scheduled.
1770 *
1771 * @return bool
1772 */
1773 public function is_scheduled()
1774 {
1775 $scheduled = get_post_status($this->get_id()) === "future";
1776 if ($scheduled) {
1777 return true;
1778 }
1779
1780 if ($this->is_recurring()) {
1781 $start_date = Carbon::parse($this->recurringStartTime, hurryt_tz());
1782 $now = Carbon::now(hurryt_tz());
1783 $now->second = $start_date->second;
1784 if ($now->lessThan($start_date)) {
1785
1786 return true;
1787 }
1788 }
1789
1790 return $scheduled;
1791 }
1792
1793 /**
1794 * Returns true if fixed campaign datetime is expired.
1795 *
1796 * @param string|null $date
1797 *
1798 * @return bool
1799 */
1800 public function is_one_time_expired($date = null)
1801 {
1802 $endDate = $date === null ? date_create($this->endDatetime) : $date;
1803 $today = date_create(current_time("mysql"));
1804
1805 return $endDate < $today;
1806 }
1807
1808 public function is_sticky_dismissed()
1809 {
1810 return isset($_COOKIE[Cookie_Detection::COOKIE_PREFIX . $this->get_id() . '_dismissed'])
1811 && $this->stickyBarDismissible === C::YES
1812 && $this->enableSticky === C::YES;
1813 }
1814
1815 /**
1816 * Returns compaign template wrapper.
1817 *
1818 * @param string
1819 *
1820 * @return string
1821 */
1822 public function wrap_template($content, $options = [])
1823 {
1824 $campaignBuilder = new CampaignBuilder($this);
1825
1826 return apply_filters('hurryt_campaign_content', $campaignBuilder->build($content, $options), $this->get_id());
1827 }
1828
1829 /*
1830 * Returns campaign template content.
1831 */
1832 public function build_template()
1833 {
1834 $campaignBuilder = new CampaignBuilder($this);
1835
1836 return $campaignBuilder->template();
1837 }
1838
1839 /**
1840 * ::PROP
1841 *
1842 * @param $value
1843 */
1844 public function setWcConditions($value)
1845 {
1846 $this->set_prop('_hurryt_wc_conditions', !empty($value) ? $value : []);
1847 }
1848
1849 /**
1850 * ::PROP
1851 *
1852 * @return mixed
1853 */
1854 public function getWcConditions()
1855 {
1856 return $this->get_prop('_hurryt_wc_conditions', false);
1857 }
1858
1859
1860 public function setRecurringUnselectedDaysAction($value)
1861 {
1862 $this->set_prop('_hurryt_recurring_unselected_days_action', $value);
1863 }
1864
1865 public function getRecurringUnselectedDaysAction()
1866 {
1867 return $this->get_prop('_hurryt_recurring_unselected_days_action');
1868 }
1869
1870 public function is_running()
1871 {
1872 // TODO: add support for weekly campaigns.
1873 if (
1874 $this->is_recurring()
1875 && !$this->can_recur_today()
1876 && ($this->recurringUnselectedDaysAction === 'hide' || $this->isWeeklyRecurring())
1877 ) {
1878 return false;
1879 }
1880
1881 $not_running = !$this->is_active() || $this->is_scheduled()
1882 || ($this->is_recurring() && empty($this->getRecurrenceEndDate()));
1883
1884
1885 return !$not_running;
1886 }
1887
1888 /**
1889 * Check if recurring or onetime campaign is expired.
1890 *
1891 * @return bool
1892 */
1893 public function is_expired()
1894 {
1895 return ($this->is_one_time() && $this->is_one_time_expired())
1896 || ($this->is_recurring() && $this->is_recurring_expired());
1897 }
1898
1899 public function get_mode_slug()
1900 {
1901 switch ($this->mode) {
1902 case C::MODE_EVERGREEN:
1903 return 'evergreen';
1904 case C::MODE_RECURRING:
1905 return 'recurring';
1906 case C::MODE_REGULAR:
1907 return 'one_time';
1908 }
1909 }
1910
1911 public function getReloadReset()
1912 {
1913 return filter_var($this->get_prop('reload_reset'), FILTER_VALIDATE_BOOLEAN);
1914 }
1915
1916 public function getDetectionMethods()
1917 {
1918 return array_map('intval', $this->get_prop('_hurryt_detection_methods'));
1919 }
1920
1921 public function setDetectionMethods($methods)
1922 {
1923 // removeIf(pro)
1924 if (is_array($methods)) {
1925 $methods = array_filter($methods, function ($m) {
1926 return (int)$m !== C::DETECTION_METHOD_USER_SESSION;
1927 });
1928 }
1929 // endRemoveIf(pro)
1930 $this->set_prop('_hurryt_detection_methods', $methods);
1931 }
1932
1933
1934
1935 /**
1936 * @return bool
1937 */
1938 private function isDailyRecurring()
1939 {
1940 return $this->recurringFrequency === C::RECURRING_DAILY;
1941 }
1942
1943 /**
1944 * @return bool
1945 */
1946 private function isWeeklyRecurring()
1947 {
1948 return $this->recurringFrequency === C::RECURRING_WEEKLY;
1949 }
1950
1951 /**
1952 * @return bool
1953 */
1954 private function isHourlyRecurring()
1955 {
1956 return $this->recurringFrequency === C::RECURRING_HOURLY;
1957 }
1958
1959 /**
1960 * @return bool
1961 */
1962 private function isMinutelyRecurring()
1963 {
1964 return $this->recurringFrequency === C::RECURRING_MINUTELY;
1965 }
1966 }
1967