Permalink
Fetching contributors…
Cannot retrieve contributors at this time
executable file 401 lines (361 sloc) 11.4 KB
<?php
/**
* Twitter implementation for Social.
*
* @package Social
* @subpackage plugins
*/
if (class_exists('Social') and !class_exists('Social_Twitter')) {
final class Social_Twitter {
/**
* Registers Twitter to Social.
*
* @static
* @wp-filter social_register_service
*
* @param array $services
*
* @return array
*/
public static function register_service(array $services) {
$services[] = 'twitter';
return $services;
}
/**
* Adds to the avatar comment types array.
*
* @static
* @param array $types
* @return array
*/
public static function get_avatar_comment_types(array $types) {
return array_merge($types, Social_Service_Twitter::comment_types());
}
/**
* Pre-processor to the comments.
*
* @wp-filter social_comments_array
* @static
* @param array $comments
* @param int $post_id
* @return array
*/
public static function comments_array(array $comments, $post_id) {
// pre-load the hashes for broadcasted tweets
$broadcasted_ids = get_post_meta($post_id, '_social_broadcasted_ids', true);
if (empty($broadcasted_ids)) {
$broadcasted_ids = array();
}
global $wpdb;
// we need comments to be keyed by ID, check for Tweet comments
$tweet_comments = $_comments = $comment_ids = array();
foreach ($comments as $key => $comment) {
if (is_object($comment)) {
$_comments['id_'.$comment->comment_ID] = $comment;
if (in_array($comment->comment_type, Social_Service_Twitter::comment_types())) {
$comment_ids[] = $comment->comment_ID;
$tweet_comments['id_'.$comment->comment_ID] = $comment;
}
}
else { // social items
$_comments[$key] = $comment;
}
}
// if no tweet comments, get out now
if (!count($tweet_comments)) {
return $comments;
}
// use our keyed array
$comments = $_comments;
unset($_comments);
$social_map = array(); // key = social id, value = comment_ID
$hash_map = array(); // key = hash, value = comment_ID
$broadcasted_social_ids = array();
$broadcast_retweets = array(); // array of comments
if (isset($broadcasted_ids['twitter'])) {
foreach ($broadcasted_ids['twitter'] as $account_id => $broadcasted) {
foreach ($broadcasted as $id => $data) {
$broadcasted_social_ids[] = $id;
// if we don't have a message saved for a tweet, try to get it so that we can use it next time
if (empty($data['message'])) {
$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');
wp_remote_get(str_replace('&amp;', '&', $url), array(
'timeout' => 0.01,
'blocking' => false,
));
}
else {
// create a hash from the broadcast so we can match retweets to it
$hash = self::build_hash($data['message']);
// This is stored as broadcasted and not the ID so we can easily store broadcasted retweets
// instead of attaching retweets to non-existent comments.
$hash_map[$hash] = 'broadcasted';
}
}
}
}
// Load the comment meta
$results = $wpdb->get_results("
SELECT meta_key, meta_value, comment_id
FROM $wpdb->commentmeta
WHERE comment_id IN (".implode(',', $comment_ids).")
AND (
meta_key = 'social_in_reply_to_status_id'
OR meta_key = 'social_status_id'
OR meta_key = 'social_raw_data'
OR meta_key = 'social_profile_image_url'
OR meta_key = 'social_comment_type'
)
");
// Set up social data for twitter comments
foreach ($tweet_comments as $key => &$comment) {
$comment->social_items = array();
// Attach meta
foreach ($results as $result) {
if ($comment->comment_ID == $result->comment_id) {
switch ($result->meta_key) {
case 'social_raw_data':
$comment->social_raw_data = json_decode(base64_decode($result->meta_value));
break;
case 'social_status_id':
$social_map[$result->meta_value] = $result->comment_id;
default:
$comment->{$result->meta_key} = $result->meta_value;
}
}
}
// Attach hash
if (isset($comment->social_raw_data) and isset($comment->social_raw_data->text)) {
$text = trim($comment->social_raw_data->text);
}
else {
$text = trim($comment->comment_content);
}
$comment->social_hash = self::build_hash($text);
if (!isset($hash_map[$comment->social_hash])) {
$hash_map[$comment->social_hash] = $comment->comment_ID;
}
}
// merge data so that $comments has the data we've set up
$comments = array_merge($comments, $tweet_comments);
// set-up replies and retweets
foreach ($tweet_comments as $key => &$comment) {
if (is_object($comment)) {
// set reply/comment parent
if (!empty($comment->social_in_reply_to_status_id) and isset($social_map[$comment->social_in_reply_to_status_id])) {
$comments[$key]->comment_parent = $social_map[$comment->social_in_reply_to_status_id];
}
// set retweets
$rt_matched = false;
if (isset($comment->social_raw_data) and isset($comment->social_raw_data->retweeted_status)) {
// explicit match via API data
$rt_id = $comment->social_raw_data->retweeted_status->id_str;
if (in_array($rt_id, $broadcasted_social_ids)) {
$broadcast_retweets[] = $comment;
unset($comments[$key]);
$rt_matched = true;
}
else if (isset($social_map[$rt_id]) and isset($comments['id_'.$social_map[$rt_id]])) {
$comments['id_'.$social_map[$rt_id]]->social_items[$key] = $comment;
unset($comments[$key]);
$rt_matched = true;
}
}
if (!$rt_matched) {
// best guess via hashes
$hash_match = $hash_map[$comment->social_hash];
if ($hash_match != $comment->comment_ID) { // hash match to own tweet is expected, at minimum - set above
if ($hash_match == 'broadcasted') {
$broadcast_retweets[] = $comment;
}
else if (isset($comments['id_'.$hash_match])) {
$comments['id_'.$hash_match]->social_items[$key] = $comment;
}
else {
// Loop through the broadcasted retweets and see if this is a retweet of one of those.
foreach ($broadcast_retweets as $retweet) {
if ($retweet->comment_ID == $hash_match) {
$broadcast_retweets[] = $comment;
break;
}
}
}
unset($comments[$key]);
}
}
}
}
if (!isset($comments['social_items'])) {
$comments['social_items'] = array();
}
if (count($broadcast_retweets)) {
$comments['social_items']['twitter'] = $broadcast_retweets;
}
return $comments;
}
/**
* Enqueues the @Anywhere script.
*
* @static
* @return void
*/
public static function enqueue_assets() {
$api_key = Social::option('twitter_anywhere_api_key');
if (!empty($api_key)) {
wp_enqueue_script('twitter_anywhere', 'http://platform.twitter.com/anywhere.js?id='.$api_key, array('social_js'), Social::$version, true);
}
}
/**
* Sets the raw data for the broadcasted post.
*
* @wp-filter social_broadcast_response
* @static
* @param array $data
* @param Social_Service_Account $account
* @param string $service_key
* @param int $post_id
* @param Social_Response $response
* @return array
*/
public static function social_save_broadcasted_ids_data(array $data, Social_Service_Account $account, $service_key, $post_id, Social_Response $response = null) {
if ($service_key == 'twitter') {
if (!empty($response)) {
$data['message'] = base64_encode(json_encode($response->body()->response));
}
$data['account'] = (object) array(
'user' => $account->as_object()->user
);
}
return $data;
}
/**
* Strips extra retweet data before comparing.
*
* @static
* @param string $text
* @return string
*/
private static function build_hash($text) {
$text = explode(' ', $text);
$content = '';
foreach ($text as $_content) {
if (!empty($_content) and strpos($_content, 'http://') === false) {
if ($_content == 'RT' or preg_match('/@([\w_]+):/i', $_content)) {
continue;
}
$content .= $_content.' ';
}
}
return md5(trim($content));
}
/**
* Checks for a retweet via twitter API data and user perception.
*
* @static
* @param stdClass $comment
* @return bool
*/
public static function is_retweet($comment = null, $tweet = null) {
$is_retweet = false;
if (!is_null($comment)) {
if (isset($comment->social_raw_data) and !empty($comment->social_raw_data->retweeted_status)) {
$is_retweet = true;
}
if (substr($comment->comment_content, 0, 4) == 'RT @') {
$is_retweet = true;
}
}
else if (!is_null($tweet)) {
if (!empty($tweet->retweeted_status)) {
$is_retweet = true;
}
if (substr($tweet->text, 0, 4) == 'RT @') {
$is_retweet = true;
}
}
return $is_retweet;
}
/**
* Adds a retweet to the original broadcasted post social items stack.
*
* @static
* @param int $comment_id
* @param array $comments
* @param array $social_items
*/
private static function add_to_social_items($comment_id, &$comments, &$social_items) {
$object = null;
$_comments = array();
foreach ($comments as $id => $comment) {
if (is_int($id)) {
if ($comment->comment_ID == $comment_id) {
$object = $comment;
}
else {
$_comments[] = $comment;
}
}
else {
if (isset($_comments[$id])) {
$_comments[$id] = array_merge($_comments[$id], $comment);
}
else {
$_comments[$id] = $comment;
}
}
}
$comments = $_comments;
if ($object !== null) {
if (!isset($social_items['twitter'])) {
$social_items['twitter'] = array();
}
$social_items['twitter'][$comment_id] = $object;
}
}
/**
* Adds messaging to the title.
*
* @static
* @param string $title
* @param string $key
* @return string
*/
public static function social_item_output_title($title, $key) {
if ($key == 'twitter') {
$title .= __(' retweeted this', 'social');
}
return $title;
}
/**
* Add a "reply to" field to broadcast form.
*
* @static
* @param obj $post
* @param obj $service
* @param obj $account
* @return void
*/
public static function social_broadcast_form_item_edit($post, $service, $account) {
if ($service->key() != 'twitter') {
return;
}
$field_name = str_replace('_content', '_in_reply_to', $account['field_name_content']);
?>
<a href="#" class="tweet-reply-link"><?php _e('Send as a reply', 'social'); ?></a>
<div class="tweet-reply-fields">
<label for="<?php echo esc_attr($field_name); ?>"><?php _e('URL of Tweet (to reply to)', 'social'); ?></label>
<input type="text" class="tweet-reply-field" name="<?php echo esc_attr($field_name); ?>" value="" id="<?php echo esc_attr($field_name); ?>" />
</div>
<?php
}
} // End Social_Twitter
define('SOCIAL_TWITTER_FILE', __FILE__);
// Filters
add_filter('social_register_service', array('Social_Twitter', 'register_service'));
add_filter('get_avatar_comment_types', array('Social_Twitter', 'get_avatar_comment_types'));
add_filter('social_comments_array', array('Social_Twitter', 'comments_array'), 10, 2);
add_filter('social_save_broadcasted_ids_data', array('Social_Twitter', 'social_save_broadcasted_ids_data'), 10, 5);
add_filter('social_item_output_title', array('Social_Twitter', 'social_item_output_title'), 10, 2);
add_action('wp_enqueue_scripts', array('Social_Twitter', 'enqueue_assets'));
add_action('social_broadcast_form_item_edit', array('Social_Twitter', 'social_broadcast_form_item_edit'), 10, 3);
}