PluginProbe
WowOptin: Next-Gen Popup Maker – Create Stunning Popups and Optins for Lead Generation / trunk
WowOptin: Next-Gen Popup Maker – Create Stunning Popups and Optins for Lead Generation vtrunk
1.4.48 1.4.47 1.4.46 1.4.45 1.4.44 1.4.43 1.4.42 1.4.41 1.4.40 1.4.39 1.4.38 1.4.37 1.4.36 1.1.2 1.2.0 1.2.1 1.2.2 1.3.0 1.3.1 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 1.4.13 All 64 releases
optin / includes / notice / templates / split-countdown.php

split-countdown.php in WowOptin: Next-Gen Popup Maker – Create Stunning Popups and Optins for Lead Generation trunk, at includes/notice/templates/split-countdown.php

245 lines 7.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * LAYOUT: art on the left and right flanks, live text + countdown centered,
4 * over a background image. The only design with a timer.
5 *
6 * Self-contained: markup, CSS and JS in this one file, every class and storage
7 * key built from $prefix so a sibling plugin can copy it as-is.
8 *
9 * @var array $notice Promo entry (brand_color, bg_image, left_image,
10 * right_image, text, countdown_color, countdown_duration, url).
11 * @var array $query_args Dismiss-link query args.
12 * @var string $prefix Identity slug from config.php.
13 * @var string $brand_color Accent color from config.php.
14 */
15
16 defined( 'ABSPATH' ) || exit;
17
18 $wrapper_class = $prefix . '-notice-wrapper';
19 $banner_class = $prefix . '-banner-notice';
20 $link_class = $prefix . '-banner-link';
21 $content_class = $prefix . '-banner-content';
22 $side_img_class = $prefix . '-banner-side-image';
23 $main_class = $prefix . '-banner-main';
24 $main_text_class = $prefix . '-banner-main-text';
25 $countdown_class = $prefix . '-notice-countdown';
26 $close_class = $prefix . '-banner-notice-close';
27 $scope = '.' . $wrapper_class . '.' . $banner_class;
28 ?>
29 <style type="text/css">
30 <?php echo esc_html( $scope ); ?> {
31 height: auto !important;
32 padding: 0 !important;
33 position: relative;
34 box-sizing: border-box;
35 background-repeat: no-repeat;
36 background-size: cover;
37 background-position: center;
38 }
39 <?php echo esc_html( $scope ); ?> .<?php echo esc_html( $link_class ); ?> {
40 width: 100%;
41 text-decoration: none;
42 display: block;
43 }
44 <?php echo esc_html( $scope ); ?> .<?php echo esc_html( $content_class ); ?> {
45 display: flex;
46 justify-content: space-between;
47 align-items: center;
48 max-width: 700px;
49 margin: 0 auto;
50 padding: 10px 16px;
51 gap: 16px;
52 }
53 <?php echo esc_html( $scope ); ?> .<?php echo esc_html( $side_img_class ); ?> {
54 display: block;
55 max-width: 100%;
56 height: auto;
57 max-height: 48px;
58 }
59 <?php echo esc_html( $scope ); ?> .<?php echo esc_html( $main_class ); ?> {
60 display: flex;
61 flex-direction: column;
62 gap: 4px;
63 align-items: center;
64 justify-content: center;
65 font-weight: 700;
66 font-size: 18px;
67 color: <?php echo esc_attr( $brand_color ); ?>;
68 line-height: 1.2;
69 text-align: center;
70 }
71
72 @media screen and (max-width: 1100px) {
73 <?php echo esc_html( $scope ); ?> .<?php echo esc_html( $content_class ); ?> .<?php echo esc_html( $main_text_class ); ?> {
74 display: none;
75 }
76 }
77
78 @media screen and (max-width: 490px) {
79 <?php echo esc_html( $scope ); ?> {
80 display: none;
81 }
82 }
83
84 @media screen and (max-width: 782px) {
85 <?php echo esc_html( $scope ); ?> .<?php echo esc_html( $content_class ); ?> {
86 justify-content: center;
87 padding: 12px 32px 12px 12px;
88 }
89 <?php echo esc_html( $scope ); ?> .<?php echo esc_html( $main_class ); ?> {
90 font-size: 22px;
91 line-height: 28px;
92 }
93 }
94 @media screen and (max-width: 480px) {
95 <?php echo esc_html( $scope ); ?> .<?php echo esc_html( $content_class ); ?> {
96 padding: 10px 32px 10px 10px;
97 }
98 <?php echo esc_html( $scope ); ?> .<?php echo esc_html( $main_class ); ?> {
99 font-size: 18px;
100 line-height: 24px;
101 }
102 }
103 </style>
104 <div
105 class="<?php echo esc_attr( $wrapper_class . ' ' . $banner_class . ' notice' ); ?>"
106 style="
107 border-left: 3px solid <?php echo esc_attr( $notice['brand_color'] ); ?>;
108 background-image: url('<?php echo esc_attr( $notice['bg_image'] ); ?>');
109 ">
110 <a
111 class="<?php echo esc_attr( $close_class ); ?> dashicons dashicons-no-alt"
112 style="
113 position: absolute;
114 top: 1px;
115 right: 1px;
116 border-radius: 50%;
117 background-color: black;
118 color: white;
119 font-size: 14px;
120 display: flex;
121 align-items: center;
122 justify-content: center;
123 "
124 aria-label="<?php esc_html_e( 'Close Banner', 'optin' ); ?>"
125 href="<?php echo esc_url( add_query_arg( $query_args ) ); ?>">
126 </a>
127
128 <a class="<?php echo esc_attr( $link_class ); ?>" target="_blank" href="<?php echo esc_url( $notice['url'] ); ?>">
129 <div class="<?php echo esc_attr( $content_class ); ?>">
130 <img class="<?php echo esc_attr( $side_img_class ); ?>" loading="lazy" src="<?php echo esc_url( $notice['left_image'] ); ?>" />
131 <div class="<?php echo esc_attr( $main_class ); ?>">
132 <span>
133 <?php echo esc_html( $notice['text'] ); ?>
134 </span>
135 <div
136 class="<?php echo esc_attr( $countdown_class ); ?>"
137 style="
138 color: <?php echo esc_attr( $notice['countdown_color'] ); ?>;
139 "
140 data-notice-key="<?php echo esc_attr( $notice['key'] . '-countdown' ); ?>"
141 data-duration="<?php echo esc_attr( $notice['countdown_duration'] ); ?>">
142 00:00:00:00
143 </div>
144 </div>
145 <img class="<?php echo esc_attr( $side_img_class ); ?>" loading="lazy" src="<?php echo esc_url( $notice['right_image'] ); ?>" />
146 </div>
147 </a>
148 </div>
149 <script type="text/javascript">
150 jQuery(function($) {
151 'use strict';
152
153 const storagePrefix = '<?php echo esc_js( $prefix ); ?>_notice_countdown_';
154 const countdownSelector = '.<?php echo esc_js( $countdown_class ); ?>';
155
156 const formatCountdown = function(seconds) {
157 const days = Math.floor(seconds / 86400);
158 const hours = Math.floor((seconds % 86400) / 3600);
159 const minutes = Math.floor((seconds % 3600) / 60);
160 const secs = seconds % 60;
161
162 return String(days).padStart(2, '0') + ':' + String(hours).padStart(2, '0') + ':' + String(minutes).padStart(2, '0') + ':' + String(secs).padStart(2, '0');
163 };
164
165 const parseDurationToSeconds = function(duration) {
166 if (typeof duration === 'number' && Number.isFinite(duration) && duration > 0) {
167 return Math.floor(duration);
168 }
169
170 const durationString = String(duration || '').trim();
171 if (/^\d+$/.test(durationString)) {
172 return parseInt(durationString, 10);
173 }
174
175 return 0;
176 };
177
178 const nowInSeconds = function() {
179 return Math.floor(Date.now() / 1000);
180 };
181
182 $(countdownSelector).each(function() {
183 const countdownElement = $(this);
184 const noticeKey = String(countdownElement.data('noticeKey') || '');
185 const duration = parseDurationToSeconds(countdownElement.data('duration'));
186
187 if (!noticeKey || duration <= 0) {
188 return;
189 }
190
191 const storageKey = storagePrefix + noticeKey;
192 let endAt = 0;
193
194 try {
195 const storedDataRaw = window.localStorage.getItem(storageKey);
196 if (storedDataRaw) {
197 const storedData = JSON.parse(storedDataRaw);
198 if (storedData && parseInt(storedData.duration, 10) === duration) {
199 endAt = parseInt(storedData.endAt, 10) || 0;
200 }
201 }
202 } catch (error) {
203 endAt = 0;
204 }
205
206 const saveTimerState = function(nextEndAt) {
207 try {
208 window.localStorage.setItem(
209 storageKey,
210 JSON.stringify({
211 endAt: nextEndAt,
212 duration: duration,
213 })
214 );
215 } catch (error) {
216 // No-op.
217 }
218 };
219
220 const resetTimer = function(currentTime) {
221 endAt = currentTime + duration;
222 saveTimerState(endAt);
223 };
224
225 const tick = function() {
226 const currentTime = nowInSeconds();
227
228 if (endAt <= currentTime) {
229 resetTimer(currentTime);
230 }
231
232 const remaining = Math.max(endAt - currentTime, 0);
233 countdownElement.text(formatCountdown(remaining));
234 };
235
236 if (endAt <= nowInSeconds()) {
237 resetTimer(nowInSeconds());
238 }
239
240 tick();
241 window.setInterval(tick, 1000);
242 });
243 });
244 </script>
245