userAgent = 'WordPress/' . $GLOBALS['wp_version']; } /** * Pulls the JSON feed from Twitter and returns an array of objects * * @param array $widgetOptions - settings needed to get feed url, etc * @return array */ private function _parseFeed($widgetOptions) { $feedUrl = $this->_getFeedUrl($widgetOptions); $resp = $this->_fetch_remote_file($feedUrl); if ( $resp->status >= 200 && $resp->status < 300 ) { if (function_exists('json_decode')) { return json_decode($resp->results); } else { require_once('json_decode.php'); return Zend_Json_Decoder::decode($resp->results); } } else { // Failed to fetch url; return array(); } } /** * Gets the URL for the desired feed. * * @param array $widgetOptions - settings needed such as username, feet type, etc * @param string[optional] $type - 'rss' or 'json' * @param bool[optional] $count - If true, it adds the count parameter to the URL * @return string - Twitter feed URL */ private function _getFeedUrl($widgetOptions, $type = 'json', $count = true) { if (!in_array($type, array('rss', 'json'))) { $type = 'json'; } if ($count) { $count = sprintf('?count=%u', $widgetOptions['items']); } else { $count = ''; } return sprintf('http://twitter.com/statuses/%1$s_timeline/%2$s.%3$s%4$s',$widgetOptions['feed'], $widgetOptions['username'], $type, $count); } /** * Replace @username with a link to that twitter user * * @param string $text - Tweet text * @return string - Tweet text with @replies linked */ public function linkTwitterUsers($text) { $text = preg_replace('/(^|\s)@(\w*)/i', '$1@$2', $text); return $text; } /** * Turn URLs into links * * @param string $text - Tweet text * @return string - Tweet text with URLs repalced with links */ public function linkUrls($text) { /** * match protocol://address/path/file.extension?some=variable&another=asf% * $1 is a possible space, this keeps us from linking href="[link]" etc * $2 is the whole URL * $3 is protocol:// * $4 is the URL without the protocol:// * $5 is the URL parameters */ $text = preg_replace("/(^|\s)(([a-zA-Z]+:\/\/)([a-z][a-z0-9_\..-]*[a-z]{2,6})([a-zA-Z0-9\/*-?&%]*))/i", "$1$2", $text); /** * match www.something.domain/path/file.extension?some=variable&another=asf% * $1 is a possible space, this keeps us from linking href="[link]" etc * $2 is the whole URL that was matched. The protocol is missing, so we assume http:// * $3 is www. * $4 is the URL matched without the www. * $5 is the URL parameters */ $text = preg_replace("/(^|\s)(www\.([a-z][a-z0-9_\..-]*[a-z]{2,6})([a-zA-Z0-9\/*-?&%]*))/i", "$1$2", $text); return $text; } /** * Uses snoopy class to pull file contents * * @param string $url - Url to get * @param array $headers - Raw headers to pass * @return Snoopy */ private function _fetch_remote_file ($url, $headers = "" ) { require_once( ABSPATH . 'wp-includes/class-snoopy.php' ); // Snoopy is an HTTP client in PHP $client = new Snoopy(); $client->agent = $this->userAgent; $client->read_timeout = $this->fetchTimeOut; $client->use_gzip = $this->useGzip; if (is_array($headers) ) { $client->rawheaders = $headers; } @$client->fetch($url); return $client; } /** * Gets tweets, from cache if possible * * @param array $widgetOptions - options needed to get feeds * @return array - Array of objects */ private function _getTweets($widgetOptions) { // Get cache of feed if it exists $tweets = wp_cache_get($widgetOptions['feed'] . $widgetOptions['username'], 'widget_twitter'); // If there is no cache if ($tweets == false) { $tweets = $this->_parseFeed($widgetOptions); // Cache for 60 seconds, Tweets are supposed to be current, so we don't cache for very long wp_cache_set($widgetOptions['feed'] . $widgetOptions['username'], $tweets, 'widget_twitter', 60); } return $tweets; } /** * Displays the Twitter widget, with all tweets in an unordered list. * Things are classed but not styled to allow easy styling. * * @param array $args - Widget Settings * @param array|int $widget_args - Widget Number */ public function display($args, $widget_args = 1) { extract( $args, EXTR_SKIP ); if ( is_numeric($widget_args) ) $widget_args = array( 'number' => $widget_args ); $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); extract( $widget_args, EXTR_SKIP ); $options = get_option('widget_twitter'); if ( !isset($options[$number]) ) { return; } // Validate our options if (!isset($options[$number]['feed']) || !in_array($options[$number]['feed'], array('user', 'friends'))) { $options[$number]['feed'] = 'user'; } $options[$number]['items'] = (int) $options[$number]['items']; if ( $options[$number]['items'] < 1 || 20 < $options[$number]['items'] ) { $options[$number]['items'] = 10; } if (!isset($options[$number]['showts'])) { $options[$number]['showts'] = 86400; } $options[$number]['hiderss'] = (isset($options[$number]['hiderss']) && $options[$number]['hiderss']); $options[$number]['avatar'] = (isset($options[$number]['avatar']) && $options[$number]['avatar']); $tweets = $this->_getTweets($options[$number]); $tweets = array_slice($tweets, 0, $options[$number]['items']); echo $before_widget; // If "hide rss" hasn't been checked, show the linked icon if (!$options[$number]['hiderss']) { if ( file_exists(dirname(__FILE__) . '/rss.png') ) { $icon = str_replace(ABSPATH, get_option('siteurl').'/', dirname(__FILE__)) . '/rss.png'; } else { $icon = get_option('siteurl').'/wp-includes/images/rss.png'; } $feedUrl = $this->_getFeedUrl($options[$number], 'rss', false); $before_title .= "RSS "; } $twitterLink = 'http://twitter.com/' . $options[$number]['username']; $before_title .= ""; $after_title = '' . $after_title; if (empty($options[$number]['title'])) { $options[$number]['title'] = "Twitter: {$options[$number]['username']}"; } echo $before_title . $options[$number]['title'] . $after_title; ?> user->screen_name}/statuses/{$replyTo->id}"> in reply to {$replyTo->user->screen_name} replyTo; } /** * Returns the Twitter user's profile image, linked to that user's profile * * @param object $user - Twitter User * @return string - Linked image (XHTML) */ private function _getProfileImage($user) { return << {$user->name} profileImage; } /** * Returns the user's screen name as a link inside strong tags. * * @param object $user - Twitter user * @return string - Username as link (XHTML) */ private function _getUserName($user) { return << {$user->screen_name} profileImage; } /** * Sets up admin forms to manage widgets * * @param array|int $widget_args - Widget Number */ public function control($widget_args) { global $wp_registered_widgets; static $updated = false; if ( is_numeric($widget_args) ) $widget_args = array( 'number' => $widget_args ); $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); extract( $widget_args, EXTR_SKIP ); $options = get_option('widget_twitter'); if ( !is_array($options) ) $options = array(); if ( !$updated && !empty($_POST['sidebar']) ) { $sidebar = (string) $_POST['sidebar']; $sidebars_widgets = wp_get_sidebars_widgets(); if ( isset($sidebars_widgets[$sidebar]) ) $this_sidebar =& $sidebars_widgets[$sidebar]; else $this_sidebar = array(); foreach ( $this_sidebar as $_widget_id ) { if ( array($this,'display') == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) { $widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number']; if ( !in_array( "twitter-$widget_number", $_POST['widget-id'] ) ) // the widget has been removed. unset($options[$widget_number]); } } foreach ( (array) $_POST['widget-twitter'] as $widget_number => $widget_twitter ) { if ( !isset($widget_twitter['username']) && isset($options[$widget_number]) ) // user clicked cancel continue; $widget_twitter['title'] = strip_tags(stripslashes($widget_twitter['title'])); $options[$widget_number] = $widget_twitter; } update_option('widget_twitter', $options); $updated = true; } if ( -1 != $number ) { $options[$number]['number'] = $number; $options[$number]['title'] = attribute_escape($options[$number]['title']); $options[$number]['username'] = attribute_escape($options[$number]['username']); $options[$number]['hiderss'] = (bool) $options[$number]['hiderss']; $options[$number]['avatar'] = (bool) $options[$number]['avatar']; if (!isset($options[$number]['feed']) || !in_array($options[$number]['feed'], array('user', 'friends'))) { $options[$number]['feed'] = 'user'; } } $this->_showForm($options[$number]); } /** * Registers widget in such a way as to allow multiple instances of it * * @see wp-includes/widgets.php */ public function register() { if ( !$options = get_option('widget_twitter') ) $options = array(); $widget_ops = array('classname' => 'widget_twitter', 'description' => __('Follow a Twitter Feed')); $control_ops = array('width' => 400, 'height' => 350, 'id_base' => 'twitter'); $name = __('Twitter Feed'); $id = false; foreach ( array_keys($options) as $o ) { // Old widgets can have null values for some reason if ( !isset($options[$o]['title']) || !isset($options[$o]['username']) ) continue; $id = "twitter-$o"; // Never never never translate an id wp_register_sidebar_widget($id, $name, array($this,'display'), $widget_ops, array( 'number' => $o )); wp_register_widget_control($id, $name, array($this,'control'), $control_ops, array( 'number' => $o )); } // If there are none, we register the widget's existance with a generic template if ( !$id ) { wp_register_sidebar_widget( 'twitter-1', $name, array($this,'display'), $widget_ops, array( 'number' => -1 ) ); wp_register_widget_control( 'twitter-1', $name, array($this,'control'), $control_ops, array( 'number' => -1 ) ); } } /** * Displays the actualy for that populates the widget options box in the * admin section * * @param array $args - Current widget settings and widget number, gets combind with defaults */ private function _showForm($args) { $defaultArgs = array( 'title' => '', 'username' => '', 'hiderss' => false, 'avatar' => false, 'feed' => 'user', 'items' => 10, 'showts' => 60 * 60 * 24, 'number' => '%i%' ); $args = wp_parse_args( $args, $defaultArgs ); extract( $args ); ?>


60 * 60 * 24 * 365, 'name' => 'year'), array('seconds' => 60 * 60 * 24 * 30, 'name' => 'month'), array('seconds' => 60 * 60 * 24 * 7, 'name' => 'week'), array('seconds' => 60 * 60 * 24, 'name' => 'day'), array('seconds' => 60 * 60, 'name' => 'hour'), array('seconds' => 60, 'name' => 'minute'), array('seconds' => 1, 'name' => 'second') ); $since = time() - $startTimestamp; if ($max != '-1' && $since >= $max) { return date('h:i:s A F d, Y', $startTimestamp); } // $j saves performing the count function each time around the loop for ($i = 0, $j = count($chunks); $i < $j; $i++) { extract($chunks[$i]); // finding the biggest chunk (if the chunk fits, break) if (($count = floor($since / $seconds)) != 0) { break; } } $print = "{$count} {$name}"; if ($count > 1) { $print .= 's'; } return "about {$print} ago"; } } // Instantiate our class $wpTwitterWidget = new wpTwitterWidget(); /** * Add filters and actions */ add_action('widgets_init', array($wpTwitterWidget, 'register')); add_filter('widget_twitter_content', array($wpTwitterWidget, 'linkTwitterUsers')); add_filter('widget_twitter_content', array($wpTwitterWidget, 'linkUrls'));