PluginProbe
Gutenify – Visual Site Builder Blocks & Starter Templates / trunk
Gutenify – Visual Site Builder Blocks & Starter Templates vtrunk
1.7.0 1.6.6 1.6.5 1.6.4 trunk 0.0.1 0.0.2 0.0.3 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 All 72 releases
gutenify / core / dist / blocks / countdown-timer / index.php

index.php in Gutenify – Visual Site Builder Blocks & Starter Templates trunk, at core/dist/blocks/countdown-timer/index.php

352 lines 11.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: Gutenify Countdown Block
4 * Plugin URI: https://gutenify.com
5 * Description: Gutenify Countdown - stores settings in post meta
6 * Version: 1.0.0
7 * Author: Gutenify
8 *
9 * @package gutenify
10 */
11
12 defined( 'ABSPATH' ) || exit;
13
14 /**
15 * Register post meta for countdown timer settings.
16 */
17 function gutenify_countdown_timer_register_meta() {
18 $meta_fields = array(
19 '_gutenify_countdown_timer_type' => array(
20 'type' => 'string',
21 'default' => 'fixed',
22 ),
23 '_gutenify_countdown_timer_evergreen_hours' => array(
24 'type' => 'integer',
25 'default' => 24,
26 ),
27 '_gutenify_countdown_timer_evergreen_minutes' => array(
28 'type' => 'integer',
29 'default' => 0,
30 ),
31 '_gutenify_countdown_timer_date' => array(
32 'type' => 'string',
33 'default' => '',
34 ),
35 '_gutenify_countdown_timer_timezone' => array(
36 'type' => 'string',
37 'default' => 'US/Eastern',
38 ),
39 '_gutenify_countdown_timer_end_action' => array(
40 'type' => 'string',
41 'default' => 'none',
42 ),
43 '_gutenify_countdown_timer_hide_selector' => array(
44 'type' => 'string',
45 'default' => '',
46 ),
47 '_gutenify_countdown_timer_redirect_url' => array(
48 'type' => 'string',
49 'default' => '',
50 ),
51 );
52
53 foreach ( $meta_fields as $meta_key => $args ) {
54 register_post_meta(
55 '',
56 $meta_key,
57 array(
58 'show_in_rest' => true,
59 'single' => true,
60 'type' => $args['type'],
61 'default' => $args['default'],
62 'auth_callback' => function () {
63 return current_user_can( 'edit_posts' );
64 },
65 )
66 );
67 }
68 }
69 add_action( 'init', 'gutenify_countdown_timer_register_meta' );
70
71 /**
72 * Register site-wide settings for countdown timer.
73 */
74 function gutenify_countdown_timer_register_settings() {
75 register_setting(
76 'options',
77 '_gutenify_countdown_timer_site_data',
78 array(
79 'type' => 'object',
80 'show_in_rest' => array(
81 'schema' => array(
82 'type' => 'object',
83 'properties' => array(
84 'countdownTimerType' => array( 'type' => 'string' ),
85 'evergreenHours' => array( 'type' => 'integer' ),
86 'evergreenMinutes' => array( 'type' => 'integer' ),
87 'date' => array( 'type' => 'string' ),
88 'timezone' => array( 'type' => 'string' ),
89 'endAction' => array( 'type' => 'string' ),
90 'hideSelector' => array( 'type' => 'string' ),
91 'redirectUrl' => array( 'type' => 'string' ),
92 'evergreenRestart' => array( 'type' => 'boolean' ),
93 ),
94 ),
95 ),
96 'default' => array(
97 'countdownTimerType' => 'fixed',
98 'evergreenHours' => 24,
99 'evergreenMinutes' => 0,
100 'evergreenRestart' => false,
101 'date' => '',
102 'timezone' => 'US/Eastern',
103 'endAction' => 'none',
104 'hideSelector' => '',
105 'redirectUrl' => '',
106 ),
107 )
108 );
109 }
110 add_action( 'init', 'gutenify_countdown_timer_register_settings' );
111
112 /**
113 * Registers the block.
114 */
115 function gutenify_countdown_timer_register_block() {
116 register_block_type(
117 __DIR__,
118 array(
119 'render_callback' => 'gutenify_countdown_timer_render',
120 )
121 );
122 }
123 add_action( 'init', 'gutenify_countdown_timer_register_block' );
124
125 /**
126 * Converts a font size value to a fluid clamp() value.
127 * Min = 75% of value, viewport range 320px–1920px.
128 */
129 function gutenify_get_fluid_font_size( $font_size ) {
130 if ( empty( $font_size ) ) {
131 return $font_size;
132 }
133
134 if ( ! preg_match( '/^([\d.]+)(.+)$/', $font_size, $matches ) ) {
135 return $font_size;
136 }
137
138 $value = (float) $matches[1];
139 $unit = $matches[2];
140
141 $value_px = $value;
142 if ( 'rem' === $unit || 'em' === $unit ) {
143 $value_px = $value * 16;
144 }
145
146 $min_px = $value_px * 0.75;
147 $min_viewport = 320;
148 $max_viewport = 1920;
149 $slope = ( $value_px - $min_px ) / ( $max_viewport - $min_viewport );
150 $intercept = $min_px - $slope * $min_viewport;
151 $slope_vw = round( $slope * 100, 4 );
152 $intercept_rem = round( $intercept / 16, 4 );
153
154 $min = 'px' === $unit
155 ? $min_px . 'px'
156 : round( $value * 0.75, 4 ) . $unit;
157
158 return "clamp({$min}, {$intercept_rem}rem + {$slope_vw}vw, {$font_size})";
159 }
160
161 /**
162 * Render callback for the block - outputs HTML with post meta as data attributes.
163 *
164 * @param array $attributes Block attributes.
165 * @param string $content Block content.
166 * @param WP_Block $block Block instance.
167 * @return string Rendered block HTML.
168 */
169 function gutenify_countdown_timer_render( $attributes, $content, $block ) {
170 $post_id = $block->context['postId'] ?? get_the_ID();
171
172 if ( ! $post_id ) {
173 return $content;
174 }
175
176 $storage_level = $attributes['storageLevel'] ?? 'postMeta';
177
178 $type = $attributes['countdownTimerType'] ?? 'fixed';
179
180 if ( 'blockLevel' === $storage_level ) {
181 $evg_hours = (int) ( $attributes['evergreenHours'] ?? 24 );
182 $evg_minutes = (int) ( $attributes['evergreenMinutes'] ?? 0 );
183 $date = $attributes['date'] ?? '';
184 $timezone = wp_timezone_string();
185 $end_action = $attributes['endAction'] ?? 'none';
186 $hide_selector = $attributes['hideSelector'] ?? '';
187 $redirect_url = $attributes['redirectUrl'] ?? '';
188 } elseif ( 'siteLevel' === $storage_level ) {
189 $site_data = get_option( '_gutenify_countdown_timer_site_data', array() );
190 $evg_hours = (int) ( $site_data['evergreenHours'] ?? 24 );
191 $evg_minutes = (int) ( $site_data['evergreenMinutes'] ?? 0 );
192 $date = $site_data['date'] ?? '';
193 $timezone = wp_timezone_string();
194 $end_action = $site_data['endAction'] ?? 'none';
195 $hide_selector = $site_data['hideSelector'] ?? '';
196 $redirect_url = $site_data['redirectUrl'] ?? '';
197 } else {
198 $evg_hours = get_post_meta( $post_id, '_gutenify_countdown_timer_evergreen_hours', true );
199 $evg_hours = $evg_hours !== '' ? (int) $evg_hours : 24;
200 $evg_minutes = get_post_meta( $post_id, '_gutenify_countdown_timer_evergreen_minutes', true );
201 $evg_minutes = $evg_minutes !== '' ? (int) $evg_minutes : 0;
202 $date = get_post_meta( $post_id, '_gutenify_countdown_timer_date', true );
203 $timezone = wp_timezone_string();
204 $end_action = get_post_meta( $post_id, '_gutenify_countdown_timer_end_action', true );
205 $hide_selector = get_post_meta( $post_id, '_gutenify_countdown_timer_hide_selector', true );
206 $redirect_url = get_post_meta( $post_id, '_gutenify_countdown_timer_redirect_url', true );
207 $evg_restart = get_post_meta( $post_id, '_gutenify_countdown_timer_evergreen_restart', true );
208 }
209
210 $evg_restart = 'siteLevel' === $storage_level ? ( $site_data['evergreenRestart'] ?? false ) : ( 'blockLevel' === $storage_level ? ( $attributes['evergreenRestart'] ?? false ) : $evg_restart );
211 $evg_restart = filter_var( $evg_restart, FILTER_VALIDATE_BOOLEAN );
212
213 if ( empty( $hide_selector ) && 'hide' === $end_action ) {
214 $hide_selector = '.gutenify-countdown-timer-hide';
215 }
216
217 if ( 'fixed' === $type && empty( $date ) ) {
218 return $content;
219 }
220
221 // Default to US/Eastern if no timezone is set.
222 if ( empty( $timezone ) ) {
223 $timezone = 'US/Eastern';
224 }
225
226 $timestamp = 0;
227
228 if ( 'evergreen' === $type ) {
229 // Calculate the full duration relative to now so the initial server render
230 // shows the maximum time before the frontend JS kicks in.
231 $timestamp = current_time( 'timestamp', true ) + ( $evg_hours * 3600 ) + ( $evg_minutes * 60 );
232 } else {
233 try {
234 // Create the DateTime object without timezone first to parse the stored date.
235 $dt = new DateTime( $date );
236
237 // Re-interpret the date in the selected timezone
238 // (strip any offset from the stored date and apply the selected timezone).
239 $tz = new DateTimeZone( $timezone );
240 $dt = new DateTime( $dt->format( 'Y-m-d H:i:s' ), $tz );
241
242 $timestamp = $dt->getTimestamp();
243 } catch ( Exception $e ) {
244 return $content;
245 }
246 }
247
248 // Compute initial countdown values server-side to avoid flash of empty content.
249 $remaining = $timestamp - current_time( 'timestamp', true );
250 if ( $remaining > 0 ) {
251 $init_days = str_pad( floor( $remaining / 86400 ), 2, '0', STR_PAD_LEFT );
252 $init_hours = str_pad( floor( ( $remaining % 86400 ) / 3600 ), 2, '0', STR_PAD_LEFT );
253 $init_minutes = str_pad( floor( ( $remaining % 3600 ) / 60 ), 2, '0', STR_PAD_LEFT );
254 $init_seconds = str_pad( $remaining % 60, 2, '0', STR_PAD_LEFT );
255 } else {
256 $init_days = '00';
257 $init_hours = '00';
258 $init_minutes = '00';
259 $init_seconds = '00';
260 }
261
262 $labels = array(
263 'days' => $attributes['daysLabel'] ?? 'DAYS',
264 'hours' => $attributes['hoursLabel'] ?? 'HOURS',
265 'minutes' => $attributes['minutesLabel'] ?? 'MINUTES',
266 'seconds' => $attributes['secondsLabel'] ?? 'SECONDS',
267 );
268
269 $label_style = '';
270
271 if ( ! empty( $attributes['labelColor'] ) ) {
272 $label_style .= 'color:' . esc_attr( $attributes['labelColor'] ) . ';';
273 }
274 if ( ! empty( $attributes['labelFontSize'] ) ) {
275 $label_style .= 'font-size:' . esc_attr( gutenify_get_fluid_font_size( $attributes['labelFontSize'] ) ) . ';';
276 }
277 if ( ! empty( $attributes['labelLineHeight'] ) ) {
278 $label_style .= 'line-height:' . esc_attr( $attributes['labelLineHeight'] ) . ';';
279 }
280
281 $label_style_attr = $label_style ? ' style="' . $label_style . '"' : '';
282
283 $wrapper_attributes = get_block_wrapper_attributes( array(
284 'data-type' => esc_attr( $type ),
285 'data-post-id' => esc_attr( $post_id ),
286 'data-evergreen-hours' => esc_attr( $evg_hours ),
287 'data-evergreen-minutes' => esc_attr( $evg_minutes ),
288 'data-timestamp' => esc_attr( $timestamp ),
289 'data-end-action' => esc_attr( $end_action ),
290 'data-hide-selector' => esc_attr( $hide_selector ),
291 'data-redirect-url' => esc_attr( $redirect_url ),
292 'data-evergreen-restart' => esc_attr( $evg_restart ? 'true' : 'false' ),
293 ) );
294
295 $separator = $attributes['separator'] ?? '';
296 $item_gap = $attributes['itemGap'] ?? '';
297 $ul_style = $item_gap ? ' style="gap:' . esc_attr( $item_gap ) . ';"' : '';
298
299 $item_border = $attributes['itemBorder'] ?? array();
300 $item_border_style = '';
301 if ( ! empty( $item_border['color'] ) ) {
302 $item_border_style .= 'border-color:' . esc_attr( $item_border['color'] ) . ';';
303 }
304 if ( ! empty( $item_border['width'] ) ) {
305 $item_border_style .= 'border-width:' . esc_attr( $item_border['width'] ) . ';';
306 }
307 if ( ! empty( $item_border['style'] ) ) {
308 $item_border_style .= 'border-style:' . esc_attr( $item_border['style'] ) . ';';
309 }
310 if ( ! empty( $attributes['itemBorderRadius'] ) ) {
311 $item_border_style .= 'border-radius:' . esc_attr( $attributes['itemBorderRadius'] ) . ';';
312 }
313 if ( ! empty( $attributes['itemPadding'] ) ) {
314 $item_border_style .= 'padding:' . esc_attr( $attributes['itemPadding'] ) . ';';
315 }
316 $item_style_attr = $item_border_style ? ' style="' . $item_border_style . '"' : '';
317
318 ob_start();
319 ?>
320 <div <?php echo wp_kses_post( $wrapper_attributes ); ?>>
321 <ul<?php echo $ul_style; ?>>
322 <li<?php echo $item_style_attr; ?>>
323 <span class="days"><?php echo esc_html( $init_days ); ?></span>
324 <small<?php echo $label_style_attr; ?>><?php echo esc_html( $labels['days'] ); ?></small>
325 </li>
326 <?php if ( $separator ) : ?>
327 <li class="separator"><?php echo esc_html( $separator ); ?></li>
328 <?php endif; ?>
329 <li<?php echo $item_style_attr; ?>>
330 <span class="hours"><?php echo esc_html( $init_hours ); ?></span>
331 <small<?php echo $label_style_attr; ?>><?php echo esc_html( $labels['hours'] ); ?></small>
332 </li>
333 <?php if ( $separator ) : ?>
334 <li class="separator"><?php echo esc_html( $separator ); ?></li>
335 <?php endif; ?>
336 <li<?php echo $item_style_attr; ?>>
337 <span class="minutes"><?php echo esc_html( $init_minutes ); ?></span>
338 <small<?php echo $label_style_attr; ?>><?php echo esc_html( $labels['minutes'] ); ?></small>
339 </li>
340 <?php if ( $separator ) : ?>
341 <li class="separator"><?php echo esc_html( $separator ); ?></li>
342 <?php endif; ?>
343 <li<?php echo $item_style_attr; ?>>
344 <span class="seconds"><?php echo esc_html( $init_seconds ); ?></span>
345 <small<?php echo $label_style_attr; ?>><?php echo esc_html( $labels['seconds'] ); ?></small>
346 </li>
347 </ul>
348 </div>
349 <?php
350 return ob_get_clean();
351 }
352