Twitter Widget Pro - Version 1.0.0

Version Description

Download this release

Release Info

Developer aaroncampbell
Plugin Icon wp plugin Twitter Widget Pro
Version 1.0.0
Comparing to
See all releases

Version 1.0.0

Files changed (2) hide show
  1. readme.txt +33 -0
  2. wp-twitter-widget.php +534 -0
readme.txt ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Twitter Widget Pro ===
2
+ Contributors: aaroncampbell
3
+ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=paypal%40xavisys%2ecom&item_name=Twitter%20Widget%20Pro&no_shipping=0&no_note=1&tax=0&currency_code=USD&lc=US&bn=PP%2dDonationsBF&charset=UTF%2d8
4
+ Tags: twitter, widget, feed
5
+ Requires at least: 2.5
6
+ Tested up to: 2.5.1
7
+ Stable tag: 1.0.0
8
+
9
+ A widget that properly handles twitter feeds (singlue user or including friends), including parsing @username and URLs into links. Requires PHP5.
10
+
11
+ == Description ==
12
+
13
+ A widget that properly handles twitter feeds, including @username and link
14
+ parsing. Feeds can be for a single user, or can include all their friends'
15
+ tweets as well (like their Twitter home page does). It supports displaying
16
+ profiles images, and even lets you control whether to display the time and date
17
+ of a tweet or how log ago it happened (about 5 hours ago, etc). Requires PHP5.
18
+
19
+ == Installation ==
20
+
21
+ 1. Verify that you have PHP5, which is required for this plugin.
22
+ 1. Upload the whole `twitter-widget-pro` directory to the `/wp-content/plugins/` directory
23
+ 1. Activate the plugin through the 'Plugins' menu in WordPress
24
+
25
+ == Frequently Asked Questions ==
26
+
27
+ = Can I have use than one instance of this widget? =
28
+
29
+ Yes, Twitter Widget Pro employs the multi-widget pattern, which allows you to not only have more than one instance of this widget on your site, but even allows more than one instance of this widget in a single sidebar.
30
+
31
+ = Can I follow more than one feed? =
32
+
33
+ Absolutely, each instance of the widget can have different settings and track different feeds.
wp-twitter-widget.php ADDED
@@ -0,0 +1,534 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Plugin Name: Twitter Widget Pro
4
+ * Plugin URI: http://xavisys.com/wordpress-twitter-widget/
5
+ * Description: A widget that properly handles twitter feeds, including @username and link parsing, feeds that include friends or just one user, and can even display profile images for the users. Requires PHP5.
6
+ * Version: 1.0.0
7
+ * Author: Aaron D. Campbell
8
+ * Author URI: http://xavisys.com/
9
+ */
10
+
11
+ /**
12
+ * Changelog:
13
+ * 04/17/2008: 1.0.0
14
+ * - Released to wordpress.org repository
15
+ *
16
+ * 04/14/2008: 0.0.3
17
+ * - Fixed some of the settings used with Snoopy
18
+ * - Set a read timeout for fetching the files
19
+ *
20
+ * 04/14/2008: 0.0.2
21
+ * - Changed some function names
22
+ * - Moved form display to a separate function (_showForm)
23
+ * - Now uses wp_parse_args to handle defaults
24
+ * - Added comments
25
+ * - Added seconds to the _timeSince function so you can have something like "about 25 seconds ago"
26
+ *
27
+ * 04/11/2008: 0.0.1
28
+ * - Original Version
29
+ */
30
+
31
+ /* Copyright 2006 Aaron D. Campbell (email : wp_plugins@xavisys.com)
32
+
33
+ This program is free software; you can redistribute it and/or modify
34
+ it under the terms of the GNU General Public License as published by
35
+ the Free Software Foundation; either version 2 of the License, or
36
+ (at your option) any later version.
37
+
38
+ This program is distributed in the hope that it will be useful,
39
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
40
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41
+ GNU General Public License for more details.
42
+
43
+ You should have received a copy of the GNU General Public License
44
+ along with this program; if not, write to the Free Software
45
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46
+ */
47
+ /**
48
+ * wpTwitterWidget is the class that handles ALL of the plugin functionality.
49
+ * It helps us avoid name collisions
50
+ * http://codex.wordpress.org/Writing_a_Plugin#Avoiding_Function_Name_Collisions
51
+ */
52
+
53
+ class wpTwitterWidget
54
+ {
55
+ /**
56
+ * User Agent to send when requesting the feeds
57
+ *
58
+ * @var string
59
+ */
60
+ private $userAgent;
61
+
62
+ /**
63
+ * Read timeout to use when fetching the feeds. Defaults to 2 seconds.
64
+ *
65
+ * @todo make a set function for this
66
+ *
67
+ * @var int
68
+ */
69
+ private $fetchTimeOut = 2;
70
+
71
+ /**
72
+ * Whether to use GZip when fetching feeds. Defaults to true
73
+ *
74
+ * @todo make a set function for this
75
+ *
76
+ * @var bool
77
+ */
78
+ private $useGzip = true;
79
+
80
+ public function __construct() {
81
+ // Set the user agent to Wordpress/x.x.x
82
+ $this->userAgent = 'WordPress/' . $GLOBALS['wp_version'];
83
+ }
84
+
85
+ /**
86
+ * Pulls the JSON feed from Twitter and returns an array of objects
87
+ *
88
+ * @param array $widgetOptions - settings needed to get feed url, etc
89
+ * @return array
90
+ */
91
+ private function _parseFeed($widgetOptions) {
92
+ $feedUrl = $this->_getFeedUrl($widgetOptions);
93
+ $resp = $this->_fetch_remote_file($feedUrl);
94
+ if ( $resp->status >= 200 && $resp->status < 300 ) {
95
+ return json_decode($resp->results);
96
+ } else {
97
+ // Failed to fetch url;
98
+ return array();
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Gets the URL for the desired feed.
104
+ *
105
+ * @param array $widgetOptions - settings needed such as username, feet type, etc
106
+ * @param string[optional] $type - 'rss' or 'json'
107
+ * @param bool[optional] $count - If true, it adds the count parameter to the URL
108
+ * @return string - Twitter feed URL
109
+ */
110
+ private function _getFeedUrl($widgetOptions, $type = 'json', $count = true) {
111
+ if (!in_array($type, array('rss', 'json'))) {
112
+ $type = 'json';
113
+ }
114
+ if ($count) {
115
+ $count = sprintf('?count=%u', $widgetOptions['items']);
116
+ } else {
117
+ $count = '';
118
+ }
119
+ return sprintf('http://twitter.com/statuses/%1$s_timeline/%2$s.%3$s%4$s',$widgetOptions['feed'], $widgetOptions['username'], $type, $count);
120
+ }
121
+
122
+ /**
123
+ * Replace @username with a link to that twitter user
124
+ *
125
+ * @param string $text - Tweet text
126
+ * @return string - Tweet text with @replies linked
127
+ */
128
+ public function linkTwitterUsers($text) {
129
+ $text = preg_replace('/(^|\s)@(\w*)(\s|$)/i', '$1@<a href="http://twitter.com/$2" class="twitter-user">$2</a>$3', $text);
130
+ return $text;
131
+ }
132
+
133
+ /**
134
+ * Turn URLs into links
135
+ *
136
+ * @param string $text - Tweet text
137
+ * @return string - Tweet text with URLs repalced with links
138
+ */
139
+ public function linkUrls($text) {
140
+ /**
141
+ * match protocol://address/path/file.extension?some=variable&another=asf%
142
+ * $1 is a possible space, this keeps us from linking href="[link]" etc
143
+ * $2 is the whole URL
144
+ * $3 is protocol://
145
+ * $4 is the URL without the protocol://
146
+ * $5 is the URL parameters
147
+ */
148
+ $text = preg_replace("/(^|\s)(([a-zA-Z]+:\/\/)([a-z][a-z0-9_\..-]*[a-z]{2,6})([a-zA-Z0-9\/*-?&%]*))/i", "$1<a href=\"$2\">$2</a>", $text);
149
+
150
+ /**
151
+ * match www.something.domain/path/file.extension?some=variable&another=asf%
152
+ * $1 is a possible space, this keeps us from linking href="[link]" etc
153
+ * $2 is the whole URL that was matched. The protocol is missing, so we assume http://
154
+ * $3 is www.
155
+ * $4 is the URL matched without the www.
156
+ * $5 is the URL parameters
157
+ */
158
+ $text = preg_replace("/(^|\s)(www\.([a-z][a-z0-9_\..-]*[a-z]{2,6})([a-zA-Z0-9\/*-?&%]*))/i", "$1<a href=\"http://$2\">$2</a>", $text);
159
+
160
+ return $text;
161
+ }
162
+
163
+ /**
164
+ * Uses snoopy class to pull file contents
165
+ *
166
+ * @param string $url - Url to get
167
+ * @param array $headers - Raw headers to pass
168
+ * @return Snoopy
169
+ */
170
+ private function _fetch_remote_file ($url, $headers = "" ) {
171
+ require_once( ABSPATH . 'wp-includes/class-snoopy.php' );
172
+ // Snoopy is an HTTP client in PHP
173
+ $client = new Snoopy();
174
+ $client->agent = $this->userAgent;
175
+ $client->read_timeout = $this->fetchTimeOut;
176
+ $client->use_gzip = $this->useGzip;
177
+ if (is_array($headers) ) {
178
+ $client->rawheaders = $headers;
179
+ }
180
+
181
+ @$client->fetch($url);
182
+ return $client;
183
+ }
184
+
185
+ /**
186
+ * Gets tweets, from cache if possible
187
+ *
188
+ * @param array $widgetOptions - options needed to get feeds
189
+ * @return array - Array of objects
190
+ */
191
+ private function _getTweets($widgetOptions) {
192
+ // Get cache of feed if it exists
193
+ $tweets = wp_cache_get($widgetOptions['feed'] . $widgetOptions['username'], 'widget_twitter');
194
+ // If there is no cache
195
+ if ($tweets == false) {
196
+ $tweets = $this->_parseFeed($widgetOptions);
197
+ // Cache for 60 seconds, Tweets are supposed to be current, so we don't cache for very long
198
+ wp_cache_set($widgetOptions['feed'] . $widgetOptions['username'], $tweets, 'widget_twitter', 60);
199
+ }
200
+ return $tweets;
201
+ }
202
+
203
+ /**
204
+ * Displays the Twitter widget, with all tweets in an unordered list.
205
+ * Things are classed but not styled to allow easy styling.
206
+ *
207
+ * @param array $args - Widget Settings
208
+ * @param array|int $widget_args - Widget Number
209
+ */
210
+ public function display($args, $widget_args = 1) {
211
+ extract( $args, EXTR_SKIP );
212
+ if ( is_numeric($widget_args) )
213
+ $widget_args = array( 'number' => $widget_args );
214
+ $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
215
+ extract( $widget_args, EXTR_SKIP );
216
+
217
+ $options = get_option('widget_twitter');
218
+ if ( !isset($options[$number]) ) {
219
+ return;
220
+ }
221
+
222
+ // Validate our options
223
+ if (!isset($options[$number]['feed']) || !in_array($options[$number]['feed'], array('user', 'friends'))) {
224
+ $options[$number]['feed'] = 'user';
225
+ }
226
+ $options[$number]['items'] = (int) $options[$number]['items'];
227
+ if ( $options[$number]['items'] < 1 || 20 < $options[$number]['items'] ) {
228
+ $options[$number]['items'] = 10;
229
+ }
230
+ if (!isset($options[$number]['showts'])) {
231
+ $options[$number]['showts'] = 86400;
232
+ }
233
+
234
+ $options[$number]['avatar'] = (isset($options[$number]['avatar']) && $options[$number]['avatar']);
235
+
236
+ $tweets = $this->_getTweets($options[$number]);
237
+ $tweets = array_slice($tweets, 0, $options[$number]['items']);
238
+
239
+ echo $before_widget;
240
+ if ( file_exists(dirname(__FILE__) . '/rss.png') ) {
241
+ $icon = str_replace(ABSPATH, get_option('siteurl').'/', dirname(__FILE__)) . '/rss.png';
242
+ } else {
243
+ $icon = get_option('siteurl').'/wp-includes/images/rss.png';
244
+ }
245
+ $feedUrl = $this->_getFeedUrl($options[$number], 'rss', false);
246
+ $before_title .= "<a class='twitterwidget' href='{$feedUrl}' title='" . attribute_escape(__('Syndicate this content')) ."'><img style='background:orange;color:white;border:none;' width='14' height='14' src='{$icon}' alt='RSS' /></a>";
247
+ if (!empty($tweets)) {
248
+ $twitterLink = 'http://twitter.com/' . $tweets[0]->user->screen_name;
249
+ $before_title .= " <a class='twitterwidget' href='$twitterLink' title='" . attribute_escape("Twitter: {$tweets[0]->user->name}") . "'>";
250
+ $after_title = '</a>' . $after_title;
251
+ }
252
+ if ( !empty( $options[$number]['title'] ) ) { echo $before_title . $options[$number]['title'] . $after_title; } ?>
253
+ <ul><?php
254
+ if ( $options[$number]['feed'] == 'user' && !empty($tweets) ) {
255
+ echo '<li>';
256
+ if ( $options[$number]['avatar']) {
257
+ echo $this->_getProfileImage($tweets[0]->user);
258
+ }
259
+ echo '<div class="clear" />';
260
+ echo '</li>';
261
+ }
262
+ foreach ($tweets as $tweet) {
263
+ // Set our "ago" string which converts the date to "# ___(s) ago"
264
+ $tweet->ago = $this->_timeSince(strtotime($tweet->created_at), $options[$number]['showts']);
265
+ ?>
266
+ <li>
267
+ <?php
268
+ if ( $options[$number]['feed'] == 'friends' ) {
269
+ if ( $options[$number]['avatar']) {
270
+ echo $this->_getProfileImage($tweet->user);
271
+ }
272
+ echo $this->_getUserName($tweet->user);
273
+ }
274
+ ?>
275
+ <span class="entry-content"><?php echo apply_filters( 'widget_twitter_content', $tweet->text ); ?></span>
276
+ <span class="entry-meta">
277
+ <a href="http://twitter.com/<?php echo $tweet->user->screen_name; ?>/statuses/<?php echo $tweet->id; ?>">
278
+ <?php echo $tweet->ago; ?>
279
+ </a> from <?php
280
+ echo $tweet->source;
281
+ if (isset($tweet->in_reply_to)) {
282
+ echo $this->_getReplyTo($tweet->in_reply_to);
283
+ } ?>
284
+ </span>
285
+ </li>
286
+ <?php
287
+ } ?></ul>
288
+ <?php echo $after_widget; ?>
289
+ <?php
290
+ }
291
+
292
+ /**
293
+ * Returns a "in reply to" link to the user passed
294
+ *
295
+ * @param object $replyTo - Tweet
296
+ * @return string - Link to Twitter user (XHTML)
297
+ */
298
+ private function _getReplyTo($replyTo) {
299
+ return <<<replyTo
300
+ <a href="http://twitter.com/{$replyTo->user->screen_name}/statuses/{$replyTo->id}">
301
+ in reply to {$replyTo->user->screen_name}
302
+ </a>
303
+ replyTo;
304
+ }
305
+
306
+ /**
307
+ * Returns the Twitter user's profile image, linked to that user's profile
308
+ *
309
+ * @param object $user - Twitter User
310
+ * @return string - Linked image (XHTML)
311
+ */
312
+ private function _getProfileImage($user) {
313
+ return <<<profileImage
314
+ <a title="{$user->name}" href="http://twitter.com/{$user->screen_name}">
315
+ <img alt="{$user->name}" src="{$user->profile_image_url}" />
316
+ </a>
317
+ profileImage;
318
+ }
319
+
320
+ /**
321
+ * Returns the user's screen name as a link inside strong tags.
322
+ *
323
+ * @param object $user - Twitter user
324
+ * @return string - Username as link (XHTML)
325
+ */
326
+ private function _getUserName($user) {
327
+ return <<<profileImage
328
+ <strong>
329
+ <a title="{$user->name}" href="http://twitter.com/{$user->screen_name}">{$user->screen_name}</a>
330
+ </strong>
331
+ profileImage;
332
+ }
333
+
334
+ /**
335
+ * Sets up admin forms to manage widgets
336
+ *
337
+ * @param array|int $widget_args - Widget Number
338
+ */
339
+ public function control($widget_args) {
340
+ global $wp_registered_widgets;
341
+ static $updated = false;
342
+
343
+ if ( is_numeric($widget_args) )
344
+ $widget_args = array( 'number' => $widget_args );
345
+ $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
346
+ extract( $widget_args, EXTR_SKIP );
347
+
348
+ $options = get_option('widget_twitter');
349
+ if ( !is_array($options) )
350
+ $options = array();
351
+
352
+ if ( !$updated && !empty($_POST['sidebar']) ) {
353
+ $sidebar = (string) $_POST['sidebar'];
354
+
355
+ $sidebars_widgets = wp_get_sidebars_widgets();
356
+ if ( isset($sidebars_widgets[$sidebar]) )
357
+ $this_sidebar =& $sidebars_widgets[$sidebar];
358
+ else
359
+ $this_sidebar = array();
360
+
361
+ foreach ( $this_sidebar as $_widget_id ) {
362
+ if ( array($this,'display') == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) {
363
+ $widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
364
+ if ( !in_array( "twitter-$widget_number", $_POST['widget-id'] ) ) // the widget has been removed.
365
+ unset($options[$widget_number]);
366
+ }
367
+ }
368
+
369
+ foreach ( (array) $_POST['widget-twitter'] as $widget_number => $widget_twitter ) {
370
+ if ( !isset($widget_twitter['username']) && isset($options[$widget_number]) ) // user clicked cancel
371
+ continue;
372
+ $widget_twitter['title'] = strip_tags(stripslashes($widget_twitter['title']));
373
+ $options[$widget_number] = $widget_twitter;
374
+ }
375
+
376
+ update_option('widget_twitter', $options);
377
+ $updated = true;
378
+ }
379
+
380
+ if ( -1 != $number ) {
381
+ $options[$number]['number'] = $number;
382
+ $options[$number]['title'] = attribute_escape($options[$number]['title']);
383
+ $options[$number]['username'] = attribute_escape($options[$number]['username']);
384
+ $options[$number]['avatar'] = (bool) $options[$number]['avatar'];
385
+ if (!isset($options[$number]['feed']) || !in_array($options[$number]['feed'], array('user', 'friends'))) {
386
+ $options[$number]['feed'] = 'user';
387
+ }
388
+ }
389
+ $this->_showForm($options[$number]);
390
+ }
391
+
392
+ /**
393
+ * Registers widget in such a way as to allow multiple instances of it
394
+ *
395
+ * @see wp-includes/widgets.php
396
+ */
397
+ public function register() {
398
+ if ( !$options = get_option('widget_twitter') )
399
+ $options = array();
400
+ $widget_ops = array('classname' => 'widget_twitter', 'description' => __('Follow a Twitter Feed'));
401
+ $control_ops = array('width' => 400, 'height' => 350, 'id_base' => 'twitter');
402
+ $name = __('Twitter Feed');
403
+
404
+ $id = false;
405
+ foreach ( array_keys($options) as $o ) {
406
+ // Old widgets can have null values for some reason
407
+ if ( !isset($options[$o]['title']) || !isset($options[$o]['username']) )
408
+ continue;
409
+ $id = "twitter-$o"; // Never never never translate an id
410
+ wp_register_sidebar_widget($id, $name, array($this,'display'), $widget_ops, array( 'number' => $o ));
411
+ wp_register_widget_control($id, $name, array($this,'control'), $control_ops, array( 'number' => $o ));
412
+ }
413
+
414
+ // If there are none, we register the widget's existance with a generic template
415
+ if ( !$id ) {
416
+ wp_register_sidebar_widget( 'twitter-1', $name, array($this,'display'), $widget_ops, array( 'number' => -1 ) );
417
+ wp_register_widget_control( 'twitter-1', $name, array($this,'control'), $control_ops, array( 'number' => -1 ) );
418
+ }
419
+ }
420
+
421
+ /**
422
+ * Displays the actualy for that populates the widget options box in the
423
+ * admin section
424
+ *
425
+ * @param array $args - Current widget settings and widget number, gets combind with defaults
426
+ */
427
+ private function _showForm($args) {
428
+
429
+ $defaultArgs = array( 'title' => '',
430
+ 'username' => '',
431
+ 'avatar' => false,
432
+ 'feed' => 'user',
433
+ 'items' => 10,
434
+ 'showts' => 60 * 60 * 24,
435
+ 'number' => '%i%' );
436
+ $args = wp_parse_args( $args, $defaultArgs );
437
+ extract( $args );
438
+ ?>
439
+ <p>
440
+ <label for="twitter-username-<?php echo $number; ?>"><?php _e('Twitter username:'); ?></label>
441
+ <input class="widefat" id="twitter-username-<?php echo $number; ?>" name="widget-twitter[<?php echo $number; ?>][username]" type="text" value="<?php echo $username; ?>" />
442
+ </p>
443
+ <p>
444
+ <label for="twitter-title-<?php echo $number; ?>"><?php _e('Give the feed a title (optional):'); ?></label>
445
+ <input class="widefat" id="twitter-title-<?php echo $number; ?>" name="widget-twitter[<?php echo $number; ?>][title]" type="text" value="<?php echo $title; ?>" />
446
+ <input type="hidden" name="widget-twitter[<?php echo $number; ?>][submit]" value="1" />
447
+ </p>
448
+ <p>
449
+ <label for="twitter-items-<?php echo $number; ?>"><?php _e('How many items would you like to display?'); ?></label>
450
+ <select id="twitter-items-<?php echo $number; ?>" name="widget-twitter[<?php echo $number; ?>][items]">
451
+ <?php
452
+ for ( $i = 1; $i <= 20; ++$i ) {
453
+ echo "<option value='$i' ", selected($items, $i), ">$i</option>";
454
+ }
455
+ ?>
456
+ </select>
457
+ </p>
458
+ <p>
459
+ <label for="twitter-showts-<?php echo $number; ?>"><?php _e('Show date/time of Tweet (rather than 2 ____ ago):'); ?></label>
460
+ <select id="twitter-showts-<?php echo $number; ?>" name="widget-twitter[<?php echo $number; ?>][showts]">
461
+ <option value="0" <?php echo selected($showts, '0'); ?>>Always</a>
462
+ <option value="3600" <?php echo selected($showts, '3600'); ?>>If over an hour old</a>
463
+ <option value="86400" <?php echo selected($showts, '86400'); ?>>If over a day old</a>
464
+ <option value="604800" <?php echo selected($showts, '604800'); ?>>If over a week old</a>
465
+ <option value="2592000" <?php echo selected($showts, '2592000'); ?>>If over a month old</a>
466
+ <option value="31536000" <?php echo selected($showts, '31536000'); ?>>If over a year old</a>
467
+ <option value="-1" <?php echo selected($showts, '-1'); ?>>Never</a>
468
+ </select>
469
+ </p>
470
+ <p>
471
+ <label for="twitter-feed-<?php echo $number; ?>-user"><input class="checkbox" type="radio" id="twitter-feed-<?php echo $number; ?>-user" name="widget-twitter[<?php echo $number; ?>][feed]" value="user"<?php checked($feed, 'user'); ?> /> <?php _e('Just User'); ?></label><br />
472
+ <label for="twitter-feed-<?php echo $number; ?>-friends"><input class="checkbox" type="radio" id="twitter-feed-<?php echo $number; ?>-friends" name="widget-twitter[<?php echo $number; ?>][feed]" value="friends"<?php checked($feed, 'friends'); ?> /> <?php _e('With Friends'); ?></label>
473
+ </p>
474
+ <p>
475
+ <label for="twitter-avatar-<?php echo $number; ?>"><input class="checkbox" type="checkbox" id="twitter-avatar-<?php echo $number; ?>" name="widget-twitter[<?php echo $number; ?>][avatar]"<?php checked($avatar, true); ?> /> <?php _e('Show Profile Image(s)'); ?></label>
476
+ </p>
477
+ <?php
478
+ }
479
+
480
+ /**
481
+ * Twitter displays all tweets that are less than 24 with something like
482
+ * "about 4 hours ago" and ones older than 24 hours with a time and date.
483
+ * This function allows us to simulate that functionality, but lets us
484
+ * choose where the dividing line is.
485
+ *
486
+ * @param int $startTimestamp - The timestamp used to calculate time passed
487
+ * @param int $max - Max number of seconds to conver to "ago" messages. 0 for all, -1 for none
488
+ * @return string
489
+ */
490
+ private function _timeSince($startTimestamp, $max) {
491
+ // array of time period chunks
492
+ $chunks = array(
493
+ array('seconds' => 60 * 60 * 24 * 365, 'name' => 'year'),
494
+ array('seconds' => 60 * 60 * 24 * 30, 'name' => 'month'),
495
+ array('seconds' => 60 * 60 * 24 * 7, 'name' => 'week'),
496
+ array('seconds' => 60 * 60 * 24, 'name' => 'day'),
497
+ array('seconds' => 60 * 60, 'name' => 'hour'),
498
+ array('seconds' => 60, 'name' => 'minute'),
499
+ array('seconds' => 1, 'name' => 'second')
500
+ );
501
+
502
+ $since = time() - $startTimestamp;
503
+
504
+ if ($max != '-1' && $since >= $max) {
505
+ return date('h:i:s A F d, Y', $startTimestamp);
506
+ }
507
+
508
+ // $j saves performing the count function each time around the loop
509
+ for ($i = 0, $j = count($chunks); $i < $j; $i++) {
510
+ extract($chunks[$i]);
511
+
512
+ // finding the biggest chunk (if the chunk fits, break)
513
+ if (($count = floor($since / $seconds)) != 0) {
514
+ break;
515
+ }
516
+ }
517
+
518
+ $print = "{$count} {$name}";
519
+ if ($count > 1) {
520
+ $print .= 's';
521
+ }
522
+
523
+ return "about {$print} ago";
524
+ }
525
+ }
526
+ // Instantiate our class
527
+ $wpTwitterWidget = new wpTwitterWidget();
528
+
529
+ /**
530
+ * Add filters and actions
531
+ */
532
+ add_action('widgets_init', array($wpTwitterWidget, 'register'));
533
+ add_filter('widget_twitter_content', array($wpTwitterWidget, 'linkTwitterUsers'));
534
+ add_filter('widget_twitter_content', array($wpTwitterWidget, 'linkUrls'));