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