PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-content/plugins/jetpack/modules/widgets/twitter.php

https://github.com/sharpmachine/wakeupmedia.com
PHP | 383 lines | 277 code | 77 blank | 29 comment | 43 complexity | 447a2b7f7e10d0d7610de37f620fb445 MD5 | raw file
  1. <?php
  2. /**
  3. * Twitter widget class
  4. * Display the latest N tweets from a Twitter screenname as a widget
  5. * Customize screenname, maximum number of tweets displayed, show or hide @replies, and text displayed between tweet text and a timestamp
  6. *
  7. */
  8. /**
  9. * Register the widget for use in Appearance -> Widgets
  10. */
  11. add_action( 'widgets_init', 'jetpack_twitter_widget_init' );
  12. function jetpack_twitter_widget_init() {
  13. register_widget( 'Jetpack_Widget_Twitter' );
  14. }
  15. class Jetpack_Widget_Twitter extends WP_Widget {
  16. function __construct() {
  17. parent::__construct( 'twitter', __( 'Twitter', 'jetpack' ), array( 'classname' => 'widget_twitter', 'description' => __( 'Display your Tweets from Twitter', 'jetpack' ) ) );
  18. }
  19. function widget( $args, $instance ) {
  20. $account = trim( urlencode( $instance['account'] ) );
  21. if ( empty( $account ) ) {
  22. if ( current_user_can('edit_theme_options') ) {
  23. echo $args['before_widget'];
  24. echo '<p>' . sprintf( __( 'Please configure your Twitter username for the <a href="%s">Twitter Widget</a>.', 'jetpack' ), admin_url( 'widgets.php' ) ) . '</p>';
  25. echo $args['after_widget'];
  26. }
  27. return;
  28. }
  29. $title = apply_filters( 'widget_title', $instance['title'] );
  30. if ( empty( $title ) )
  31. $title = __( 'Twitter Updates', 'jetpack' );
  32. $show = absint( $instance['show'] ); // # of Updates to show
  33. if ( $show > 200 ) // Twitter paginates at 200 max tweets. update() should not have accepted greater than 20
  34. $show = 200;
  35. $hidereplies = (bool) $instance['hidereplies'];
  36. $hidepublicized = (bool) $instance['hidepublicized'];
  37. $include_retweets = (bool) $instance['includeretweets'];
  38. $follow_button = (bool) $instance['followbutton'];
  39. echo "{$args['before_widget']}{$args['before_title']}<a href='" . esc_url( "http://twitter.com/{$account}" ) . "'>" . esc_html( $title ) . "</a>{$args['after_title']}";
  40. $tweets = $this->fetch_twitter_user_stream( $account, $hidereplies, $show, $include_retweets );
  41. if ( ! $tweets['error'] ) {
  42. $before_tweet = isset( $instance['beforetweet'] ) ? stripslashes( wp_filter_post_kses( $instance['beforetweet'] ) ) : '';
  43. $before_timesince = ( isset( $instance['beforetimesince'] ) && ! empty( $instance['beforetimesince'] ) ) ? esc_html( $instance['beforetimesince'] ) : ' ';
  44. $this->display_tweets( $show, $tweets['data'], $hidepublicized, $before_tweet, $before_timesince, $account );
  45. if ( $follow_button )
  46. $this->display_follow_button( $account );
  47. add_action( 'wp_footer', array( $this, 'twitter_widget_script' ) );
  48. } else {
  49. echo esc_html( $tweets['error'] );
  50. }
  51. echo $args['after_widget'];
  52. do_action( 'jetpack_stats_extra', 'widgets', 'twitter' );
  53. }
  54. function display_tweets( $show, $tweets, $hidepublicized, $before_tweet, $before_timesince, $account ) {
  55. $tweets_out = 0;
  56. ?><ul class='tweets'><?php
  57. foreach( (array) $tweets as $tweet ) {
  58. if ( $tweets_out >= $show )
  59. break;
  60. if ( empty( $tweet['text'] ) )
  61. continue;
  62. if( $hidepublicized && false !== strstr( $tweet['source'], 'http://publicize.wp.com/' ) )
  63. continue;
  64. $tweet['text'] = esc_html( $tweet['text'] ); // escape here so that Twitter handles in Tweets don't get mangled
  65. $tweet = $this->expand_tco_links( $tweet );
  66. $tweet['text'] = make_clickable( $tweet['text'] );
  67. /*
  68. * Create links from plain text based on Twitter patterns
  69. * @link http://github.com/mzsanford/twitter-text-rb/blob/master/lib/regex.rb Official Twitter regex
  70. */
  71. $tweet['text'] = preg_replace_callback( '/(^|[^0-9A-Z&\/]+)(#|\xef\xbc\x83)([0-9A-Z_]*[A-Z_]+[a-z0-9_\xc0-\xd6\xd8-\xf6\xf8\xff]*)/iu', array( $this, '_jetpack_widget_twitter_hashtag' ), $tweet['text'] );
  72. $tweet['text'] = preg_replace_callback( '/([^a-zA-Z0-9_]|^)([@\xef\xbc\xa0]+)([a-zA-Z0-9_]{1,20})(\/[a-zA-Z][a-zA-Z0-9\x80-\xff-]{0,79})?/u', array( $this, '_jetpack_widget_twitter_username' ), $tweet['text'] );
  73. if ( isset( $tweet['id_str'] ) )
  74. $tweet_id = urlencode( $tweet['id_str'] );
  75. else
  76. $tweet_id = urlencode( $tweet['id'] );
  77. ?>
  78. <li>
  79. <?php echo esc_attr( $before_tweet ) . $tweet['text'] . esc_attr( $before_timesince ) ?>
  80. <a href="<?php echo esc_url( "http://twitter.com/{$account}/statuses/{$tweet_id}" ); ?>" class="timesince"><?php echo esc_html( str_replace( ' ', '&nbsp;', $this->time_since( strtotime( $tweet['created_at'] ) ) ) ); ?>&nbsp;ago</a>
  81. </li>
  82. <?php
  83. unset( $tweet_it );
  84. $tweets_out++;
  85. }
  86. ?></ul><?php
  87. }
  88. function display_follow_button( $account ) {
  89. global $themecolors;
  90. $follow_colors = isset( $themecolors['link'] ) ? " data-link-color='#{$themecolors['link']}'" : '';
  91. $follow_colors .= isset( $themecolors['text'] ) ? " data-text-color='#{$themecolors['text']}'" : '';
  92. $follow_button_attrs = " class='twitter-follow-button' data-show-count='false'{$follow_colors}";
  93. ?><a href="http://twitter.com/<?php echo esc_attr( $account ); ?>" <?php echo $follow_button_attrs; ?>>Follow @<?php echo esc_attr( $account ); ?></a><?php
  94. }
  95. function expand_tco_links( $tweet ) {
  96. if ( ! empty( $tweet['entities']['urls'] ) && is_array( $tweet['entities']['urls'] ) ) {
  97. foreach ( $tweet['entities']['urls'] as $entity_url ) {
  98. if ( ! empty( $entity_url['expanded_url'] ) ) {
  99. $tweet['text'] = str_replace(
  100. $entity_url['url'],
  101. '<a href="' . esc_url( $entity_url['expanded_url'] ) . '"> ' . esc_html( $entity_url['display_url'] ) . '</a>',
  102. $tweet['text']
  103. );
  104. }
  105. }
  106. }
  107. return $tweet;
  108. }
  109. function fetch_twitter_user_stream( $account, $hidereplies, $show, $include_retweets ) {
  110. $tweets = get_transient( 'widget-twitter-' . $this->number );
  111. $the_error = get_transient( 'widget-twitter-error-' . $this->number );
  112. if ( ! $tweets ) {
  113. $params = array(
  114. 'screen_name' => $account, // Twitter account name
  115. 'trim_user' => true, // only basic user data (slims the result)
  116. 'include_entities' => true
  117. );
  118. // If combined with $count, $exclude_replies only filters that number of tweets (not all tweets up to the requested count).
  119. if ( $hidereplies )
  120. $params['exclude_replies'] = true;
  121. else
  122. $params['count'] = $show;
  123. if ( $include_retweets )
  124. $params['include_rts'] = true;
  125. $twitter_json_url = esc_url_raw( 'http://api.twitter.com/1/statuses/user_timeline.json?' . http_build_query( $params ), array( 'http', 'https' ) );
  126. unset( $params );
  127. $response = wp_remote_get( $twitter_json_url, array( 'User-Agent' => 'WordPress.com Twitter Widget' ) );
  128. $response_code = wp_remote_retrieve_response_code( $response );
  129. switch( $response_code ) {
  130. case 200 : // process tweets and display
  131. $tweets = json_decode( wp_remote_retrieve_body( $response ), true );
  132. if ( ! is_array( $tweets ) || isset( $tweets['error'] ) ) {
  133. do_action( 'jetpack_bump_stats_extras', 'twitter_widget', 'request-fail-$response_code-bad-data' );
  134. $the_error = '<p>' . __( 'Error: Twitter did not respond. Please wait a few minutes and refresh this page.', 'jetpack' ) . '</p>';
  135. $tweet_cache_expire = 300;
  136. break;
  137. } else {
  138. set_transient( 'widget-twitter-backup-' . $this->number, $tweets, 86400 ); // A one day backup in case there is trouble talking to Twitter
  139. }
  140. do_action( 'jetpack_bump_stats_extras', 'twitter_widget', 'request-success' );
  141. $tweet_cache_expire = 900;
  142. break;
  143. case 401 : // display private stream notice
  144. do_action( 'jetpack_bump_stats_extras', 'twitter_widget', 'request-fail-$response_code' );
  145. $tweets = array();
  146. $the_error = '<p>' . sprintf( __( 'Error: Please make sure the Twitter account is <a href="%s">public</a>.', 'jetpack' ), 'http://support.twitter.com/forums/10711/entries/14016' ) . '</p>';
  147. $tweet_cache_expire = 300;
  148. break;
  149. default : // display an error message
  150. do_action( 'jetpack_bump_stats_extras', 'twitter_widget', 'request-fail-$response_code' );
  151. $tweets = get_transient( 'widget-twitter-backup-' . $this->number );
  152. $the_error = '<p>' . __( 'Error: Twitter did not respond. Please wait a few minutes and refresh this page.', 'jetpack' ) . '</p>';
  153. $tweet_cache_expire = 300;
  154. break;
  155. }
  156. set_transient( 'widget-twitter-' . $this->number, $tweets, $tweet_cache_expire );
  157. set_transient( 'widget-twitter-error-' . $this->number, $the_error, $tweet_cache_expire );
  158. }
  159. return array( 'data' => $tweets, 'error' => $the_error );
  160. }
  161. function update( $new_instance, $old_instance ) {
  162. $instance = array();
  163. $instance['account'] = trim( wp_kses( $new_instance['account'], array() ) );
  164. $instance['account'] = str_replace( array( 'http://twitter.com/', '/', '@', '#!', ), array( '', '', '', '', ), $instance['account'] );
  165. $instance['title'] = wp_kses( $new_instance['title'], array() );
  166. $instance['show'] = absint( $new_instance['show'] );
  167. $instance['hidereplies'] = isset( $new_instance['hidereplies'] );
  168. $instance['hidepublicized'] = isset( $new_instance['hidepublicized'] );
  169. $instance['includeretweets'] = isset( $new_instance['includeretweets'] );
  170. if ( $instance['followbutton'] != $new_instance['followbutton'] ) {
  171. if ( $new_instance['followbutton'] )
  172. do_action( 'jetpack_bump_stats_extras', 'twitter_widget', 'follow_button_enabled' );
  173. else
  174. do_action( 'jetpack_bump_stats_extras', 'twitter_widget', 'follow_button_disabled' );
  175. }
  176. $instance['followbutton'] = ! isset( $new_instance['followbutton'] ) ? 0 : 1;
  177. $instance['beforetimesince'] = $new_instance['beforetimesince'];
  178. delete_transient( 'widget-twitter-' . $this->number );
  179. delete_transient( 'widget-twitter-error-' . $this->number );
  180. return $instance;
  181. }
  182. function form( $instance ) {
  183. //Defaults
  184. $account = isset( $instance['account'] ) ? wp_kses( $instance['account'], array() ) : '';
  185. $title = isset( $instance['title'] ) ? $instance['title'] : '';
  186. $show = isset( $instance['show'] ) ? absint( $instance['show'] ) : 5;
  187. $show = ( $show < 1 || 20 < $show ) ? 5 : $show;
  188. $hidereplies = isset( $instance['hidereplies'] ) && ! empty( $instance['hidereplies'] ) ? (bool) $instance['hidereplies'] : false;
  189. $hidepublicized = isset( $instance['hidepublicized'] ) && ! empty( $instance['hidepublicized'] ) ? (bool) $instance['hidepublicized'] : false;
  190. $include_retweets = isset( $instance['includeretweets'] ) && ! empty( $instance['includeretweets'] ) ? (bool) $instance['includeretweets'] : false;
  191. $follow_button = isset( $instance['followbutton'] ) && ! empty( $instance['followbutton'] ) ? 1 : 0;
  192. $before_timesince = isset( $instance['beforetimesince'] ) && ! empty( $instance['beforetimesince'] ) ? esc_attr( $instance['beforetimesince'] ) : '';
  193. ?>
  194. <p>
  195. <label for="<?php echo $this->get_field_id( 'title' ); ?>">
  196. <?php esc_html_e( 'Title:', 'jetpack' )?>
  197. <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( $title ); ?>" />
  198. </label>
  199. </p>
  200. <p>
  201. <label for="<?php echo $this->get_field_id( 'account' ); ?>">
  202. <?php esc_html_e( 'Twitter username:', 'jetpack' ); ?> <a href="http://support.wordpress.com/widgets/twitter-widget/#twitter-username" target="_blank">( ? )</a>
  203. <input class="widefat" id="<?php echo $this->get_field_id( 'account' ); ?>" name="<?php echo $this->get_field_name( 'account' ); ?>" type="text" value="<?php echo esc_attr( $account ); ?>" />
  204. </label>
  205. </p>
  206. <p>
  207. <label for="<?php echo $this->get_field_id( 'show' ); ?>">
  208. <?php esc_html_e( 'Maximum number of Tweets to show:', 'jetpack' ); ?>
  209. <select id="<?php echo $this->get_field_id( 'show' ); ?>" name="<?php echo $this->get_field_name( 'show' ); ?>">
  210. <?php
  211. for ( $i = 1; $i <= 20; ++$i ) :
  212. ?><option value="<?php echo esc_attr( $i ); ?>" <?php selected( $show, $i ); ?>><?php echo esc_attr( $i ); ?></option><?php
  213. endfor;
  214. ?>
  215. </select>
  216. </label>
  217. </p>
  218. <p>
  219. <label for="<?php echo $this->get_field_id( 'hidereplies' ); ?>">
  220. <input id="<?php echo $this->get_field_id( 'hidereplies' );?>" class="checkbox" type="checkbox" name="<?php echo $this->get_field_name( 'hidereplies' ); ?>" <?php checked( $hidereplies, true ); ?> />
  221. <?php esc_html_e( 'Hide replies', 'jetpack' ); ?>
  222. </label>
  223. </p>
  224. <p>
  225. <label for="<?php echo $this->get_field_id( 'hidepublicized' ); ?>">
  226. <input id="<?php echo $this->get_field_id( 'hidepublicized' ); ?>" class="checkbox" type="checkbox" name="<?php echo $this->get_field_name( 'hidepublicized' ); ?>" <?php checked( $hidepublicized, true ); ?> />
  227. <?php esc_html_e( 'Hide Tweets pushed by Publicize', 'jetpack' ); ?>
  228. </label>
  229. </p>
  230. <p>
  231. <label for="<?php echo $this->get_field_id( 'includeretweets' ); ?>">
  232. <input id="<?php echo $this->get_field_id( 'includeretweets' ); ?>" class="checkbox" type="checkbox" name="<?php echo $this->get_field_name( 'includeretweets' ); ?>" <?php checked( $include_retweets, true ); ?> />
  233. <?php esc_html_e( 'Include retweets', 'jetpack' ); ?>
  234. </label>
  235. </p>
  236. <p>
  237. <label for="<?php echo $this->get_field_id( 'followbutton' ); ?>">
  238. <input id="<?php echo $this->get_field_id( 'followbutton' ); ?>" class="checkbox" type="checkbox" name="<?php echo $this->get_field_name( 'followbutton' ); ?>" <?php checked( $follow_button, 1 ); ?> />
  239. <?php esc_html_e( 'Display Follow Button', 'jetpack' ); ?>
  240. </label>
  241. </p>
  242. <p>
  243. <label for="<?php echo $this->get_field_id( 'beforetimesince' ); ?>">
  244. <?php esc_html_e( 'Text to display between Tweet and timestamp:', 'jetpack' ); ?>
  245. <input class="widefat" id="<?php echo $this->get_field_id( 'beforetimesince' ); ?>" name="<?php echo $this->get_field_name( 'beforetimesince' ); ?>" type="text" value="<?php echo esc_attr( $before_timesince ); ?>" />
  246. </label>
  247. </p>
  248. <?php
  249. }
  250. function time_since( $original, $do_more = 0 ) {
  251. // array of time period chunks
  252. $chunks = array(
  253. array(60 * 60 * 24 * 365 , 'year'),
  254. array(60 * 60 * 24 * 30 , 'month'),
  255. array(60 * 60 * 24 * 7, 'week'),
  256. array(60 * 60 * 24 , 'day'),
  257. array(60 * 60 , 'hour'),
  258. array(60 , 'minute'),
  259. );
  260. $today = time();
  261. $since = $today - $original;
  262. for ($i = 0, $j = count($chunks); $i < $j; $i++) {
  263. $seconds = $chunks[$i][0];
  264. $name = $chunks[$i][1];
  265. if (($count = floor($since / $seconds)) != 0)
  266. break;
  267. }
  268. $print = ($count == 1) ? '1 '.$name : "$count {$name}s";
  269. if ($i + 1 < $j) {
  270. $seconds2 = $chunks[$i + 1][0];
  271. $name2 = $chunks[$i + 1][1];
  272. // add second item if it's greater than 0
  273. if ( (($count2 = floor(($since - ($seconds * $count)) / $seconds2)) != 0) && $do_more )
  274. $print .= ($count2 == 1) ? ', 1 '.$name2 : ", $count2 {$name2}s";
  275. }
  276. return $print;
  277. }
  278. /**
  279. * Link a Twitter user mentioned in the tweet text to the user's page on Twitter.
  280. *
  281. * @param array $matches regex match
  282. * @return string Tweet text with inserted @user link
  283. */
  284. function _jetpack_widget_twitter_username( array $matches ) { // $matches has already been through wp_specialchars
  285. return "$matches[1]@<a href='" . esc_url( 'http://twitter.com/' . urlencode( $matches[3] ) ) . "'>$matches[3]</a>";
  286. }
  287. /**
  288. * Link a Twitter hashtag with a search results page on Twitter.com
  289. *
  290. * @param array $matches regex match
  291. * @return string Tweet text with inserted #hashtag link
  292. */
  293. function _jetpack_widget_twitter_hashtag( array $matches ) { // $matches has already been through wp_specialchars
  294. return "$matches[1]<a href='" . esc_url( 'http://twitter.com/search?q=%23' . urlencode( $matches[3] ) ) . "'>#$matches[3]</a>";
  295. }
  296. function twitter_widget_script() {
  297. if ( ! wp_script_is( 'twitter-widgets', 'registered' ) ) {
  298. if ( is_ssl() )
  299. $twitter_widget_js = 'https://platform.twitter.com/widgets.js';
  300. else
  301. $twitter_widget_js = 'http://platform.twitter.com/widgets.js';
  302. wp_register_script( 'twitter-widgets', $twitter_widget_js, array(), '20111117', true );
  303. wp_print_scripts( 'twitter-widgets' );
  304. }
  305. }
  306. }