web/wp-content/plugins/social/social-twitter.php
changeset 196 5e8dcbe22c24
equal deleted inserted replaced
195:c7c0fbc09788 196:5e8dcbe22c24
       
     1 <?php
       
     2 /**
       
     3  * Twitter implementation for Social.
       
     4  *
       
     5  * @package    Social
       
     6  * @subpackage plugins
       
     7  */
       
     8 if (class_exists('Social') and !class_exists('Social_Twitter')) {
       
     9 
       
    10 final class Social_Twitter {
       
    11 
       
    12 	/**
       
    13 	 * Registers Twitter to Social.
       
    14 	 *
       
    15 	 * @static
       
    16 	 * @wp-filter  social_register_service
       
    17 	 *
       
    18 	 * @param  array  $services
       
    19 	 *
       
    20 	 * @return array
       
    21 	 */
       
    22 	public static function register_service(array $services) {
       
    23 		$services[] = 'twitter';
       
    24 		return $services;
       
    25 	}
       
    26 
       
    27 	/**
       
    28 	 * Adds to the avatar comment types array.
       
    29 	 *
       
    30 	 * @static
       
    31 	 * @param  array  $types
       
    32 	 * @return array
       
    33 	 */
       
    34 	public static function get_avatar_comment_types(array $types) {
       
    35 		return array_merge($types, Social_Service_Twitter::comment_types());
       
    36 	}
       
    37 
       
    38 	/**
       
    39 	 * Pre-processor to the comments.
       
    40 	 *
       
    41 	 * @wp-filter social_comments_array
       
    42 	 * @static
       
    43 	 * @param  array  $comments
       
    44 	 * @param  int    $post_id
       
    45 	 * @return array
       
    46 	 */
       
    47 	public static function comments_array(array $comments, $post_id) {
       
    48 		// pre-load the hashes for broadcasted tweets
       
    49 		$broadcasted_ids = get_post_meta($post_id, '_social_broadcasted_ids', true);
       
    50 		if (empty($broadcasted_ids)) {
       
    51 			$broadcasted_ids = array();
       
    52 		}
       
    53 		global $wpdb;
       
    54 
       
    55 		// we need comments to be keyed by ID, check for Tweet comments
       
    56 		$tweet_comments = $_comments = $comment_ids = array();
       
    57 		foreach ($comments as $key => $comment) {
       
    58 			if (is_object($comment)) {
       
    59 				$_comments['id_'.$comment->comment_ID] = $comment;
       
    60 				if (in_array($comment->comment_type, Social_Service_Twitter::comment_types())) {
       
    61 					$comment_ids[] = $comment->comment_ID;
       
    62 					$tweet_comments['id_'.$comment->comment_ID] = $comment;
       
    63 				}
       
    64 			}
       
    65 			else { // social items
       
    66 				$_comments[$key] = $comment;
       
    67 			}
       
    68 		}
       
    69 
       
    70 		// if no tweet comments, get out now
       
    71 		if (!count($tweet_comments)) {
       
    72 			return $comments;
       
    73 		}
       
    74 
       
    75 		// use our keyed array
       
    76 		$comments = $_comments;
       
    77 		unset($_comments);
       
    78 
       
    79 		$social_map = array(); // key = social id, value = comment_ID
       
    80 		$hash_map = array(); // key = hash, value = comment_ID
       
    81 		$broadcasted_social_ids = array();
       
    82  		$broadcast_retweets = array(); // array of comments
       
    83 
       
    84 		if (isset($broadcasted_ids['twitter'])) {
       
    85 			foreach ($broadcasted_ids['twitter'] as $account_id => $broadcasted) {
       
    86 				foreach ($broadcasted as $id => $data) {
       
    87 					$broadcasted_social_ids[] = $id;
       
    88 					// if we don't have a message saved for a tweet, try to get it so that we can use it next time
       
    89 					if (empty($data['message'])) {
       
    90 						$url = wp_nonce_url(home_url('index.php?social_controller=aggregation&social_action=retrieve_twitter_content&broadcasted_id='.$id.'&post_id='.$post_id), 'retrieve_twitter_content');
       
    91 						wp_remote_get(str_replace('&amp;', '&', $url), array(
       
    92 							'timeout' => 0.01,
       
    93 							'blocking' => false,
       
    94 						));
       
    95 					}
       
    96 					else {
       
    97 						// create a hash from the broadcast so we can match retweets to it
       
    98 						$hash = self::build_hash($data['message']);
       
    99 
       
   100 						// This is stored as broadcasted and not the ID so we can easily store broadcasted retweets
       
   101 						// instead of attaching retweets to non-existent comments.
       
   102 						$hash_map[$hash] = 'broadcasted';
       
   103 					}
       
   104 				}
       
   105 			}
       
   106 		}
       
   107 
       
   108 		// Load the comment meta
       
   109 		$results = $wpdb->get_results("
       
   110 			SELECT meta_key, meta_value, comment_id
       
   111 			  FROM $wpdb->commentmeta
       
   112 			 WHERE comment_id IN (".implode(',', $comment_ids).")
       
   113 			   AND (
       
   114 			       meta_key = 'social_in_reply_to_status_id'
       
   115 			    OR meta_key = 'social_status_id'
       
   116 			    OR meta_key = 'social_raw_data'
       
   117 			    OR meta_key = 'social_profile_image_url'
       
   118 			    OR meta_key = 'social_comment_type'
       
   119 			)
       
   120 		");
       
   121 
       
   122 		// Set up social data for twitter comments
       
   123 		foreach ($tweet_comments as $key => &$comment) {
       
   124 			$comment->social_items = array();
       
   125 
       
   126 			// Attach meta
       
   127 			foreach ($results as $result) {
       
   128 				if ($comment->comment_ID == $result->comment_id) {
       
   129 					switch ($result->meta_key) {
       
   130 						case 'social_raw_data':
       
   131 							$comment->social_raw_data = json_decode(base64_decode($result->meta_value));
       
   132 							break;
       
   133 						case 'social_status_id':
       
   134 							$social_map[$result->meta_value] = $result->comment_id;
       
   135 						default:
       
   136 							$comment->{$result->meta_key} = $result->meta_value;
       
   137 					}
       
   138 				}
       
   139 			}
       
   140 
       
   141 			// Attach hash
       
   142 			if (isset($comment->social_raw_data) and isset($comment->social_raw_data->text)) {
       
   143 				$text = trim($comment->social_raw_data->text);
       
   144 			}
       
   145 			else {
       
   146 				$text = trim($comment->comment_content);
       
   147 			}
       
   148 			$comment->social_hash = self::build_hash($text);
       
   149 
       
   150 			if (!isset($hash_map[$comment->social_hash])) {
       
   151 				$hash_map[$comment->social_hash] = $comment->comment_ID;
       
   152 			}
       
   153 		}
       
   154 
       
   155 		// merge data so that $comments has the data we've set up
       
   156 		$comments = array_merge($comments, $tweet_comments);
       
   157 
       
   158 		// set-up replies and retweets
       
   159 		foreach ($tweet_comments as $key => &$comment) {
       
   160 			if (is_object($comment)) {
       
   161 				// set reply/comment parent
       
   162 				if (!empty($comment->social_in_reply_to_status_id) and isset($social_map[$comment->social_in_reply_to_status_id])) {
       
   163 					$comments[$key]->comment_parent = $social_map[$comment->social_in_reply_to_status_id];
       
   164 				}
       
   165 
       
   166 				// set retweets
       
   167 				$rt_matched = false;
       
   168 				if (isset($comment->social_raw_data) and isset($comment->social_raw_data->retweeted_status)) {
       
   169 					// explicit match via API data
       
   170 					$rt_id = $comment->social_raw_data->retweeted_status->id_str;
       
   171 					if (in_array($rt_id, $broadcasted_social_ids)) {
       
   172 						$broadcast_retweets[] = $comment;
       
   173 						unset($comments[$key]);
       
   174 						$rt_matched = true;
       
   175 					}
       
   176 					else if (isset($social_map[$rt_id]) and isset($comments['id_'.$social_map[$rt_id]])) {
       
   177 						$comments['id_'.$social_map[$rt_id]]->social_items[$key] = $comment;
       
   178 						unset($comments[$key]);
       
   179 						$rt_matched = true;
       
   180 					}
       
   181 				}
       
   182 
       
   183 				if (!$rt_matched) {
       
   184 					// best guess via hashes
       
   185 					$hash_match = $hash_map[$comment->social_hash];
       
   186 					if ($hash_match != $comment->comment_ID) { // hash match to own tweet is expected, at minimum - set above
       
   187 						if ($hash_match == 'broadcasted') {
       
   188 							$broadcast_retweets[] = $comment;
       
   189 						}
       
   190 						else if (isset($comments['id_'.$hash_match])) {
       
   191 							$comments['id_'.$hash_match]->social_items[$key] = $comment;
       
   192 						}
       
   193 						else {
       
   194 							// Loop through the broadcasted retweets and see if this is a retweet of one of those.
       
   195 							foreach ($broadcast_retweets as $retweet) {
       
   196 								if ($retweet->comment_ID == $hash_match) {
       
   197 									$broadcast_retweets[] = $comment;
       
   198 									break;
       
   199 								}
       
   200 							}
       
   201 						}
       
   202 						unset($comments[$key]);
       
   203 					}
       
   204 				}
       
   205 			}
       
   206 		}
       
   207 
       
   208 		if (!isset($comments['social_items'])) {
       
   209 			$comments['social_items'] = array();
       
   210 		}
       
   211 
       
   212 		if (count($broadcast_retweets)) {
       
   213 			$comments['social_items']['twitter'] = $broadcast_retweets;
       
   214 		}
       
   215 
       
   216 		return $comments;
       
   217 	}
       
   218 
       
   219 
       
   220 	/**
       
   221 	 * Sets the raw data for the broadcasted post.
       
   222 	 *
       
   223 	 * @wp-filter social_broadcast_response
       
   224 	 * @static
       
   225 	 * @param  array                   $data
       
   226 	 * @param  Social_Service_Account  $account
       
   227 	 * @param  string                  $service_key
       
   228 	 * @param  int                     $post_id
       
   229 	 * @param  Social_Response         $response
       
   230 	 * @return array
       
   231 	 */
       
   232 	public static function social_save_broadcasted_ids_data(array $data, Social_Service_Account $account, $service_key, $post_id, Social_Response $response = null) {
       
   233 		if ($service_key == 'twitter') {
       
   234 			if (!empty($response)) {
       
   235 				$data['message'] = base64_encode(json_encode($response->body()->response));
       
   236 			}
       
   237 			$data['account'] = (object) array(
       
   238 				'user' => $account->as_object()->user
       
   239 			);
       
   240 		}
       
   241 
       
   242 		return $data;
       
   243 	}
       
   244 
       
   245 	/**
       
   246 	 * Strips extra retweet data before comparing.
       
   247 	 *
       
   248 	 * @static
       
   249 	 * @param  string  $text
       
   250 	 * @return string
       
   251 	 */
       
   252 	private static function build_hash($text) {
       
   253 		$text = explode(' ', $text);
       
   254 		$content = '';
       
   255 		foreach ($text as $_content) {
       
   256 			if (!empty($_content) and strpos($_content, 'http://') === false) {
       
   257 				if ($_content == 'RT' or preg_match('/@([\w_]+):/i', $_content)) {
       
   258 					continue;
       
   259 				}
       
   260 
       
   261 				$content .= $_content.' ';
       
   262 			}
       
   263 		}
       
   264 
       
   265 		return md5(trim($content));
       
   266 	}
       
   267 
       
   268 	/**
       
   269 	 * Checks for a retweet via twitter API data and user perception.
       
   270 	 *
       
   271 	 * @static
       
   272 	 * @param  stdClass  $comment
       
   273 	 * @return bool
       
   274 	 */
       
   275 	public static function is_retweet($comment = null, $tweet = null) {
       
   276 		$is_retweet = false;
       
   277 		if (!is_null($comment)) {
       
   278 			if (isset($comment->social_raw_data) and !empty($comment->social_raw_data->retweeted_status)) {
       
   279 				$is_retweet = true;
       
   280 			}
       
   281 			if (substr($comment->comment_content, 0, 4) == 'RT @') {
       
   282 				$is_retweet = true;
       
   283 			}
       
   284 		}
       
   285 		else if (!is_null($tweet)) {
       
   286 			if (!empty($tweet->retweeted_status)) {
       
   287 				$is_retweet = true;
       
   288 			}
       
   289 			if (substr($tweet->text, 0, 4) == 'RT @') {
       
   290 				$is_retweet = true;
       
   291 			}
       
   292 		}
       
   293 		return $is_retweet;
       
   294 	}
       
   295 
       
   296 	/**
       
   297 	 * Adds a retweet to the original broadcasted post social items stack.
       
   298 	 *
       
   299 	 * @static
       
   300 	 * @param  int    $comment_id
       
   301 	 * @param  array  $comments
       
   302 	 * @param  array  $social_items
       
   303 	 */
       
   304 	private static function add_to_social_items($comment_id, &$comments, &$social_items) {
       
   305 		$object = null;
       
   306 		$_comments = array();
       
   307 		foreach ($comments as $id => $comment) {
       
   308 			if (is_int($id)) {
       
   309 				if ($comment->comment_ID == $comment_id) {
       
   310 					$object = $comment;
       
   311 				}
       
   312 				else {
       
   313 					$_comments[] = $comment;
       
   314 				}
       
   315 			}
       
   316 			else {
       
   317 				if (isset($_comments[$id])) {
       
   318 					$_comments[$id] = array_merge($_comments[$id], $comment);
       
   319 				}
       
   320 				else {
       
   321 					$_comments[$id] = $comment;
       
   322 				}
       
   323 			}
       
   324 		}
       
   325 		$comments = $_comments;
       
   326 
       
   327 		if ($object !== null) {
       
   328 			if (!isset($social_items['twitter'])) {
       
   329 				$social_items['twitter'] = array();
       
   330 			}
       
   331 
       
   332 			$social_items['twitter'][$comment_id] = $object;
       
   333 		}
       
   334 	}
       
   335 
       
   336 	/**
       
   337 	 * Adds messaging to the title.
       
   338 	 *
       
   339 	 * @static
       
   340 	 * @param  string  $title
       
   341 	 * @param  string  $key
       
   342 	 * @return string
       
   343 	 */
       
   344 	public static function social_item_output_title($title, $key) {
       
   345 		if ($key == 'twitter') {
       
   346 			$title .= __(' retweeted this', 'social');
       
   347 		}
       
   348 
       
   349 		return $title;
       
   350 	}
       
   351 
       
   352 	/**
       
   353 	 * Add a "reply to" field to broadcast form.
       
   354 	 *
       
   355 	 * @static
       
   356 	 * @param  obj  $post
       
   357 	 * @param  obj  $service
       
   358 	 * @param  obj  $account
       
   359 	 * @return void
       
   360 	 */
       
   361 	public static function social_broadcast_form_item_edit($post, $service, $account) {
       
   362 		if ($service->key() != 'twitter') {
       
   363 			return;
       
   364 		}
       
   365 		$field_name = str_replace('_content', '_in_reply_to', $account['field_name_content']);
       
   366 ?>
       
   367 <a href="#" class="tweet-reply-link"><?php _e('Send as a reply', 'social'); ?></a>
       
   368 <div class="tweet-reply-fields">
       
   369 	<label for="<?php echo esc_attr($field_name); ?>"><?php _e('URL of Tweet (to reply to)', 'social'); ?></label>
       
   370 	<input type="text" class="tweet-reply-field" name="<?php echo esc_attr($field_name); ?>" value="" id="<?php echo esc_attr($field_name); ?>" />
       
   371 </div>
       
   372 <?php
       
   373 	}
       
   374 
       
   375 } // End Social_Twitter
       
   376 
       
   377 define('SOCIAL_TWITTER_FILE', __FILE__);
       
   378 
       
   379 // Filters
       
   380 add_filter('social_register_service', array('Social_Twitter', 'register_service'));
       
   381 add_filter('get_avatar_comment_types', array('Social_Twitter', 'get_avatar_comment_types'));
       
   382 add_filter('social_comments_array', array('Social_Twitter', 'comments_array'), 10, 2);
       
   383 add_filter('social_save_broadcasted_ids_data', array('Social_Twitter', 'social_save_broadcasted_ids_data'), 10, 5);
       
   384 add_filter('social_item_output_title', array('Social_Twitter', 'social_item_output_title'), 10, 2);
       
   385 add_action('social_broadcast_form_item_edit', array('Social_Twitter', 'social_broadcast_form_item_edit'), 10, 3);
       
   386 
       
   387 }