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