PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 7.6.2
Jetpack – WP Security, Backup, Speed, & Growth v7.6.2
16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 All 503 releases
jetpack / modules / widgets / milestone / milestone.php

milestone.php in Jetpack – WP Security, Backup, Speed, & Growth 7.6.2, at modules/widgets/milestone/milestone.php

686 lines 21.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Milestone
4 Description: Countdown to a specific date.
5 Version: 1.0
6 Author: Automattic Inc.
7 Author URI: http://automattic.com/
8 License: GPLv2 or later
9 */
10
11 use Automattic\Jetpack\Assets;
12
13 function jetpack_register_widget_milestone() {
14 register_widget( 'Milestone_Widget' );
15 }
16 add_action( 'widgets_init', 'jetpack_register_widget_milestone' );
17
18 class Milestone_Widget extends WP_Widget {
19 private static $dir = null;
20 private static $url = null;
21 private static $defaults = null;
22 private static $config_js = null;
23
24 /**
25 * Available time units sorted in descending order.
26 * @var Array
27 */
28 protected $available_units = array(
29 'years',
30 'months',
31 'days',
32 'hours',
33 'minutes',
34 'seconds'
35 );
36
37 function __construct() {
38 $widget = array(
39 'classname' => 'milestone-widget',
40 'description' => __( 'Display a countdown to a certain date.', 'jetpack' ),
41 );
42
43 parent::__construct(
44 'Milestone_Widget',
45 /** This filter is documented in modules/widgets/facebook-likebox.php */
46 apply_filters( 'jetpack_widget_name', __( 'Milestone', 'jetpack' ) ),
47 $widget
48 );
49
50 self::$dir = trailingslashit( dirname( __FILE__ ) );
51 self::$url = plugin_dir_url( __FILE__ );
52
53 add_action( 'wp_enqueue_scripts', array( __class__, 'enqueue_template' ) );
54 add_action( 'admin_enqueue_scripts', array( __class__, 'enqueue_admin' ) );
55 add_action( 'wp_footer', array( $this, 'localize_script' ) );
56
57 if ( is_active_widget( false, false, $this->id_base, true ) || is_active_widget( false, false, 'monster', true ) || is_customize_preview() ) {
58 add_action( 'wp_head', array( __class__, 'styles_template' ) );
59 }
60 }
61
62 public static function enqueue_admin( $hook_suffix ) {
63 if ( 'widgets.php' == $hook_suffix ) {
64 wp_enqueue_style( 'milestone-admin', self::$url . 'style-admin.css', array(), '20161215' );
65 wp_enqueue_script(
66 'milestone-admin-js',
67 Assets::get_file_url_for_environment(
68 '_inc/build/widgets/milestone/admin.min.js',
69 'modules/widgets/milestone/admin.js'
70 ),
71 array( 'jquery' ),
72 '20170915',
73 true
74 );
75 }
76 }
77
78 public static function enqueue_template() {
79 if ( Jetpack_AMP_Support::is_amp_request() ) {
80 return;
81 }
82
83 wp_enqueue_script(
84 'milestone',
85 Assets::get_file_url_for_environment(
86 '_inc/build/widgets/milestone/milestone.min.js',
87 'modules/widgets/milestone/milestone.js'
88 ),
89 array( 'jquery' ),
90 '20160520',
91 true
92 );
93 }
94
95 public static function styles_template() {
96 global $themecolors;
97 $colors = wp_parse_args( $themecolors, array(
98 'bg' => 'ffffff',
99 'border' => 'cccccc',
100 'text' => '333333',
101 ) );
102 ?>
103 <style>
104 .milestone-widget {
105 margin-bottom: 1em;
106 }
107 .milestone-content {
108 line-height: 2;
109 margin-top: 5px;
110 max-width: 100%;
111 padding: 0;
112 text-align: center;
113 }
114 .milestone-header {
115 background-color: <?php echo self::sanitize_color_hex( $colors['text'] ); ?>;
116 color: <?php echo self::sanitize_color_hex( $colors['bg'] ); ?>;
117 line-height: 1.3;
118 margin: 0;
119 padding: .8em;
120 }
121 .milestone-header .event,
122 .milestone-header .date {
123 display: block;
124 }
125 .milestone-header .event {
126 font-size: 120%;
127 }
128 .milestone-countdown .difference {
129 display: block;
130 font-size: 500%;
131 font-weight: bold;
132 line-height: 1.2;
133 }
134 .milestone-countdown,
135 .milestone-message {
136 background-color: <?php echo self::sanitize_color_hex( $colors['bg'] ); ?>;
137 border: 1px solid <?php echo self::sanitize_color_hex( $colors['border'] ); ?>;
138 border-top: 0;
139 color: <?php echo self::sanitize_color_hex( $colors['text'] ); ?>;
140 padding-bottom: 1em;
141 }
142 .milestone-message {
143 padding-top: 1em
144 }
145 </style>
146 <?php
147 }
148
149 /**
150 * Ensure that a string representing a color in hexadecimal
151 * notation is safe for use in css and database saves.
152 *
153 * @param string Color in hexadecimal notation. "#" may or may not be prepended to the string.
154 * @return string Color in hexadecimal notation on success - the string "transparent" otherwise.
155 */
156 public static function sanitize_color_hex( $hex, $prefix = '#' ) {
157 $hex = trim( $hex );
158
159 /* Strip recognized prefixes. */
160 if ( 0 === strpos( $hex, '#' ) ) {
161 $hex = substr( $hex, 1 );
162 } elseif ( 0 === strpos( $hex, '%23' ) ) {
163 $hex = substr( $hex, 3 );
164 }
165
166 if ( 0 !== preg_match( '/^[0-9a-fA-F]{6}$/', $hex ) ) {
167 return $prefix . $hex;
168 }
169
170 return 'transparent';
171 }
172
173 /**
174 * Localize Front-end Script.
175 *
176 * Print the javascript configuration array only if the
177 * current template has an instance of the widget that
178 * is still counting down. In all other cases, this
179 * function will dequeue milestone.js.
180 *
181 * Hooks into the "wp_footer" action.
182 */
183 function localize_script() {
184 if ( Jetpack_AMP_Support::is_amp_request() ) {
185 return;
186 }
187
188 if ( empty( self::$config_js['instances'] ) ) {
189 wp_dequeue_script( 'milestone' );
190 return;
191 }
192 self::$config_js['api_root'] = esc_url_raw( rest_url() );
193 wp_localize_script( 'milestone', 'MilestoneConfig', self::$config_js );
194 }
195
196 /**
197 * Widget
198 */
199 function widget( $args, $instance ) {
200 echo $args['before_widget'];
201
202 /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
203 $title = apply_filters( 'widget_title', $instance['title'] );
204 if ( ! empty( $title ) ) {
205 echo $args['before_title'] . $title . $args['after_title'];
206 }
207
208 $data = $this->get_widget_data( $instance );
209
210 self::$config_js['instances'][] = array(
211 'id' => $args['widget_id'],
212 'message' => $data['message'],
213 'refresh' => $data['refresh']
214 );
215
216 echo '<div class="milestone-content">';
217
218 echo '<div class="milestone-header">';
219 echo '<strong class="event">' . esc_html( $instance['event'] ) . '</strong>';
220 echo '<span class="date">' . esc_html( date_i18n( get_option( 'date_format' ), $data['milestone'] ) ) . '</span>';
221 echo '</div>';
222
223 echo $data['message'];
224
225 echo '</div><!--milestone-content-->';
226
227 echo $args['after_widget'];
228
229 /** This action is documented in modules/widgets/gravatar-profile.php */
230 do_action( 'jetpack_stats_extra', 'widget_view', 'milestone' );
231 }
232
233 function get_widget_data( $instance ) {
234 $data = array();
235
236 $instance = $this->sanitize_instance( $instance );
237
238 $milestone = mktime( $instance['hour'], $instance['min'], 0, $instance['month'], $instance['day'], $instance['year'] );
239 $now = (int) current_time( 'timestamp' );
240 $type = $instance['type'];
241
242 if ( 'since' === $type ) {
243 $diff = (int) floor( $now - $milestone );
244 } else {
245 $diff = (int) floor( $milestone - $now );
246 }
247
248 $data['diff'] = $diff;
249 $data['unit'] = $this->get_unit( $diff, $instance['unit'] );
250
251 // Setting the refresh counter to equal the number of seconds it takes to flip a unit
252 $refresh_intervals = array(
253 0, // should be YEAR_IN_SECONDS, but doing setTimeout for a year doesn't seem to be logical
254 0, // same goes for MONTH_IN_SECONDS,
255 DAY_IN_SECONDS,
256 HOUR_IN_SECONDS,
257 MINUTE_IN_SECONDS,
258 1
259 );
260
261 $data['refresh'] = $refresh_intervals[ array_search( $data['unit'], $this->available_units ) ];
262 $data['milestone'] = $milestone;
263
264 if ( ( 1 > $diff ) && ( 'until' === $type ) ) {
265 $data['message'] = '<div class="milestone-message">' . $instance['message'] . '</div>';
266 $data['refresh'] = 0; // No need to refresh, the milestone has been reached
267 } else {
268 $interval_text = $this->get_interval_in_units( $diff, $data['unit'] );
269 $interval = intval( $interval_text );
270
271 if ( 'since' === $type ) {
272
273 switch ( $data['unit'] ) {
274 case 'years':
275 $data['message'] = sprintf(
276 _n(
277 '<span class="difference">%s</span> <span class="label">year ago.</span>',
278 '<span class="difference">%s</span> <span class="label">years ago.</span>',
279 $interval,
280 'jetpack'
281 ),
282 $interval_text
283 );
284 break;
285 case 'months':
286 $data['message'] = sprintf(
287 _n(
288 '<span class="difference">%s</span> <span class="label">month ago.</span>',
289 '<span class="difference">%s</span> <span class="label">months ago.</span>',
290 $interval,
291 'jetpack'
292 ),
293 $interval_text
294 );
295 break;
296 case 'days':
297 $data['message'] = sprintf(
298 _n(
299 '<span class="difference">%s</span> <span class="label">day ago.</span>',
300 '<span class="difference">%s</span> <span class="label">days ago.</span>',
301 $interval,
302 'jetpack'
303 ),
304 $interval_text
305 );
306 break;
307 case 'hours':
308 $data['message'] = sprintf(
309 _n(
310 '<span class="difference">%s</span> <span class="label">hour ago.</span>',
311 '<span class="difference">%s</span> <span class="label">hours ago.</span>',
312 $interval,
313 'jetpack'
314 ),
315 $interval_text
316 );
317 break;
318 case 'minutes':
319 $data['message'] = sprintf(
320 _n(
321 '<span class="difference">%s</span> <span class="label">minute ago.</span>',
322 '<span class="difference">%s</span> <span class="label">minutes ago.</span>',
323 $interval,
324 'jetpack'
325 ),
326 $interval_text
327 );
328 break;
329 case 'seconds':
330 $data['message'] = sprintf(
331 _n(
332 '<span class="difference">%s</span> <span class="label">second ago.</span>',
333 '<span class="difference">%s</span> <span class="label">seconds ago.</span>',
334 $interval,
335 'jetpack'
336 ),
337 $interval_text
338 );
339 break;
340 }
341 } else {
342 switch ( $this->get_unit( $diff, $instance['unit'] ) ) {
343 case 'years':
344 $data['message'] = sprintf(
345 _n(
346 '<span class="difference">%s</span> <span class="label">year to go.</span>',
347 '<span class="difference">%s</span> <span class="label">years to go.</span>',
348 $interval,
349 'jetpack'
350 ),
351 $interval_text
352 );
353 break;
354 case 'months':
355 $data['message'] = sprintf(
356 _n(
357 '<span class="difference">%s</span> <span class="label">month to go.</span>',
358 '<span class="difference">%s</span> <span class="label">months to go.</span>',
359 $interval,
360 'jetpack'
361 ),
362 $interval_text
363 );
364 break;
365 case 'days':
366 $data['message'] = sprintf(
367 _n(
368 '<span class="difference">%s</span> <span class="label">day to go.</span>',
369 '<span class="difference">%s</span> <span class="label">days to go.</span>',
370 $interval,
371 'jetpack'
372 ),
373 $interval_text
374 );
375 break;
376 case 'hours':
377 $data['message'] = sprintf(
378 _n(
379 '<span class="difference">%s</span> <span class="label">hour to go.</span>',
380 '<span class="difference">%s</span> <span class="label">hours to go.</span>',
381 $interval,
382 'jetpack'
383 ),
384 $interval_text
385 );
386 break;
387 case 'minutes':
388 $data['message'] = sprintf(
389 _n(
390 '<span class="difference">%s</span> <span class="label">minute to go.</span>',
391 '<span class="difference">%s</span> <span class="label">minutes to go.</span>',
392 $interval,
393 'jetpack'
394 ),
395 $interval_text
396 );
397 break;
398 case 'seconds':
399 $data['message'] = sprintf(
400 _n(
401 '<span class="difference">%s</span> <span class="label">second to go.</span>',
402 '<span class="difference">%s</span> <span class="label">seconds to go.</span>',
403 $interval,
404 'jetpack'
405 ),
406 $interval_text
407 );
408 break;
409 }
410 }
411 $data['message'] = '<div class="milestone-countdown">' . $data['message'] . '</div>';
412 }
413
414 return $data;
415 }
416
417 /**
418 * Return the largest possible time unit that the difference will be displayed in.
419 *
420 * @param Integer $seconds the interval in seconds
421 * @param String $maximum_unit the maximum unit that will be used. Optional.
422 * @return String $calculated_unit
423 */
424 protected function get_unit( $seconds, $maximum_unit = 'automatic' ) {
425 $unit = '';
426
427 if ( $seconds >= YEAR_IN_SECONDS * 2 ) {
428 // more than 2 years - show in years, one decimal point
429 $unit = 'years';
430
431 } else if ( $seconds >= YEAR_IN_SECONDS ) {
432 if ( 'years' === $maximum_unit ) {
433 $unit = 'years';
434 } else {
435 // automatic mode - showing months even if it's between one and two years
436 $unit = 'months';
437 }
438
439 } else if ( $seconds >= MONTH_IN_SECONDS * 3 ) {
440 // fewer than 2 years - show in months
441 $unit = 'months';
442
443 } else if ( $seconds >= MONTH_IN_SECONDS ) {
444 if ( 'months' === $maximum_unit ) {
445 $unit = 'months';
446 } else {
447 // automatic mode - showing days even if it's between one and three months
448 $unit = 'days';
449 }
450
451 } else if ( $seconds >= DAY_IN_SECONDS - 1 ) {
452 // fewer than a month - show in days
453 $unit = 'days';
454
455 } else if ( $seconds >= HOUR_IN_SECONDS - 1 ) {
456 // less than 1 day - show in hours
457 $unit = 'hours';
458
459 } else if ( $seconds >= MINUTE_IN_SECONDS - 1 ) {
460 // less than 1 hour - show in minutes
461 $unit = 'minutes';
462
463 } else {
464 // less than 1 minute - show in seconds
465 $unit = 'seconds';
466 }
467
468 $maximum_unit_index = array_search( $maximum_unit, $this->available_units );
469 $unit_index = array_search( $unit, $this->available_units );
470
471 if (
472 false === $maximum_unit_index // the maximum unit parameter is automatic
473 || $unit_index > $maximum_unit_index // there is not enough seconds for even one maximum time unit
474 ) {
475 return $unit;
476 }
477 return $maximum_unit;
478 }
479
480 /**
481 * Returns a time difference value in specified units.
482 *
483 * @param Integer $seconds
484 * @param String $units
485 * @return Integer|String $time_in_units
486 */
487 protected function get_interval_in_units( $seconds, $units ) {
488 switch ( $units ) {
489 case 'years':
490 $years = $seconds / YEAR_IN_SECONDS;
491 $decimals = abs( round( $years, 1 ) - round( $years ) ) > 0 ? 1 : 0;
492 return number_format_i18n( $years, $decimals );
493 case 'months':
494 return (int) ( $seconds / 60 / 60 / 24 / 30 );
495 case 'days':
496 return (int) ( $seconds / 60 / 60 / 24 + 1 );
497 case 'hours':
498 return (int) ( $seconds / 60 / 60 );
499 case 'minutes':
500 return (int) ( $seconds / 60 + 1 );
501 default:
502 return $seconds;
503 }
504 }
505
506 /**
507 * Update
508 */
509 function update( $new_instance, $old_instance ) {
510 return $this->sanitize_instance( $new_instance );
511 }
512
513 /*
514 * Make sure that a number is within a certain range.
515 * If the number is too small it will become the possible lowest value.
516 * If the number is too large it will become the possible highest value.
517 *
518 * @param int $n The number to check.
519 * @param int $floor The lowest possible value.
520 * @param int $ceil The highest possible value.
521 */
522 function sanitize_range( $n, $floor, $ceil ) {
523 $n = (int) $n;
524 if ( $n < $floor ) {
525 $n = $floor;
526 } elseif ( $n > $ceil ) {
527 $n = $ceil;
528 }
529 return $n;
530 }
531
532 /*
533 * Sanitize an instance of this widget.
534 *
535 * Date ranges match the documentation for mktime in the php manual.
536 * @see http://php.net/manual/en/function.mktime.php#refsect1-function.mktime-parameters
537 *
538 * @uses Milestone_Widget::sanitize_range().
539 */
540 function sanitize_instance( $dirty ) {
541 $now = (int) current_time( 'timestamp' );
542
543 $dirty = wp_parse_args( $dirty, array(
544 'title' => '',
545 'event' => __( 'The Big Day', 'jetpack' ),
546 'unit' => 'automatic',
547 'type' => 'until',
548 'message' => __( 'The big day is here.', 'jetpack' ),
549 'day' => date( 'd', $now ),
550 'month' => date( 'm', $now ),
551 'year' => date( 'Y', $now ),
552 'hour' => 0,
553 'min' => 0,
554 ) );
555
556 $allowed_tags = array(
557 'a' => array( 'title' => array(), 'href' => array(), 'target' => array() ),
558 'em' => array( 'title' => array() ),
559 'strong' => array( 'title' => array() ),
560 );
561
562 $clean = array(
563 'title' => trim( strip_tags( stripslashes( $dirty['title'] ) ) ),
564 'event' => trim( strip_tags( stripslashes( $dirty['event'] ) ) ),
565 'unit' => $dirty['unit'],
566 'type' => $dirty['type'],
567 'message' => wp_kses( $dirty['message'], $allowed_tags ),
568 'year' => $this->sanitize_range( $dirty['year'], 1901, 2037 ),
569 'month' => $this->sanitize_range( $dirty['month'], 1, 12 ),
570 'hour' => $this->sanitize_range( $dirty['hour'], 0, 23 ),
571 'min' => zeroise( $this->sanitize_range( $dirty['min'], 0, 59 ), 2 ),
572 );
573
574 $clean['day'] = $this->sanitize_range( $dirty['day'], 1, date( 't', mktime( 0, 0, 0, $clean['month'], 1, $clean['year'] ) ) );
575
576 return $clean;
577 }
578
579 /**
580 * Form
581 */
582 function form( $instance ) {
583 $instance = $this->sanitize_instance( $instance );
584
585 $units = array(
586 'automatic' => _x( 'Automatic', 'Milestone widget: mode in which the date unit is determined automatically', 'jetpack' ),
587 'years' => _x( 'Years', 'Milestone widget: mode in which the date unit is set to years', 'jetpack' ),
588 'months' => _x( 'Months', 'Milestone widget: mode in which the date unit is set to months', 'jetpack' ),
589 'days' => _x( 'Days', 'Milestone widget: mode in which the date unit is set to days', 'jetpack' ),
590 'hours' => _x( 'Hours', 'Milestone widget: mode in which the date unit is set to hours', 'jetpack' ),
591 );
592 ?>
593
594 <div class="milestone-widget">
595 <p>
596 <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title', 'jetpack' ); ?></label>
597 <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $instance['title'] ); ?>" />
598 </p>
599
600 <p>
601 <label for="<?php echo $this->get_field_id( 'event' ); ?>"><?php _e( 'Description', 'jetpack' ); ?></label>
602 <input class="widefat" id="<?php echo $this->get_field_id( 'event' ); ?>" name="<?php echo $this->get_field_name( 'event' ); ?>" type="text" value="<?php echo esc_attr( $instance['event'] ); ?>" />
603 </p>
604
605 <fieldset class="jp-ms-data-time">
606 <legend><?php esc_html_e( 'Date', 'jetpack' ); ?></legend>
607
608 <label for="<?php echo $this->get_field_id( 'month' ); ?>" class="assistive-text"><?php _e( 'Month', 'jetpack' ); ?></label>
609 <select id="<?php echo $this->get_field_id( 'month' ); ?>" class="month" name="<?php echo $this->get_field_name( 'month' ); ?>"><?php
610 global $wp_locale;
611 for ( $i = 1; $i < 13; $i++ ) {
612 $monthnum = zeroise( $i, 2 );
613 echo '<option value="' . esc_attr( $monthnum ) . '"' . selected( $i, $instance['month'], false ) . '>' . $monthnum . '-' . $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) ) . '</option>';
614 }
615 ?></select>
616
617 <label for="<?php echo $this->get_field_id( 'day' ); ?>" class="assistive-text"><?php _e( 'Day', 'jetpack' ); ?></label>
618 <input id="<?php echo $this->get_field_id( 'day' ); ?>" class="day" name="<?php echo $this->get_field_name( 'day' ); ?>" type="text" value="<?php echo esc_attr( $instance['day'] ); ?>">,
619
620 <label for="<?php echo $this->get_field_id( 'year' ); ?>" class="assistive-text"><?php _e( 'Year', 'jetpack' ); ?></label>
621 <input id="<?php echo $this->get_field_id( 'year' ); ?>" class="year" name="<?php echo $this->get_field_name( 'year' ); ?>" type="text" value="<?php echo esc_attr( $instance['year'] ); ?>">
622 </fieldset>
623
624 <fieldset class="jp-ms-data-time">
625 <legend><?php esc_html_e( 'Time', 'jetpack' ); ?></legend>
626
627 <label for="<?php echo $this->get_field_id( 'hour' ); ?>" class="assistive-text"><?php _e( 'Hour', 'jetpack' ); ?></label>
628 <input id="<?php echo $this->get_field_id( 'hour' ); ?>" class="hour" name="<?php echo $this->get_field_name( 'hour' ); ?>" type="text" value="<?php echo esc_attr( $instance['hour'] ); ?>">
629
630 <label for="<?php echo $this->get_field_id( 'min' ); ?>" class="assistive-text"><?php _e( 'Minutes', 'jetpack' ); ?></label>
631
632 <span class="time-separator">:</span>
633
634 <input id="<?php echo $this->get_field_id( 'min' ); ?>" class="minutes" name="<?php echo $this->get_field_name( 'min' ); ?>" type="text" value="<?php echo esc_attr( $instance['min'] ); ?>">
635 </fieldset>
636
637 <fieldset class="jp-ms-data-unit">
638 <legend><?php esc_html_e( 'Time Unit', 'jetpack' ); ?></legend>
639
640 <label for="<?php echo $this->get_field_id( 'unit' ); ?>" class="assistive-text">
641 <?php _e( 'Time Unit', 'jetpack' ); ?>
642 </label>
643 <select id="<?php echo $this->get_field_id( 'unit' ); ?>" class="unit" name="<?php echo $this->get_field_name( 'unit' ); ?>">
644 <?php
645 foreach ( $units as $key => $unit ) {
646 echo '<option value="' . esc_attr( $key ) . '"' . selected( $key, $instance['unit'], false ) . '>' . $unit . '</option>';
647 }
648 ?></select>
649 </fieldset>
650
651 <ul class="milestone-type">
652 <li>
653 <label>
654 <input
655 <?php checked( $instance['type'], 'until' ); ?>
656 name="<?php echo esc_attr( $this->get_field_name( 'type' ) ); ?>"
657 type="radio"
658 value="until"
659 />
660 <?php esc_html_e( 'Until your milestone', 'jetpack' ); ?>
661 </label>
662 </li>
663
664 <li>
665 <label>
666 <input
667 <?php checked( $instance['type'], 'since' ); ?>
668 name="<?php echo esc_attr( $this->get_field_name( 'type' ) ); ?>"
669 type="radio"
670 value="since"
671 />
672 <?php esc_html_e( 'Since your milestone', 'jetpack' ); ?>
673 </label>
674 </li>
675 </ul>
676
677 <p class="milestone-message-wrapper">
678 <label for="<?php echo $this->get_field_id( 'message' ); ?>"><?php _e( 'Milestone Reached Message', 'jetpack' ); ?></label>
679 <textarea id="<?php echo $this->get_field_id( 'message' ); ?>" name="<?php echo $this->get_field_name( 'message' ); ?>" class="widefat" rows="3"><?php echo esc_textarea( $instance['message'] ); ?></textarea>
680 </p>
681 </div>
682
683 <?php
684 }
685 }
686