PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.0-beta
Jetpack – WP Security, Backup, Speed, & Growth v16.0-beta
16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / widgets / milestone / class-milestone-widget.php
jetpack / modules / widgets / milestone Last commit date
admin.js 5 years ago class-milestone-widget.php 7 months ago milestone-widget.css 7 months ago milestone.js 1 year ago milestone.php 5 years ago style-admin.css 4 months ago
class-milestone-widget.php
759 lines
1 <?php
2 /**
3 * Milestone Countdown Widget
4 *
5 * @package automattic/jetpack
6 */
7
8 use Automattic\Jetpack\Assets;
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit( 0 );
12 }
13
14 /**
15 * Class Milestone_Widget
16 */
17 class Milestone_Widget extends WP_Widget {
18 /**
19 * Holding array for widget configuration and localization.
20 *
21 * @var array
22 */
23 private static $config_js = array();
24
25 /**
26 * Available time units sorted in descending order.
27 *
28 * @var Array
29 */
30 protected $available_units = array(
31 'years',
32 'months',
33 'days',
34 'hours',
35 'minutes',
36 'seconds',
37 );
38
39 /**
40 * Milestone_Widget constructor.
41 */
42 public function __construct() {
43 $widget = array(
44 'classname' => 'milestone-widget',
45 'description' => __( 'Display a countdown to a certain date.', 'jetpack' ),
46 );
47
48 parent::__construct(
49 'Milestone_Widget',
50 /** This filter is documented in modules/widgets/facebook-likebox.php */
51 apply_filters( 'jetpack_widget_name', __( 'Milestone', 'jetpack' ) ),
52 $widget
53 );
54
55 add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_template' ) );
56 add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_admin' ) );
57 add_action( 'wp_footer', array( $this, 'localize_script' ) );
58
59 if ( is_active_widget( false, false, $this->id_base, true ) || is_active_widget( false, false, 'monster', true ) || is_customize_preview() ) {
60 add_action( 'wp_head', array( __CLASS__, 'styles_template' ) );
61 }
62 }
63
64 /**
65 * Enqueue admin assets.
66 *
67 * @param string $hook_suffix Hook suffix provided by WordPress.
68 */
69 public static function enqueue_admin( $hook_suffix ) {
70 if ( 'widgets.php' === $hook_suffix ) {
71 wp_enqueue_style( 'milestone-admin', plugin_dir_url( __FILE__ ) . 'style-admin.css', array(), '20201113' );
72 wp_enqueue_script(
73 'milestone-admin-js',
74 Assets::get_file_url_for_environment(
75 '_inc/build/widgets/milestone/admin.min.js',
76 'modules/widgets/milestone/admin.js'
77 ),
78 array( 'jquery' ),
79 '20201113',
80 true
81 );
82 }
83 }
84
85 /**
86 * Enqueue the frontend JS.
87 */
88 public static function enqueue_template() {
89 if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
90 return;
91 }
92
93 wp_enqueue_script(
94 'milestone',
95 Assets::get_file_url_for_environment(
96 '_inc/build/widgets/milestone/milestone.min.js',
97 'modules/widgets/milestone/milestone.js'
98 ),
99 array(),
100 '20201113',
101 true
102 );
103 }
104
105 /**
106 * Output the frontend styling.
107 */
108 public static function styles_template() {
109 global $themecolors;
110 $colors = wp_parse_args(
111 $themecolors,
112 array(
113 'bg' => 'ffffff',
114 'border' => 'cccccc',
115 'text' => '333333',
116 )
117 );
118 ?>
119 <style>
120 .milestone-widget {
121 --milestone-text-color: <?php echo self::sanitize_color_hex( $colors['text'] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>;
122 --milestone-bg-color: <?php echo self::sanitize_color_hex( $colors['bg'] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>;
123 --milestone-border-color:<?php echo self::sanitize_color_hex( $colors['border'] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>;
124 }
125 </style>
126 <?php
127 }
128
129 /**
130 * Ensure that a string representing a color in hexadecimal
131 * notation is safe for use in css and database saves.
132 *
133 * @param string $hex Hexademical code to sanitize.
134 * @param string $prefix Prefix for the hex code.
135 *
136 * @return string Color in hexadecimal notation on success - the string "transparent" otherwise.
137 */
138 public static function sanitize_color_hex( $hex, $prefix = '#' ) {
139 $hex = trim( $hex );
140
141 /* Strip recognized prefixes. */
142 if ( str_starts_with( $hex, '#' ) ) {
143 $hex = substr( $hex, 1 );
144 } elseif ( str_starts_with( $hex, '%23' ) ) {
145 $hex = substr( $hex, 3 );
146 }
147
148 if ( 0 !== preg_match( '/^[0-9a-fA-F]{6}$/', $hex ) ) {
149 return $prefix . $hex;
150 }
151
152 return 'transparent';
153 }
154
155 /**
156 * Localize Front-end Script.
157 *
158 * Print the javascript configuration array only if the
159 * current template has an instance of the widget that
160 * is still counting down. In all other cases, this
161 * function will dequeue milestone.js.
162 *
163 * Hooks into the "wp_footer" action.
164 */
165 public function localize_script() {
166 if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
167 return;
168 }
169
170 if ( empty( self::$config_js['instances'] ) ) {
171 wp_dequeue_script( 'milestone' );
172 return;
173 }
174 self::$config_js['api_root'] = esc_url_raw( rest_url() );
175 wp_localize_script( 'milestone', 'MilestoneConfig', self::$config_js );
176 }
177
178 /**
179 * Return an associative array of default values
180 *
181 * These values are used in new widgets.
182 *
183 * @return array Array of default values for the Widget's options.
184 */
185 public function defaults() {
186 $now = current_datetime();
187 $now_timestamp = $now->getTimestamp();
188
189 return array(
190 'title' => '',
191 'event' => __( 'The Big Day', 'jetpack' ),
192 'unit' => 'automatic',
193 'type' => 'until',
194 'message' => __( 'The big day is here.', 'jetpack' ),
195 'day' => gmdate( 'd', $now_timestamp ),
196 'month' => gmdate( 'm', $now_timestamp ),
197 'year' => gmdate( 'Y', $now_timestamp ),
198 'hour' => 0,
199 'min' => 0,
200 );
201 }
202
203 /**
204 * Widget
205 *
206 * @param array $args Widget args.
207 * @param array $instance Widget instance.
208 */
209 public function widget( $args, $instance ) {
210 $instance = wp_parse_args( $instance, $this->defaults() );
211
212 $this->enqueue_scripts();
213
214 echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
215
216 /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
217 $title = apply_filters( 'widget_title', $instance['title'] );
218 if ( ! empty( $title ) ) {
219 echo $args['before_title'] . $title . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
220 }
221
222 $widget_id = ! empty( $args['widget_id'] ) ? $args['widget_id'] : 'milestone_widget';
223 $data = $this->get_widget_data( $instance );
224 $config = array(
225 'id' => $widget_id,
226 'message' => $data['message'],
227 'refresh' => $data['refresh'],
228 );
229
230 /*
231 * Sidebars may be configured to not expose the `widget_id`. Example: `twentytwenty` footer areas.
232 *
233 * We need our own unique identifier.
234 */
235 $config['content_id'] = $widget_id . '-content';
236
237 self::$config_js['instances'][] = $config;
238
239 printf( '<div id="%s" class="milestone-content">', esc_html( $config['content_id'] ) );
240
241 echo '<div class="milestone-header">';
242 echo '<strong class="event">' . esc_html( $instance['event'] ) . '</strong>';
243 echo '<span class="date">' . esc_html( date_i18n( get_option( 'date_format' ), $data['milestone'] ) ) . '</span>';
244 echo '</div>';
245
246 echo wp_kses_post( $data['message'] );
247
248 echo '</div><!--milestone-content-->';
249
250 echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
251
252 /** This action is documented in modules/widgets/gravatar-profile.php */
253 do_action( 'jetpack_stats_extra', 'widget_view', 'milestone' );
254 }
255
256 /**
257 * Enqueue widget styles
258 */
259 public function enqueue_scripts() {
260 wp_enqueue_style(
261 'milestone-widget',
262 plugins_url( 'milestone-widget.css', __FILE__ ),
263 array(),
264 JETPACK__VERSION
265 );
266 }
267
268 /**
269 * Getter for the widget data.
270 *
271 * @param array $instance Widget instance.
272 *
273 * @return array
274 */
275 public function get_widget_data( $instance ) {
276 $data = array();
277
278 $instance = $this->sanitize_instance( $instance );
279
280 $milestone = mktime( $instance['hour'], $instance['min'], 0, $instance['month'], $instance['day'], $instance['year'] );
281 $now = (int) current_time( 'timestamp' ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
282 $type = $instance['type'];
283
284 if ( 'since' === $type ) {
285 $diff = (int) floor( $now - $milestone );
286 } else {
287 $diff = (int) floor( $milestone - $now );
288 }
289
290 $data['diff'] = $diff;
291 $data['unit'] = $this->get_unit( $diff, $instance['unit'] );
292
293 // Setting the refresh counter to equal the number of seconds it takes to flip a unit.
294 $refresh_intervals = array(
295 0, // should be YEAR_IN_SECONDS, but doing setTimeout for a year doesn't seem to be logical.
296 0, // same goes for MONTH_IN_SECONDS.
297 DAY_IN_SECONDS,
298 HOUR_IN_SECONDS,
299 MINUTE_IN_SECONDS,
300 1,
301 );
302
303 $data['refresh'] = $refresh_intervals[ array_search( $data['unit'], $this->available_units, true ) ];
304 $data['milestone'] = $milestone;
305
306 if ( ( 1 > $diff ) && ( 'until' === $type ) ) {
307 $data['message'] = '<div class="milestone-message">' . $instance['message'] . '</div>';
308 $data['refresh'] = 0; // No need to refresh, the milestone has been reached.
309 } else {
310 $interval_text = $this->get_interval_in_units( $diff, $data['unit'] );
311 $interval = (int) $interval_text;
312
313 if ( 'since' === $type ) {
314
315 switch ( $data['unit'] ) {
316 case 'years':
317 $data['message'] = sprintf(
318 /* translators: %s is the number of year(s). */
319 _n(
320 '<span class="difference">%s</span> <span class="label">year ago.</span>',
321 '<span class="difference">%s</span> <span class="label">years ago.</span>',
322 $interval,
323 'jetpack'
324 ),
325 $interval_text
326 );
327 break;
328 case 'months':
329 $data['message'] = sprintf(
330 /* translators: %s is the number of month(s). */
331 _n(
332 '<span class="difference">%s</span> <span class="label">month ago.</span>',
333 '<span class="difference">%s</span> <span class="label">months ago.</span>',
334 $interval,
335 'jetpack'
336 ),
337 $interval_text
338 );
339 break;
340 case 'days':
341 $data['message'] = sprintf(
342 /* translators: %s is the number of days(s). */
343 _n(
344 '<span class="difference">%s</span> <span class="label">day ago.</span>',
345 '<span class="difference">%s</span> <span class="label">days ago.</span>',
346 $interval,
347 'jetpack'
348 ),
349 $interval_text
350 );
351 break;
352 case 'hours':
353 $data['message'] = sprintf(
354 /* translators: %s is the number of hours(s). */
355 _n(
356 '<span class="difference">%s</span> <span class="label">hour ago.</span>',
357 '<span class="difference">%s</span> <span class="label">hours ago.</span>',
358 $interval,
359 'jetpack'
360 ),
361 $interval_text
362 );
363 break;
364 case 'minutes':
365 $data['message'] = sprintf(
366 /* translators: %s is the number of minutes(s). */
367 _n(
368 '<span class="difference">%s</span> <span class="label">minute ago.</span>',
369 '<span class="difference">%s</span> <span class="label">minutes ago.</span>',
370 $interval,
371 'jetpack'
372 ),
373 $interval_text
374 );
375 break;
376 case 'seconds':
377 $data['message'] = sprintf(
378 /* translators: %s is the number of second(s). */
379 _n(
380 '<span class="difference">%s</span> <span class="label">second ago.</span>',
381 '<span class="difference">%s</span> <span class="label">seconds ago.</span>',
382 $interval,
383 'jetpack'
384 ),
385 $interval_text
386 );
387 break;
388 }
389 } else {
390 switch ( $this->get_unit( $diff, $instance['unit'] ) ) {
391 case 'years':
392 $data['message'] = sprintf(
393 /* translators: %s is the number of year(s). */
394 _n(
395 '<span class="difference">%s</span> <span class="label">year to go.</span>',
396 '<span class="difference">%s</span> <span class="label">years to go.</span>',
397 $interval,
398 'jetpack'
399 ),
400 $interval_text
401 );
402 break;
403 case 'months':
404 $data['message'] = sprintf(
405 /* translators: %s is the number of month(s). */
406 _n(
407 '<span class="difference">%s</span> <span class="label">month to go.</span>',
408 '<span class="difference">%s</span> <span class="label">months to go.</span>',
409 $interval,
410 'jetpack'
411 ),
412 $interval_text
413 );
414 break;
415 case 'days':
416 $data['message'] = sprintf(
417 /* translators: %s is the number of days(s). */
418 _n(
419 '<span class="difference">%s</span> <span class="label">day to go.</span>',
420 '<span class="difference">%s</span> <span class="label">days to go.</span>',
421 $interval,
422 'jetpack'
423 ),
424 $interval_text
425 );
426 break;
427 case 'hours':
428 $data['message'] = sprintf(
429 /* translators: %s is the number of hour(s). */
430 _n(
431 '<span class="difference">%s</span> <span class="label">hour to go.</span>',
432 '<span class="difference">%s</span> <span class="label">hours to go.</span>',
433 $interval,
434 'jetpack'
435 ),
436 $interval_text
437 );
438 break;
439 case 'minutes':
440 $data['message'] = sprintf(
441 /* translators: %s is the number of minute(s). */
442 _n(
443 '<span class="difference">%s</span> <span class="label">minute to go.</span>',
444 '<span class="difference">%s</span> <span class="label">minutes to go.</span>',
445 $interval,
446 'jetpack'
447 ),
448 $interval_text
449 );
450 break;
451 case 'seconds':
452 $data['message'] = sprintf(
453 /* translators: %s is the number of second(s). */
454 _n(
455 '<span class="difference">%s</span> <span class="label">second to go.</span>',
456 '<span class="difference">%s</span> <span class="label">seconds to go.</span>',
457 $interval,
458 'jetpack'
459 ),
460 $interval_text
461 );
462 break;
463 }
464 }
465 $data['message'] = '<div class="milestone-countdown">' . $data['message'] . '</div>';
466 }
467
468 return $data;
469 }
470
471 /**
472 * Return the largest possible time unit that the difference will be displayed in.
473 *
474 * @param Integer $seconds the interval in seconds.
475 * @param String $maximum_unit the maximum unit that will be used. Optional.
476 * @return String $calculated_unit
477 */
478 protected function get_unit( $seconds, $maximum_unit = 'automatic' ) {
479 $unit = '';
480
481 if ( $seconds >= YEAR_IN_SECONDS * 2 ) {
482 // more than 2 years - show in years, one decimal point.
483 $unit = 'years';
484
485 } elseif ( $seconds >= YEAR_IN_SECONDS ) {
486 if ( 'years' === $maximum_unit ) {
487 $unit = 'years';
488 } else {
489 // automatic mode - showing months even if it's between one and two years.
490 $unit = 'months';
491 }
492 } elseif ( $seconds >= MONTH_IN_SECONDS * 3 ) {
493 // fewer than 2 years - show in months.
494 $unit = 'months';
495
496 } elseif ( $seconds >= MONTH_IN_SECONDS ) {
497 if ( 'months' === $maximum_unit ) {
498 $unit = 'months';
499 } else {
500 // automatic mode - showing days even if it's between one and three months.
501 $unit = 'days';
502 }
503 } elseif ( $seconds >= DAY_IN_SECONDS - 1 ) {
504 // fewer than a month - show in days.
505 $unit = 'days';
506
507 } elseif ( $seconds >= HOUR_IN_SECONDS - 1 ) {
508 // less than 1 day - show in hours.
509 $unit = 'hours';
510
511 } elseif ( $seconds >= MINUTE_IN_SECONDS - 1 ) {
512 // less than 1 hour - show in minutes.
513 $unit = 'minutes';
514
515 } else {
516 // less than 1 minute - show in seconds.
517 $unit = 'seconds';
518 }
519
520 $maximum_unit_index = array_search( $maximum_unit, $this->available_units, true );
521 $unit_index = array_search( $unit, $this->available_units, true );
522
523 if (
524 false === $maximum_unit_index // the maximum unit parameter is automatic.
525 || $unit_index > $maximum_unit_index // there is not enough seconds for even one maximum time unit.
526 ) {
527 return $unit;
528 }
529 return $maximum_unit;
530 }
531
532 /**
533 * Returns a time difference value in specified units.
534 *
535 * @param int $seconds Number of seconds.
536 * @param string $units Unit.
537 * @return int $time_in_units.
538 */
539 protected function get_interval_in_units( $seconds, $units ) {
540 switch ( $units ) {
541 case 'years':
542 $years = $seconds / YEAR_IN_SECONDS;
543 $decimals = abs( round( $years, 1 ) - round( $years ) ) > 0 ? 1 : 0;
544 return number_format_i18n( $years, $decimals );
545 case 'months':
546 return (int) ( $seconds / 60 / 60 / 24 / 30 );
547 case 'days':
548 return (int) ( $seconds / 60 / 60 / 24 + 1 );
549 case 'hours':
550 return (int) ( $seconds / 60 / 60 );
551 case 'minutes':
552 return (int) ( $seconds / 60 + 1 );
553 default:
554 return $seconds;
555 }
556 }
557
558 /**
559 * Update widget.
560 *
561 * @param array $new_instance New instance of the widget being saved.
562 * @param array $old_instance Previous instance being saved over.
563 *
564 * @return array
565 */
566 public function update( $new_instance, $old_instance ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
567 return $this->sanitize_instance( $new_instance );
568 }
569
570 /**
571 * Make sure that a number is within a certain range.
572 * If the number is too small it will become the possible lowest value.
573 * If the number is too large it will become the possible highest value.
574 *
575 * @param int $n The number to check.
576 * @param int $floor The lowest possible value.
577 * @param int $ceil The highest possible value.
578 */
579 public function sanitize_range( $n, $floor, $ceil ) {
580 $n = (int) $n;
581 if ( $n < $floor ) {
582 $n = $floor;
583 } elseif ( $n > $ceil ) {
584 $n = $ceil;
585 }
586 return $n;
587 }
588
589 /**
590 * Sanitize an instance of this widget.
591 *
592 * Date ranges match the documentation for mktime in the php manual.
593 *
594 * @see https://php.net/manual/en/function.mktime.php#refsect1-function.mktime-parameters
595 *
596 * @uses Milestone_Widget::sanitize_range().
597 *
598 * @param array $dirty Unsantized data for the widget.
599 *
600 * @return array Santized data.
601 */
602 public function sanitize_instance( $dirty ) {
603 $dirty = wp_parse_args(
604 $dirty,
605 $this->defaults()
606 );
607
608 $allowed_tags = array(
609 'a' => array(
610 'title' => array(),
611 'href' => array(),
612 'target' => array(),
613 ),
614 'em' => array( 'title' => array() ),
615 'strong' => array( 'title' => array() ),
616 );
617
618 $clean = array(
619 'title' => trim( wp_strip_all_tags( stripslashes( $dirty['title'] ) ) ),
620 'event' => trim( wp_strip_all_tags( stripslashes( $dirty['event'] ) ) ),
621 'unit' => $dirty['unit'],
622 'type' => $dirty['type'],
623 'message' => wp_kses( $dirty['message'], $allowed_tags ),
624 'year' => $this->sanitize_range( $dirty['year'], 1901, 2037 ),
625 'month' => $this->sanitize_range( $dirty['month'], 1, 12 ),
626 'hour' => $this->sanitize_range( $dirty['hour'], 0, 23 ),
627 'min' => zeroise( $this->sanitize_range( $dirty['min'], 0, 59 ), 2 ),
628 );
629
630 $clean['day'] = $this->sanitize_range( $dirty['day'], 1, gmdate( 't', mktime( 0, 0, 0, $clean['month'], 1, $clean['year'] ) ) );
631
632 return $clean;
633 }
634
635 /**
636 * Form
637 *
638 * @param array $instance Widget instance.
639 * @return string|void
640 */
641 public function form( $instance ) {
642 $instance = $this->sanitize_instance( $instance );
643
644 $units = array(
645 'automatic' => _x( 'Automatic', 'Milestone widget: mode in which the date unit is determined automatically', 'jetpack' ),
646 'years' => _x( 'Years', 'Milestone widget: mode in which the date unit is set to years', 'jetpack' ),
647 'months' => _x( 'Months', 'Milestone widget: mode in which the date unit is set to months', 'jetpack' ),
648 'days' => _x( 'Days', 'Milestone widget: mode in which the date unit is set to days', 'jetpack' ),
649 'hours' => _x( 'Hours', 'Milestone widget: mode in which the date unit is set to hours', 'jetpack' ),
650 );
651 ?>
652 <div class="milestone-widget">
653 <p>
654 <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title', 'jetpack' ); ?></label>
655 <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $instance['title'] ); ?>" />
656 </p>
657
658 <p>
659 <label for="<?php echo esc_attr( $this->get_field_id( 'event' ) ); ?>"><?php esc_html_e( 'Description', 'jetpack' ); ?></label>
660 <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'event' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'event' ) ); ?>" type="text" value="<?php echo esc_attr( $instance['event'] ); ?>" />
661 </p>
662
663 <fieldset class="jp-ms-data-time">
664 <legend><?php esc_html_e( 'Date', 'jetpack' ); ?></legend>
665
666 <label for="<?php echo esc_attr( $this->get_field_id( 'month' ) ); ?>" class="assistive-text"><?php esc_html_e( 'Month', 'jetpack' ); ?></label>
667 <select id="<?php echo esc_attr( $this->get_field_id( 'month' ) ); ?>" class="month" name="<?php echo esc_attr( $this->get_field_name( 'month' ) ); ?>">
668 <?php
669 global $wp_locale;
670 for ( $i = 1; $i < 13; $i++ ) {
671 $monthnum = zeroise( $i, 2 );
672 printf(
673 '<option value="%s" %s>%s-%s</option>',
674 esc_attr( $monthnum ),
675 selected( $i, $instance['month'], false ),
676 esc_attr( $monthnum ),
677 esc_attr( $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) ) )
678 );
679 }
680 ?>
681 </select>
682
683 <label for="<?php echo esc_attr( $this->get_field_id( 'day' ) ); ?>" class="assistive-text"><?php esc_html_e( 'Day', 'jetpack' ); ?></label>
684 <input id="<?php echo esc_attr( $this->get_field_id( 'day' ) ); ?>" class="day" name="<?php echo esc_attr( $this->get_field_name( 'day' ) ); ?>" type="text" value="<?php echo esc_attr( $instance['day'] ); ?>">,
685
686 <label for="<?php echo esc_attr( $this->get_field_id( 'year' ) ); ?>" class="assistive-text"><?php esc_html_e( 'Year', 'jetpack' ); ?></label>
687 <input id="<?php echo esc_attr( $this->get_field_id( 'year' ) ); ?>" class="year" name="<?php echo esc_attr( $this->get_field_name( 'year' ) ); ?>" type="text" value="<?php echo esc_attr( $instance['year'] ); ?>">
688 </fieldset>
689
690 <fieldset class="jp-ms-data-time">
691 <legend><?php esc_html_e( 'Time', 'jetpack' ); ?></legend>
692
693 <label for="<?php echo esc_attr( $this->get_field_id( 'hour' ) ); ?>" class="assistive-text"><?php esc_html_e( 'Hour', 'jetpack' ); ?></label>
694 <input id="<?php echo esc_attr( $this->get_field_id( 'hour' ) ); ?>" class="hour" name="<?php echo esc_attr( $this->get_field_name( 'hour' ) ); ?>" type="text" value="<?php echo esc_attr( $instance['hour'] ); ?>">
695
696 <label for="<?php echo esc_attr( $this->get_field_id( 'min' ) ); ?>" class="assistive-text"><?php esc_html_e( 'Minutes', 'jetpack' ); ?></label>
697
698 <span class="time-separator">:</span>
699
700 <input id="<?php echo esc_attr( $this->get_field_id( 'min' ) ); ?>" class="minutes" name="<?php echo esc_attr( $this->get_field_name( 'min' ) ); ?>" type="text" value="<?php echo esc_attr( $instance['min'] ); ?>">
701 </fieldset>
702
703 <fieldset class="jp-ms-data-unit">
704 <legend><?php esc_html_e( 'Time Unit', 'jetpack' ); ?></legend>
705
706 <label for="<?php echo esc_attr( $this->get_field_id( 'unit' ) ); ?>" class="assistive-text">
707 <?php esc_html_e( 'Time Unit', 'jetpack' ); ?>
708 </label>
709
710 <select id="<?php echo esc_attr( $this->get_field_id( 'unit' ) ); ?>" class="unit" name="<?php echo esc_attr( $this->get_field_name( 'unit' ) ); ?>">
711 <?php
712 foreach ( $units as $key => $unit ) {
713 printf(
714 '<option value="%s" %s>%s</option>',
715 esc_attr( $key ),
716 selected( $key, $instance['unit'], false ),
717 esc_html( $unit )
718 );
719 }
720 ?>
721 </select>
722 </fieldset>
723
724 <ul class="milestone-type">
725 <li>
726 <label>
727 <input
728 <?php checked( $instance['type'], 'until' ); ?>
729 name="<?php echo esc_attr( $this->get_field_name( 'type' ) ); ?>"
730 type="radio"
731 value="until"
732 />
733 <?php esc_html_e( 'Until your milestone', 'jetpack' ); ?>
734 </label>
735 </li>
736
737 <li>
738 <label>
739 <input
740 <?php checked( $instance['type'], 'since' ); ?>
741 name="<?php echo esc_attr( $this->get_field_name( 'type' ) ); ?>"
742 type="radio"
743 value="since"
744 />
745 <?php esc_html_e( 'Since your milestone', 'jetpack' ); ?>
746 </label>
747 </li>
748 </ul>
749
750 <p class="milestone-message-wrapper">
751 <label for="<?php echo esc_attr( $this->get_field_id( 'message' ) ); ?>"><?php esc_html_e( 'Milestone Reached Message', 'jetpack' ); ?></label>
752 <textarea id="<?php echo esc_attr( $this->get_field_id( 'message' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'message' ) ); ?>" class="widefat" rows="3"><?php echo esc_textarea( $instance['message'] ); ?></textarea>
753 </p>
754 </div>
755
756 <?php
757 }
758 }
759