Completed
Push — widgets/5493-additions ( dc56c0...74466f )
by George
321:30 queued 312:13
created

Milestone_Widget::__construct()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 13
nc 2
nop 0
dl 0
loc 21
rs 9.3142
c 0
b 0
f 0
1
<?php
2
/*
3
Plugin Name: Milestone
4
Description: Countdown to a specific date.
5
Version: 1.0
6
Author: Automattic
7
Author URI: http://automattic.com/
8
License: GPLv2 or later
9
*/
10
11
class Milestone_Widget extends WP_Widget {
12
	private static $dir       = null;
13
	private static $defaults  = null;
0 ignored issues
show
Unused Code introduced by
The property $defaults is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
14
	private static $config_js = null;
15
16
	function __construct() {
17
		$widget = array(
18
			'classname'   => 'milestone-widget',
19
			'description' => __( 'Display a countdown to a certain date.' )
20
		);
21
22
		$control = array(
23
			'width' => 251, // Chrome needs a little extra room for the date fields.
24
		);
25
26
		parent::__construct( 'Milestone_Widget', __( 'Milestone' ), $widget, $control );
27
28
		self::$dir = trailingslashit( __DIR__ );
29
30
		add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_template' ) );
31
		add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_admin' ) );
32
		add_action( 'wp_footer', array( __CLASS__, 'localize_script' ) );
33
34
		if ( is_active_widget( false, false, $this->id_base, true ) || is_active_widget( false, false, 'monster', true ) )
35
			add_action( 'wp_head', array( __CLASS__, 'styles_template' ) );
36
	}
37
38
	public static function enqueue_admin( $hook_suffix ) {
39
		if ( 'widgets.php' == $hook_suffix ) {
40
			wp_enqueue_style( 'milestone-admin', plugins_url( 'style-admin.css', __FILE__ ), array(), '20111212' );
41
			wp_style_add_data( 'milestone-admin', 'jetpack-inline', true );
42
		}
43
	}
44
45
	public static function enqueue_template() {
46
		wp_enqueue_script( 'milestone', plugins_url( 'milestone.js', __FILE__ ), array( 'jquery' ), '20160520', true );
47
	}
48
49
	public static function styles_template() {
50
		global $themecolors;
51
		$colors = wp_parse_args( $themecolors, array(
52
			'bg'     => 'fff',
53
			'border' => 'ccc',
54
			'text'   => '333',
55
		) );
56
?>
57
<style>
58
.milestone-widget {
59
	margin-bottom: 1em;
60
}
61
.milestone-content {
62
	line-height: 2;
63
	margin-top: 5px;
64
	max-width: 17em;
65
	padding: 0;
66
	text-align: center;
67
}
68
.milestone-header {
69
	background-color: #<?php echo sanitize_hex_color_no_hash( $colors['text'] ); ?>;
70
	color: #<?php echo sanitize_hex_color_no_hash( $colors['bg'] ); ?>;
71
	line-height: 1.3;
72
	margin: 0;
73
	padding: .8em;
74
}
75
.milestone-header .event,
76
.milestone-header .date {
77
	display: block;
78
}
79
.milestone-header .event {
80
	font-size: 120%;
81
}
82
.milestone-countdown .difference {
83
	display: block;
84
	font-size: 500%;
85
	font-weight: bold;
86
	line-height: 1.2;
87
}
88
.milestone-countdown,
89
.milestone-message {
90
	background-color: #<?php echo sanitize_hex_color_no_hash( $colors['bg'] ); ?>;
91
	border: 1px solid #<?php echo sanitize_hex_color_no_hash( $colors['border'] ); ?>;
92
	border-top: 0;
93
	color: #<?php echo sanitize_hex_color_no_hash( $colors['text'] ); ?>;
94
	padding-bottom: 1em;
95
}
96
.milestone-message {
97
	padding-top: 1em
98
}
99
</style>
100
<?php
101
	}
102
103
	/**
104
	 * Localize Front-end Script.
105
	 *
106
	 * Print the javascript configuration array only if the
107
	 * current template has an instance of the widget that
108
	 * is still counting down. In all other cases, this
109
	 * function will dequeue milestone.js.
110
	 *
111
	 * Hooks into the "wp_footer" action.
112
	 */
113
	function localize_script() {
114
		if ( empty( self::$config_js['instances'] ) ) {
115
			wp_dequeue_script( 'milestone' );
116
			return;
117
		}
118
119
		wp_localize_script( 'milestone', 'MilestoneConfig', array(
120
			'instances'         => self::$config_js['instances'],
121
			'labels'            => self::get_interval_labels(),
122
			'MINUTE_IN_SECONDS' => MINUTE_IN_SECONDS,
123
			'HOUR_IN_SECONDS'   => HOUR_IN_SECONDS,
124
			'DAY_IN_SECONDS'    => DAY_IN_SECONDS,
125
			'WEEK_IN_SECONDS'   => WEEK_IN_SECONDS,
126
			'MONTH_IN_SECONDS'  => MONTH_IN_SECONDS,
127
			'YEAR_IN_SECONDS'   => YEAR_IN_SECONDS,
128
		) );
129
	}
130
131
	/**
132
	 * Widget
133
	 */
134
	function widget( $args, $instance ) {
135
		$instance = $this->sanitize_instance( $instance );
136
137
		$milestone = mktime( $instance['hour'], $instance['min'], 0, $instance['month'], $instance['day'], $instance['year'] );
138
		$now  = (int) current_time( 'timestamp' );
139
		$diff = (int) floor( $milestone - $now );
140
141
		$number = 0;
0 ignored issues
show
Unused Code introduced by
$number is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
142
		$label  = '';
0 ignored issues
show
Unused Code introduced by
$label is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
143
		$interval_labels = self::get_interval_labels();
144
145
		if ( 2 * YEAR_IN_SECONDS <= $diff ) { // more than 2 years - show in years, one decimal point
146
			$number = round( $diff / YEAR_IN_SECONDS, 1 );
147
			$label  = $interval_labels['years'];
148
		} else if ( 3 * MONTH_IN_SECONDS <= $diff ) { // fewer than 2 years - show in months
149
			$number = floor( $diff / MONTH_IN_SECONDS );
150
			$label  = ( 1 == $number ) ? $interval_labels['month'] : $interval_labels['months'];
151
		} else if ( DAY_IN_SECONDS <= $diff ) { // fewer than 3 months - show in days
152
			$number = floor( $diff / DAY_IN_SECONDS ) + 1;
153
			$label  = ( 1 == $number ) ? $interval_labels['day'] : $interval_labels['days'];
154
		} else if ( HOUR_IN_SECONDS <= $diff ) { // less than 1 day - show in hours
155
			$number = floor( $diff / HOUR_IN_SECONDS );
156
			$label  = ( 1 == $number ) ? $interval_labels['hour'] : $interval_labels['hours'];
157
		} else if ( MINUTE_IN_SECONDS <= $diff ) { // less than 1 hour - show in minutes
158
			$number = floor( $diff / MINUTE_IN_SECONDS ) + 1;
159
			$label = ( 1 == $number ) ? $interval_labels['minute'] : $interval_labels['minutes'];
160
		} else { // less than 1 minute - show in seconds
161
			$number = $diff;
162
			$label = ( 1 == $number ) ? $interval_labels['second'] : $interval_labels['seconds'] ;
163
		}
164
165
		echo $args['before_widget'];
166
167
		$title = apply_filters( 'widget_title', $instance['title'] );
168
		if ( ! empty( $title ) ) {
169
			echo $args['before_title'] . $title . $args['after_title'];
170
		}
171
172
		echo '<div class="milestone-content">';
173
174
		echo '<div class="milestone-header">';
175
		echo '<strong class="event">' . esc_html( $instance['event'] ) . '</strong>';
176
		echo '<span class="date">' . esc_html( date_i18n( __( 'F jS, Y' ), $milestone ) ) . '</span>';
177
		echo '</div>';
178
179
		if ( 1 > $diff ) {
180
			/* Milestone has past. */
181
			echo '<div class="milestone-message">' . $instance['message'] . '</div>';
182
		} else {
183
			/* Countdown to the milestone. */
184
			echo '<div class="milestone-countdown">' . sprintf( __( '%1$s %2$s to go.' ),
185
				'<span class="difference">' . esc_html( $number ) . '</span>',
186
				'<span class="label">' . esc_html( $label ) . '</span>'
187
			) . '</div>';
188
189
			self::$config_js['instances'][] = array(
190
				'id'      => $args['widget_id'],
191
				'diff'    => $diff,
192
				'message' => $instance['message'],
193
			);
194
		}
195
196
		echo '</div><!--milestone-content-->';
197
198
		echo $args['after_widget'];
199
		if ( method_exists( 'stats_extra' ) ) {
200
			stats_extra( 'widget_view', 'milestone' );
201
		}
202
	}
203
204
	/**
205
	 * Update
206
	 */
207
	function update( $new_instance, $old_instance ) {
208
		return $this->sanitize_instance( $new_instance );
209
	}
210
211
	/*
212
	 * Make sure that a number is within a certain range.
213
	 * If the number is too small it will become the possible lowest value.
214
	 * If the number is too large it will become the possible highest value.
215
	 *
216
	 * @param int $n The number to check.
217
	 * @param int $floor The lowest possible value.
218
	 * @param int $ceil The highest possible value.
219
	 */
220
	function sanitize_range( $n, $floor, $ceil ) {
221
		$n = (int) $n;
222
		if ( $n < $floor ) {
223
			$n = $floor;
224
		} elseif ( $n > $ceil ) {
225
			$n = $ceil;
226
		}
227
		return $n;
228
	}
229
230
	/*
231
	 * Sanitize an instance of this widget.
232
	 *
233
	 * Date ranges match the documentation for mktime in the php manual.
234
	 * @see http://php.net/manual/en/function.mktime.php#refsect1-function.mktime-parameters
235
	 *
236
	 * @uses Milestone_Widget::sanitize_range().
237
	 */
238
	function sanitize_instance( $dirty ) {
239
		$now = (int) current_time( 'timestamp' );
240
241
		$dirty = wp_parse_args( $dirty, array(
242
			'title'   => '',
243
			'event'   => __( 'The Big Day' ),
244
			'message' => __( 'The big day is here.' ),
245
			'day'     => date( 'd', $now ),
246
			'month'   => date( 'm', $now ),
247
			'year'    => date( 'Y', $now ),
248
			'hour'    => 0,
249
			'min'     => 0,
250
		) );
251
252
		$allowed_tags = array(
253
			'a'      => array( 'title' => array(), 'href' => array() ),
254
			'em'     => array( 'title' => array() ),
255
			'strong' => array( 'title' => array() ),
256
		);
257
258
		$clean = array(
259
			'title'   => trim( strip_tags( stripslashes( $dirty['title'] ) ) ),
260
			'event'   => trim( strip_tags( stripslashes( $dirty['event'] ) ) ),
261
			'message' => wp_kses( $dirty['message'], $allowed_tags ),
262
			'year'    => $this->sanitize_range( $dirty['year'],  1901, 2037 ),
263
			'month'   => $this->sanitize_range( $dirty['month'], 1, 12 ),
264
			'hour'    => $this->sanitize_range( $dirty['hour'],  0, 23 ),
265
			'min'     => zeroise( $this->sanitize_range( $dirty['min'], 0, 59 ), 2 ),
266
		);
267
268
		$clean['day'] = $this->sanitize_range( $dirty['day'], 1, date( 't', mktime( 0, 0, 0, $clean['month'], 1, $clean['year'] ) ) );
269
270
		return $clean;
271
	}
272
273
	/**
274
	 * Form
275
	 */
276
	function form( $instance ) {
277
		$instance = $this->sanitize_instance( $instance );
278
		?>
279
280
	<div class="milestone-widget">
281
		<p>
282
			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title' ); ?></label>
283
			<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'] ); ?>" />
284
		</p>
285
286
		<p>
287
			<label for="<?php echo $this->get_field_id( 'event' ); ?>"><?php _e( 'Event' ); ?></label>
288
			<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'] ); ?>" />
289
		</p>
290
291
		<fieldset>
292
			<legend><?php _e( 'Date and Time' ); ?></legend>
293
294
			<label for="<?php echo $this->get_field_id( 'month' ); ?>" class="assistive-text"><?php _e( 'Month' ); ?></label>
295
			<select id="<?php echo $this->get_field_id( 'month' ); ?>" class="month" name="<?php echo $this->get_field_name( 'month' ); ?>">
296
				<?php
297
				global $wp_locale;
298
				for ( $i = 1; $i <= 12; $i++ ) {
299
					$monthnum = zeroise( $i, 2 );
300
					echo '<option value="' . esc_attr( $monthnum ) . '"' . selected( $i, $instance['month'], false ) . '>' . $monthnum . '-' . $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) ) . '</option>';
301
				}
302
				?>
303
			</select>
304
305
			<label for="<?php echo $this->get_field_id( 'day' ); ?>" class="assistive-text"><?php _e( 'Day' ); ?></label>
306
			<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'] ); ?>">,
307
308
			<label for="<?php echo $this->get_field_id( 'year' ); ?>" class="assistive-text"><?php _e( 'Year' ); ?></label>
309
			<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'] ); ?>">
310
311
			@ <label for="<?php echo $this->get_field_id( 'hour' ); ?>" class="assistive-text"><?php _e( 'Hour' ); ?></label>
312
			<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'] ); ?>">
313
314
			<label for="<?php echo $this->get_field_id( 'min' ); ?>" class="assistive-text"><?php _e( 'Minutes' ); ?></label>
315
			: <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'] ); ?>">
316
		</fieldset>
317
318
		<p>
319
			<label for="<?php echo $this->get_field_id( 'message' ); ?>"><?php _e( 'Message' ); ?></label>
320
			<textarea id="<?php echo $this->get_field_id( 'message' ); ?>" name="<?php echo $this->get_field_name( 'message' ); ?>" class="widefat"><?php echo esc_textarea( $instance['message'] ); ?></textarea>
321
		</p>
322
	</div>
323
324
		<?php
325
	}
326
327
	/**
328
	 * Cache the translations, but do it on-demand so it's
329
	 * not run every page load whether used or not.
330
	 *
331
	 * @return array
332
	 */
333
	public static function get_interval_labels() {
334
		static $labels = null;
335
336
		// Static variables can't be initialized to arrays on declaration, so we do it here:
337
		if ( is_null( $labels ) ) {
338
			$labels = array(
339
				'year'    => __( 'year' ),
340
				'years'   => __( 'years' ),
341
				'month'   => __( 'month' ),
342
				'months'  => __( 'months' ),
343
				'day'     => __( 'day' ),
344
				'days'    => __( 'days' ),
345
				'hour'    => __( 'hour' ),
346
				'hours'   => __( 'hours' ),
347
				'minute'  => __( 'minute' ),
348
				'minutes' => __( 'minutes' ),
349
				'second'  => __( 'second' ),
350
				'seconds' => __( 'seconds' ),
351
			);
352
		}
353
354
		return $labels;
355
	}
356
}
357
358
add_action( 'widgets_init', 'register_milestone_widget' );
359
function register_milestone_widget() {
360
	register_widget( 'Milestone_Widget' );
361
}
362