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

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

1,446 lines 30.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Hurrytimer;
4
5 use Carbon\Carbon;
6 use Carbon\CarbonPeriod;
7 use Hurrytimer\Utils\Helpers;
8
9 class Campaign
10 {
11
12 /**
13 * Campaign custom post ID
14 *
15 * @var int
16 */
17 private $id;
18
19 /**
20 * Campaign mode.
21 *
22 * @see C.php
23 *
24 * @var int
25 */
26 public $mode = C::MODE_REGULAR;
27
28 /**
29 * Evergreen duration array.
30 *
31 * @see getDuration()
32 *
33 * @var array
34 */
35 public $duration;
36
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 /**
95 * Restart option after expiration.
96 *
97 * @see \Hurrytimer\CampaignRestart
98 *
99 * @var int
100 */
101 public $restart;
102
103 /**
104 * Headline text.
105 *
106 * @var string
107 */
108 public $headline = "Hurry Up!";
109
110 /**
111 * Headline color.
112 *
113 * @var string
114 */
115 public $headlineColor = "#000";
116
117 /**
118 * Headline size.
119 *
120 * @var int
121 */
122 public $headlineSize = 30;
123
124 /**
125 * Headline position.
126 *
127 * @var int
128 */
129 public $headlinePosition = C::HEADLINE_POSITION_ABOVE_TIMER;
130
131 /**
132 * Headline visibility.
133 *
134 * @var boolean
135 */
136 public $headlineVisibility = C::YES;
137
138 public $headlineSpacing = 5;
139
140 /**
141 * Control labels visibility.
142 *
143 * @var string
144 */
145 public $labelVisibility = C::YES;
146
147 /**
148 * Show/hide days block.
149 *
150 * @var string
151 */
152 public $daysVisibility = C::YES;
153
154 /**
155 * Show/hide hours block.
156 *
157 * @var string
158 */
159 public $hoursVisibility = C::YES;
160
161 /**
162 * Show/hide minutes block.
163 *
164 * @var string
165 */
166 public $minutesVisibility = C::YES;
167
168 /**
169 * Show/hide seconds block.
170 *
171 * @var string
172 */
173 public $secondsVisibility = C::YES;
174
175 /**
176 * Regular campaign end date/time.
177 *
178 * @var string
179 */
180 public $endDatetime;
181
182 /**
183 * Labels texts.
184 *
185 * @var array
186 */
187 public $labels
188 = [
189 'days' => 'days',
190 'hours' => 'hrs',
191 'minutes' => 'mins',
192 'seconds' => 'secs',
193 ];
194
195 /**
196 * Digit color.
197 *
198 * @var string
199 */
200 public $digitColor = "#000";
201
202 /**
203 * Digit size.
204 *
205 * @var int
206 */
207 public $digitSize = 35;
208
209 /**
210 * Redirect action url.
211 *
212 * @var string
213 */
214 public $redirectUrl;
215
216 /**
217 * Label size.
218 *
219 * @var int
220 */
221 public $labelSize = 12;
222
223 /**
224 * Label color.
225 *
226 * @var string
227 */
228 public $labelColor = "#000";
229
230 /**
231 * End action.
232 *
233 * @var array
234 */
235 public $actions = [];
236
237 /**
238 * WooCommerce compaign position in product page.
239 *
240 * @var int
241 */
242 public $wcPosition = C::WC_POSITION_ABOVE_TITLE;
243
244 /**
245 * Enable/disable woocommerce integration.
246 *
247 * @var string
248 */
249 public $wcEnable = C::NO;
250
251 /**
252 * WooCommerce products selection.
253 *
254 * @var array
255 */
256 public $wcProductsSelection;
257
258 /**
259 * WooCommerce products selection type.
260 *
261 * @var int
262 */
263 public $wcProductsSelectionType;
264
265 public $wcConditions;
266
267 /**
268 * Timer block border color.
269 *
270 * @var string
271 */
272 public $blockBorderColor = "";
273
274 /**
275 * Timer Block border width.
276 *
277 * @var int
278 */
279
280 public $blockBorderWidth = 0;
281
282 /**
283 * Timer block radius.
284 *
285 * @var int
286 */
287 public $blockBorderRadius = 0;
288
289 /**
290 * Block size.
291 *
292 * @var int
293 */
294
295 public $blockSize = 50;
296
297 /**
298 * Block background color.
299 *
300 * @var string
301 */
302 public $blockBgColor = '';
303
304 /**
305 * Block spacing.
306 *
307 * @var int
308 */
309 public $blockSpacing = 5;
310
311 /**
312 * Block padding.
313 *
314 * @var int
315 */
316 public $blockPadding = 0;
317
318 /**
319 * Block spearator visibility.
320 *
321 * @var boolean
322 */
323 public $blockSeparatorVisibility = C::YES;
324
325 /**
326 * Label case
327 *
328 * @var string
329 */
330 public $labelCase = C::TRANSFORM_UPPERCASE;
331
332 /**
333 * Custom CSS
334 *
335 * @var string
336 */
337 public $customCss = '';
338
339 /**
340 * Block elements display
341 * Values: block, inline
342 *
343 * @var string
344 */
345 public $blockDisplay = 'block';
346
347 /**
348 * Enable sticky bar.
349 */
350 public $enableSticky = C::NO;
351
352 /**
353 * Sticky bar background color.
354 *
355 * @var string
356 */
357 public $stickyBarBgColor = '#eee';
358
359 /**
360 * Sticky bar close button color.
361 *
362 * @var string
363 */
364 public $stickyBarCloseBtnColor = '#fff';
365
366 /**
367 * Sticky bar position.
368 * Values: top, bottom
369 *
370 * @var string
371 */
372 public $stickyBarPosition = 'top';
373
374 /**
375 * Sticky bar padding.
376 *
377 * @var integer
378 */
379 public $stickyBarPadding = 5;
380
381 /**
382 * Sticky bar display pages.
383 *
384 * @var array
385 */
386 public $stickyBarPages = [];
387
388 /**
389 * Where to display the sticky bar option
390 *
391 * @var string
392 */
393 public $stickyBarDisplayOn = 'all_pages';
394
395 /**
396 * Show sticky bar close button?
397 *
398 * @var string
399 */
400 public $stickyBarDismissible = C::YES;
401
402 /**
403 * CTA settings.
404 *
405 * @var array
406 */
407 public $callToAction
408 = [
409 'enabled' => C::NO,
410 'new_tab' => C::NO,
411 'url' => '',
412 'text' => 'Learn More',
413 'text_size' => 15,
414 'text_color' => '#fff',
415 'bg_color' => '#000',
416 'y_padding' => 10,
417 'x_padding' => 15,
418 'border_radius' => 3,
419 'spacing' => 5,
420 ];
421
422 /**
423 * Campaign elements display
424 * values: block,inline
425 *
426 * @var string
427 */
428 public $campaignDisplay = 'block';
429
430 /**
431 * Campaign aligments
432 * values: center,left,right
433 *
434 * @var string
435 */
436 public $campaignAlign = 'center';
437
438 /**
439 * Campaign spacing.
440 *
441 * @var integer
442 */
443 public $campaignSpacing = 10;
444
445 /**
446 * Campaign horizontal padding.
447 *
448 * @var integer
449 */
450 public $campaignXPadding = 10;
451
452 /**
453 * Campaign vertical padding.
454 *
455 * @var integer
456 */
457 public $campaignYPadding = 10;
458
459 public function __construct( $id )
460 {
461 $this->recurringStartTime = Carbon::now( hurryt_tz() )->format( 'Y-m-d h:i A' );
462 $this->id = $id;
463 }
464
465 /**
466 * Returns compaign post iD.
467 *
468 * @return int
469 */
470 public function get_id()
471 {
472 return $this->id;
473 }
474
475 /**
476 * Returns true if the current sticky bar can be displayed on the given page.
477 *
478 * @param $page_id
479 *
480 * @return bool
481 */
482 public function show_sticky_on_page( $page_id )
483 {
484 if ( $this->enableSticky === C::NO ) {
485 return true;
486 }
487
488 $can_show = false;
489 switch ( $this->getStickyBarDisplayOn() ) {
490 case 'all_pages':
491 $can_show = true;
492 break;
493 case 'wc_products_pages':
494 if ( function_exists( 'is_product' ) && is_product() ) {
495 $wc_campaign = new WCCampaign();
496 $can_show = ( $wc_campaign->has_campaign( $this, $page_id ) );
497 } else {
498 $can_show = false;
499 }
500 break;
501 case 'specific_pages':
502 $pages = $this->getStickyBarPages();
503 $can_show = in_array( $page_id, $pages );
504 break;
505 }
506
507 return apply_filters( 'hurryt_show_sticky_bar', $can_show, $this->get_id() );
508
509 }
510
511 /**
512 * Returns sticky bar pages.
513 *
514 * @return array
515 */
516 public function getStickyBarPages()
517 {
518 $pagesIds = $this->get_prop( 'sticky_bar_pages' );
519
520 return array_filter( array_map( 'intval', $pagesIds ) );
521 }
522
523 /**
524 * Set sticky bar pages.
525 *
526 * @param $value
527 */
528 public function setStickyBarPages( $value )
529 {
530 $this->set_prop( 'sticky_bar_pages', $value );
531 }
532
533 public function getStickyBarDisplayOn()
534 {
535
536 // backward compat.
537 $all_pages = $this->get_prop( 'sticky_bar_show_on_all_pages', false );
538
539 if ( $all_pages === C::YES ) {
540 $this->setStickyBarDisplayOn( 'all_pages' );
541 }
542
543 $this->delete_prop( 'sticky_bar_show_on_all_pages' );
544
545 $value = $this->get_prop( '_hurryt_sticky_bar_display_on', false );
546
547 return !empty( $value ) ? $value : $this->stickyBarDisplayOn;
548 }
549
550 public function setStickyBarDisplayOn( $value )
551 {
552 $this->set_prop( '_hurryt_sticky_bar_display_on', $value );
553 }
554
555 /**
556 * Get raw setting.
557 *
558 * @param string $name
559 * @param boolean
560 *
561 * @return mixed
562 */
563 public function get_prop( $name, $useDefault = true )
564 {
565 $value = get_post_meta( $this->id, $name, true );
566 if ( !empty( $value ) ) {
567 return $value;
568 }
569 if ( $useDefault ) {
570 return $this->{Helpers::snakeToCamelCase( $name )};
571 }
572
573 return $value;
574 }
575
576 public function set_prop( $name, $value )
577 {
578 $value = !empty( $value ) ? $value : '';
579 $getterMethod = Helpers::snakeToCamelCase( $name );
580 if ( empty( $value ) && method_exists( $this, $getterMethod ) ) {
581 $value = $this->{$getterMethod}();
582 }
583
584 update_post_meta( $this->id, $name, $value );
585 }
586
587 /**
588 * Bulk save for compaign settings.
589 *
590 * @param $data
591 */
592 public function storeSettings( $data )
593 {
594 foreach ( $data as $prop => $value ) {
595 $method = Helpers::snakeToCamelCase( "set_{$prop}" );
596 if ( method_exists( $this, $method ) ) {
597 $this->$method( $value ?: $this->$prop );
598 } elseif ( property_exists( __CLASS__, Helpers::snakeToCamelCase( $prop ) ) ) {
599 $this->set_prop( $prop, $value );
600 }
601 }
602 if ( !isset( $data[ 'wc_conditions' ] ) ) {
603 $this->setWcConditions( [] );
604 }
605 if ( !isset( $data[ 'sticky_bar_pages' ] ) ) {
606 $this->setStickyBarPages( [] );
607 }
608 self::generate_css();
609 }
610
611 //removeIf(pro)
612
613 /**
614 * @param int $mode
615 * ::PROP
616 */
617 public function setMode( $mode )
618 {
619 if ( $mode == C::MODE_RECURRING ) {
620 return;
621 }
622 $this->set_prop( 'mode', $mode );
623 }
624 //endRemoveIf(pro)
625
626 /**
627 * Build User CSS,
628 * Then merge it with base one.
629 *
630 * @return void
631 */
632 public static function generate_css()
633 {
634
635 // Build and return CSS
636 ob_start();
637 include HURRYT_DIR . 'includes/css.php';
638 $css = ob_get_clean();
639 $base = file_get_contents( HURRYT_DIR . '/assets/css/base.css' );
640
641 // Merge built and base css.
642 $base .= $css;
643
644 // Save to public file.
645 file_put_contents( HURRYT_DIR . '/assets/css/hurrytimer.css', $base );
646 }
647
648 /**
649 * @todo refactor
650 */
651 public function loadSettings()
652 {
653
654 $reflection = new \ReflectionObject( $this );
655 foreach ( $reflection->getProperties( \ReflectionProperty::IS_PUBLIC ) as $prop ) {
656 $name = $prop->getName();
657 $method = 'get' . ucfirst( $name );
658 if ( method_exists( $this, $method ) ) {
659 $this->{$name} = $this->$method();
660 } else {
661 $this->{$name} = $this->get_prop( Helpers::camelToSnakeCase( $name ) );
662 }
663 }
664 }
665
666 /**
667 * Returns compaign headline.
668 * ::PROP
669 *
670 * @return mixed
671 */
672 public function getHeadline()
673 {
674 return $this->id ? get_the_title( $this->id ) : $this->headline;
675 }
676
677 public function is_published()
678 {
679 return get_post_status( $this->id ) === "publish";
680 }
681
682 /**
683 * Check if WooCommerce is enabled for this campaign.
684 *
685 * @return bool
686 */
687 public function is_wc_enabled()
688 {
689 return $this->getWcEnable() === C::YES;
690 }
691
692 /**
693 * Check current countdown timer mode
694 * ::PROP
695 *
696 * @return bool
697 */
698 public function is_evergreen()
699 {
700 return $this->get_prop( 'mode' ) == C::MODE_EVERGREEN;
701 }
702
703 public function is_one_time()
704 {
705 return $this->get_prop( 'mode' ) == C::MODE_REGULAR;
706 }
707
708 public function is_recurring()
709 {
710 return $this->get_prop( 'mode' ) == C::MODE_RECURRING;
711
712 }
713
714 /**
715 * Save compaign endtime for regular mode.
716 *
717 * @param $date
718 */
719 public function setEndDatetime( $date )
720 {
721 $this->set_prop( 'end_datetime', $date ?: $this->defaultEndDatetime() );
722 }
723
724 /**
725 * Returns default end datetime for regular mode.
726 * ::PROP
727 *
728 * @return false|string
729 */
730 private function defaultEndDatetime()
731 {
732 return date( 'Y-m-d h:i A', strtotime( '+1 week' ) );
733 }
734
735 /**
736 * Save digit color.
737 * ::PROP
738 *
739 * @param $color
740 */
741 public function setDigitColor( $color )
742 {
743 $this->set_prop( 'digit_color', $color );
744 }
745
746 /**
747 * Returns headline visibility.
748 * ::PROP
749 *
750 * @return mixed
751 */
752
753 public function getHeadlineVisibility()
754 {
755 $meta = 'headline_visibility';
756
757 $value = $this->get_prop( $meta, false );
758 if ( $value === C::NO || $value === C::YES ) {
759 return $value;
760 }
761
762 $legacyMeta = 'display_headline';
763 $legacyValue = filter_var( $this->get_prop_legacy( $legacyMeta ),
764 FILTER_VALIDATE_BOOLEAN );
765 $legacyValue = $legacyValue ? C::YES : C::NO;
766
767 $this->set_prop( $meta, $legacyValue );
768
769 $this->delete_prop( $legacyMeta );
770
771 return $this->get_prop( $meta );
772 }
773
774 /**
775 * Returns digit color.
776 * Backward compat with older versions.
777 * ::PROP
778 *
779 * @return mixed
780 */
781 public function getDigitColor()
782 {
783 $value = $this->get_prop( 'digit_color', false );
784 if ( $value ) {
785 return $value;
786 }
787
788 $legacy = $this->get_prop_legacy( 'text_color' );
789 if ( !$legacy ) {
790 return $this->digitColor;
791 }
792
793 $this->setDigitColor( $legacy );
794 if ( !$this->get_prop( 'label_color', false ) ) {
795 $this->setLabelColor( $legacy );
796 }
797
798 $this->delete_prop( 'text_color' );
799
800 return $this->get_prop( 'digit_color' );
801 }
802
803 /**
804 * ::PROP
805 *
806 * @param $color
807 */
808 public function setLabelColor( $color )
809 {
810 $this->set_prop( 'label_color', $color );
811 }
812
813 /**
814 * Get label color
815 * ::PROP
816 *
817 * @return mixed
818 */
819 public function getLabelColor()
820 {
821 $value = $this->get_prop( 'label_color', false );
822 if ( $value ) {
823 return $value;
824 }
825
826 $legacy = $this->get_prop_legacy( 'text_color' );
827 if ( !$legacy ) {
828 return $this->labelColor;
829 }
830
831 $this->setLabelColor( $legacy );
832 if ( !$this->get_prop( 'digit_color', false ) ) {
833 $this->setDigitColor( $legacy );
834 }
835
836 $this->delete_prop( 'text_color' );
837
838 return $this->get_prop( 'label_color' );
839
840 }
841
842 /**
843 *
844 * Return timer digit size.
845 * Backward comapt. with older versions.
846 * ::PROP
847 *
848 * @return int
849 * @since 1.2.4
850 */
851 public function getDigitSize()
852 {
853 $meta = 'digit_size';
854 $value = $this->get_prop( $meta, false );
855 if ( !empty( $value ) ) {
856 return $value;
857 }
858 $legacy = $this->get_prop_legacy( 'text_size' );
859
860 if ( empty( $legacy ) ) {
861 return $this->digitSize;
862 }
863
864 $this->setDigitSize( $legacy );
865
866 $this->delete_prop( 'text_size' );
867
868 return $this->get_prop( 'digit_size' );
869 }
870
871 /**
872 * Save timer digit size.
873 * ::PROP
874 *
875 * @param $size
876 */
877 public function setDigitSize( $size )
878 {
879 $this->set_prop( 'digit_size', $size );
880 }
881
882 /**
883 * Save timer label size.
884 * ::PROP
885 *
886 * @param $size
887 */
888 public function setLabelSize( $size )
889 {
890 $this->set_prop( 'label_size', $size );
891 }
892
893 /**
894 * ::PROP
895 *
896 * @param $size
897 */
898 public function setHeadlineSize( $size )
899 {
900 $this->set_prop( 'headline_size', $size );
901 }
902
903 /**
904 * Returns evergreen duration.
905 * ::PROP
906 *
907 * @return array
908 */
909 public function getDuration()
910 {
911 $default = [ 0, 0, 0, 0 ];
912 $duration = $this->get_prop( 'duration' );
913 if ( is_array( $duration ) ) {
914 $duration = array_merge( $duration, $default );
915
916 return array_map( 'intval', $duration );
917 }
918
919 return $default;
920 }
921
922 /**
923 * ::PROP
924 *
925 * @param $value
926 */
927 public function setRecurringDuration( $value )
928 {
929 $this->set_prop( '_hurryt_recurring_duration', $value );
930 }
931
932
933 /**
934 * Returns evergreen duration.
935 *
936 * @return array
937 */
938 public function getRecurringDuration()
939 {
940 $default = [ 0, 0, 0, 0 ];
941 $duration = $this->get_prop( '_hurryt_recurring_duration', false );
942 if ( is_array( $duration ) ) {
943 return array_map( 'intval', array_merge( $duration, $default ) );
944 }
945
946 return $default;
947 }
948
949 /**
950 * Returns actions array.
951 *
952 * @return array
953 */
954 public function getActions()
955 {
956 $legacy = $this->get_prop_legacy( 'end_action' );
957 if ( $legacy ) {
958 $redirectUrl = $this->get_prop_legacy( 'redirect_url' );
959 $actions = [
960 [
961 'id' => intval( $legacy ),
962 'redirectUrl' => $redirectUrl,
963 ],
964 ];
965 $this->set_prop( 'actions', $actions );
966 $this->delete_prop( 'end_action' );
967 $this->delete_prop( 'redirect_url' );
968
969 return $this->mergeActions( $actions );
970 }
971
972 return $this->mergeActions( $this->get_prop( 'actions' ) );
973 }
974
975 private function mergeActions( $actions )
976 {
977 $defaults = [
978 [
979 'id' => C::ACTION_NONE,
980 'redirectUrl' => '',
981 'message' => '',
982 'wcStockStatus' => '',
983 ],
984 ];
985
986 if ( count( $actions ) === 0 ) {
987 return $defaults;
988 }
989
990 return array_map( function ( $action ) use ( $defaults ) {
991 $action[ 'id' ] = (int)$action[ 'id' ];
992
993 return array_merge( $defaults[ 0 ], $action );
994 }, $actions );
995 }
996
997 /**
998 * Returns evergreen duration in seconds.
999 *
1000 * @param array $duration
1001 *
1002 * @return int
1003 */
1004 public function duration_to_sec( $duration = [] )
1005 {
1006 list( $d, $h, $m, $s ) = empty( $duration ) ? $this->getDuration() : $duration;
1007
1008 return $d * DAY_IN_SECONDS +
1009 $h * HOUR_IN_SECONDS +
1010 $m * MINUTE_IN_SECONDS +
1011 $s;
1012 }
1013
1014 /**
1015 * Returns end datetime.
1016 *
1017 * @return string
1018 */
1019 public function getEndDatetime()
1020 {
1021 return $this->get_prop( 'end_datetime' ) ?: $this->defaultEndDatetime();
1022 }
1023
1024 /**
1025 * Return true if the recurrence is expired.
1026 *
1027 * @return bool
1028 */
1029 public function is_recurring_expired()
1030 {
1031 $deadline = $this->get_current_recurrence_end_date();
1032 if ( !( $deadline instanceof Carbon ) ) {
1033 return false;
1034 }
1035
1036 $now = Carbon::now( hurryt_tz() );
1037
1038 return $now->isAfter( $deadline );
1039 }
1040
1041 /**
1042 * Calculate next recurrence.
1043 *
1044 * @return mixed
1045 */
1046 function get_time_to_next_recurrence()
1047 {
1048 $this->loadSettings();
1049 $interval = absint( $this->recurringInterval );
1050
1051 if ( $this->recurringFrequency === C::RECURRING_DAILY ) {
1052 $frequencyInSeconds = DAY_IN_SECONDS;
1053 } elseif ( $this->recurringFrequency === C::RECURRING_WEEKLY ) {
1054 $frequencyInSeconds = WEEK_IN_SECONDS;
1055
1056 } elseif ( $this->recurringFrequency === C::RECURRING_HOURLY ) {
1057 $frequencyInSeconds = HOUR_IN_SECONDS;
1058
1059 } else {
1060 $frequencyInSeconds = MINUTE_IN_SECONDS;
1061 }
1062
1063 $duration = $this->duration_to_sec( $this->getRecurringDuration() );
1064
1065 return max( 0, ( $frequencyInSeconds * $interval ) - $duration );
1066 }
1067
1068 /**
1069 * Return true if the current campaign can recur today.
1070 *
1071 * @return bool
1072 */
1073 public function can_recur_today()
1074 {
1075 $this->loadSettings();
1076 $day = absint( Carbon::now( hurryt_tz() )->format( 'w' ) );
1077 $recur = in_array( $day, array_map( 'absint', $this->recurringDays ) );
1078
1079 return apply_filters( 'hurryt_recur_today', $recur, $this->get_id() );
1080 }
1081
1082 /**
1083 * Return current recurrence date
1084 *
1085 * @return \Carbon\CarbonInterface|null
1086 * @throws \Exception
1087 */
1088 public function get_current_recurrence_start_date()
1089 {
1090 try {
1091 $this->loadSettings();
1092 $dtStart = Carbon::parse( $this->recurringStartTime, hurryt_tz() );
1093 $now = Carbon::now( hurryt_tz() );
1094
1095 $range = CarbonPeriod::since( $dtStart );
1096 $interval = absint( $this->recurringInterval );
1097
1098 if ( $this->recurringFrequency === C::RECURRING_DAILY ) {
1099 $range->days( $interval );
1100 } elseif ( $this->recurringFrequency === C::RECURRING_WEEKLY ) {
1101 $range->weeks( $interval );
1102 } elseif ( $this->recurringFrequency === C::RECURRING_HOURLY ) {
1103 $range->hours( $interval );
1104 } else {
1105 $range->minutes( $interval );
1106 }
1107
1108 // Recurs forever
1109 if ( absint( $this->recurringEnd ) === C::RECURRING_END_NEVER ) {
1110 $range->until( $now );
1111 // Recurs until
1112 } elseif ( absint( $this->recurringEnd ) === C::RECURRING_END_TIME ) {
1113 $range->until( Carbon::parse( $this->recurringUntil, hurryt_tz() ) );
1114
1115 $range->addFilter( function ( $date ) use ( $now ) {
1116 /**
1117 * @var Carbon $date
1118 */
1119 return $date->isBefore( $now );
1120 } );
1121
1122 // Recurs N times.
1123 } elseif ( absint( $this->recurringEnd ) === C::RECURRING_END_OCCURRENCES ) {
1124
1125 // Virtual endDate
1126 $range->until( Carbon::now( hurryt_tz() )->addCenturies( 1 ) );
1127
1128 // Limit to the number of occurences in `$this->recurringCount`
1129 $range->setRecurrences( absint( $this->recurringCount ) );
1130
1131 // Set the endDate to the last occurence date
1132 $range->setEndDate( $range->last() );
1133 $range->addFilter( function ( $date ) use ( $now ) {
1134
1135 /**
1136 * @var Carbon $date
1137 */
1138 return $date->isBefore( $now );
1139 } );
1140
1141 }
1142
1143 return $range->last();
1144
1145 } catch ( \Exception $e ) {
1146 return null;
1147 }
1148 }
1149
1150 /**
1151 * Get the next/current deadline based on the current date.
1152 *
1153 * @return null|Carbon
1154 */
1155 public function get_current_recurrence_end_date()
1156 {
1157 $date = $this->get_current_recurrence_start_date();
1158 if ( !$date ) {
1159 return null;
1160 }
1161 $date = clone Carbon::instance( $date );
1162
1163 $duration = $this->duration_to_sec( $this->getRecurringDuration() );
1164
1165 $date->addSeconds( $duration );
1166
1167 return $date;
1168 }
1169
1170 /**
1171 * Returns compaign publish datetime.
1172 *
1173 * @return mixed
1174 */
1175 public function getStartTimestamp()
1176 {
1177 return get_the_date( $this->id );
1178 }
1179
1180 /**
1181 * Returns position in WooCommerce product page.
1182 * ::PROP
1183 *
1184 * @return mixed
1185 */
1186 public function getWcPosition()
1187 {
1188 $legacy = $this->get_prop_legacy( 'position' );
1189
1190 if ( !$legacy ) {
1191 return $this->get_prop( 'wc_position' );
1192 }
1193 $this->set_prop( 'wc_position', $legacy );
1194 $this->delete_prop( 'position' );
1195
1196 return $legacy;
1197 }
1198
1199 private function get_prop_legacy( $name )
1200 {
1201 return get_post_meta( $this->id, $name, true );
1202 }
1203
1204 /**
1205 * Returns true if WooCommerce integration is enabled.
1206 * ::PROP
1207 *
1208 * @return mixed
1209 */
1210 public function getWcEnable()
1211 {
1212 $value = $this->get_prop( 'wc_enable', false );
1213
1214 if ( $value === C::YES || $value === C::NO ) {
1215 return $value;
1216 }
1217
1218 $legacy = filter_var( $value, FILTER_VALIDATE_BOOLEAN );
1219 if ( $legacy ) {
1220 $this->set_prop( 'wc_enable', C::YES );
1221 } else {
1222 $this->set_prop( 'wc_enable', C::NO );
1223 }
1224
1225 return $this->get_prop( 'wc_enable' );
1226 }
1227
1228 /**
1229 * Returns true if label should be displayed.
1230 *
1231 * @return mixed
1232 */
1233 public function getLabelVisibility()
1234 {
1235 $meta = 'label_visibility';
1236 $value = $this->get_prop( $meta, false );
1237 if ( $value === C::NO || $value === C::YES ) {
1238 return $value;
1239 }
1240
1241 $legacy = filter_var( $this->get_prop_legacy( 'display_labels' ),
1242 FILTER_VALIDATE_BOOLEAN );
1243 $legacy = $legacy ? C::YES : C::NO;
1244
1245 $this->set_prop( $meta, $legacy );
1246
1247 $this->delete_prop( 'display_labels' );
1248
1249 return $this->get_prop( $meta );
1250
1251 }
1252
1253 /**
1254 *
1255 * Returns restart type.
1256 *
1257 * @return int
1258 */
1259 public function getRestart()
1260 {
1261 return $this->get_prop( 'restart' ) ?: C::RESTART_NONE;
1262 }
1263
1264 /**
1265 * Returns WooCommerce products selection type.
1266 *
1267 * @return string
1268 */
1269 public function getWcProductsSelectionType()
1270 {
1271 $legacy = $this->get_prop_legacy( 'products_type' );
1272 if ( !$legacy ) {
1273 return $this->get_prop( 'wc_products_selection_type' );
1274 }
1275 $this->set_prop( 'wc_products_selection_type', $legacy );
1276 $this->delete_prop( 'products_type' );
1277
1278 return $legacy;
1279 }
1280
1281 /**
1282 * Delete setting item.
1283 *
1284 * @param $name
1285 */
1286 public function delete_prop( $name )
1287 {
1288 delete_post_meta( $this->id, $name );
1289 }
1290
1291 /**
1292 * Returns products selection IDs.
1293 * ::PROP
1294 *
1295 * @return array
1296 */
1297 public function getWcProductsSelection()
1298 {
1299 $legacy = $this->get_prop_legacy( 'products' );
1300 if ( !$legacy ) {
1301 return $this->get_prop( 'wc_products_selection' );
1302 }
1303 $this->set_prop( 'wc_products_selection', $legacy );
1304 $this->delete_prop( 'products' );
1305
1306 return $legacy;
1307 }
1308
1309 /**
1310 * Store custom labels.
1311 * ::PROP
1312 *
1313 * @param $labels
1314 */
1315 public function setLabels( $labels )
1316 {
1317 $labels = array_merge( $this->labels, array_filter( $labels ) );
1318 update_post_meta( $this->id, 'labels', $labels );
1319 }
1320
1321 /**
1322 * Returns true if compaign can be published.
1323 *
1324 * @return bool
1325 */
1326 public function is_active()
1327 {
1328 return get_post_status( $this->id ) === "publish"
1329 || get_post_status( $this->id ) === "future";
1330
1331 }
1332
1333 /**
1334 * Returns trus if the compaign is scheduled.
1335 *
1336 * @return bool
1337 */
1338 public function is_scheduled()
1339 {
1340 $scheduled = get_post_status( $this->get_id() ) === "future";
1341 if ( $scheduled ) {
1342 return true;
1343 }
1344
1345 if ( $this->is_recurring() ) {
1346 $start_date = Carbon::parse( $this->recurringStartTime, hurryt_tz() );
1347 $now = Carbon::now( hurryt_tz() );
1348 if ( $now->isBefore( $start_date ) ) {
1349 return true;
1350 }
1351 }
1352
1353 return $scheduled;
1354 }
1355
1356 /**
1357 * Returns true if fixed campaign datetime is expired.
1358 *
1359 * @param string|null $date
1360 *
1361 * @return bool
1362 */
1363 public function is_one_time_expired( $date = null )
1364 {
1365 $endDate = $date === null ? date_create( $this->endDatetime ) : $date;
1366 $today = date_create( current_time( "mysql" ) );
1367
1368 return $endDate < $today;
1369 }
1370
1371 public function is_sticky_dismissed()
1372 {
1373 return isset( $_COOKIE[ CookieDetection::COOKIE_PREFIX . $this->get_id() . '_dismissed' ] )
1374 && $this->stickyBarDismissible === C::YES
1375 && $this->enableSticky === C::YES;
1376 }
1377
1378 /**
1379 * Returns compaign template wrapper.
1380 *
1381 * @param string
1382 *
1383 * @return string
1384 */
1385 public function wrap_template( $content )
1386 {
1387 $campaignBuilder = new CampaignBuilder( $this );
1388
1389 return $campaignBuilder->build( $content );
1390 }
1391
1392 /*
1393 * Returns campaign template content.
1394 */
1395 public function build_template()
1396 {
1397 $campaignBuilder = new CampaignBuilder( $this );
1398
1399 return $campaignBuilder->template();
1400 }
1401
1402 /**
1403 * ::PROP
1404 *
1405 * @param $value
1406 */
1407 public function setWcConditions( $value )
1408 {
1409 $this->set_prop( '_hurryt_wc_conditions', !empty( $value ) ? $value : [] );
1410 }
1411
1412 /**
1413 * ::PROP
1414 *
1415 * @return mixed
1416 */
1417 public function getWcConditions()
1418 {
1419 return $this->get_prop( '_hurryt_wc_conditions', false );
1420 }
1421
1422
1423 public function is_running()
1424 {
1425 $no = !$this->is_active()
1426 || $this->is_scheduled()
1427 || !$this->show_sticky_on_page( hurryt_current_page_id() )
1428 || $this->is_sticky_dismissed()
1429 || ( $this->is_recurring() && !$this->can_recur_today() )
1430 || ( $this->is_recurring() && $this->get_current_recurrence_end_date() === null );
1431
1432 return !$no;
1433 }
1434
1435 /**
1436 * Check if recurring or onetime campaign is expired.
1437 *
1438 * @return bool
1439 */
1440 public function is_expired()
1441 {
1442 return ( $this->is_one_time() && $this->is_one_time_expired() )
1443 || ( $this->is_recurring() && $this->is_recurring_expired() );
1444 }
1445 }
1446