100) */ function tmac_get_mentions( $postID ) { //Retrive last ID checked for on this post so we don't re-add a comment already added $lastID = get_post_meta( $postID, 'tmac_last_id', true ); //Build URL $url = 'http://search.twitter.com/search.json?rpp=100&since_id=' . $lastID . '&q=' . urlencode( get_permalink( $postID ) ); //make the API call and pass it back $data = json_decode( wp_remote_retrieve_body( wp_remote_get( $url ) ) ); return $data; } /** * Inserts mentions into the comments table, queues and checks for spam as necessary * @params int postID ID of post to check for comments * @since .1a * @returns int number of tweets found */ function tmac_insert_metions( $postID ) { //get options $options = tmac_get_options(); //Get array of mentions $mentions = tmac_get_mentions( $postID ); //if there are no tweets, update post meta to speed up subsequent calls and return if ( sizeof( $mentions->results ) == 0) { update_post_meta($postID, 'tmac_last_id', $mentions->max_id ); return 0; } //loop through mentions foreach ($mentions->results as $tweet) { //If they exclude RTs, look for "RT" and skip if needed if (!$options['RTs']) { if (strpos($tweet->text,'RT') != FALSE) continue; } //Format the author's name based on cache or call API if necessary $author = tmac_build_author_name( $tweet->from_user ); //prepare comment array $commentdata = array( 'comment_post_ID' => $postID, 'comment_author' => $author, 'comment_author_email' => $tweet->from_user . '@twitter.com', 'comment_author_url' => 'http://twitter.com/' . $tweet->from_user . '/status/' . $tweet->id, 'comment_content' => $tweet->text, 'comment_date_gmt' => date('Y-m-d H:i:s', strtotime($tweet->created_at) ), 'comment_type' => $options['comment_type'] ); //insert comment using our modified function $comment_id = tmac_new_comment( $commentdata ); //Cache the user's profile image add_comment_meta($comment_id, 'tmac_image', $tweet->profile_image_url, true); } //If we found a mention, update the last_Id post meta update_post_meta($postID, 'tmac_last_id', $mentions->max_id ); //return number of mentions found return sizeof( $mentions->results ); } /** * Function to run on cron to check for mentions * @since .1a * @returns int number of mentions found * @todo break query into multiple queries so recent posts are checked more frequently */ function tmac_mentions_check(){ $mentions = 0; //get limit $options = tmac_get_options(); //Get all posts $posts = get_posts('numberposts=' . $options['posts_per_check'] ); //Loop through each post and check for new mentions foreach ($posts as $post) { $mentions += tmac_insert_metions( $post->ID ); } return $mentions; } /** * Resets internal API counter every hour * * User API is limited to 150 unauthenticated calls / hour * Authenticated API is limited to 350 / hour * Search calls do not count toward total, although search has an unpublished limit * * @since .2 * @todo query the API for our actual limit */ function tmac_reset_api_counter() { global $tmac_api_counter; $tmac_api_counter = 0; } //Register Cron on activation register_activation_hook(__FILE__, 'tmac_activation'); add_action('tmac_hourly_check', 'tmac_mentions_check'); add_action('tmac_hourly_check', 'tmac_reset_api_counter'); /** * Callback to call hourly to check for new mentions * @since .1a */ function tmac_activation() { wp_schedule_event(time(), 'hourly', 'tmac_hourly_check'); $options = get_option('tmac_options'); //If the comment_type option is not set (upgrade), set it if ( empty( $options['comment_type'] ) ) $options['comment_type'] = ''; if ( empty( $options['posts_per_check'] ) ) $options['posts_per_check'] = '-1'; update_option('tmac_options', $options); } //Kill cron on deactivation register_deactivation_hook(__FILE__, 'tmac_deactivation'); /** * Callback to remove cron job * @since .1a */ function tmac_deactivation() { wp_clear_scheduled_hook('tmac_hourly_check'); } /** * Custom new_comment function to allow overiding of timestamp to meet tweet's timestamp * * (Adaptation of wp_new_comment from /wp-includes/comments.php, * original function does not allow for overriding timestamp, * copied from v 3.1 ) * * @params array $commentdata assoc. array of comment data, same format as wp_insert_comment() * @since .1a */ function tmac_new_comment( $commentdata ) { $commentdata = apply_filters('preprocess_comment', $commentdata); $commentdata['comment_post_ID'] = (int) $commentdata['comment_post_ID']; if ( isset($commentdata['user_ID']) ) $commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID']; elseif ( isset($commentdata['user_id']) ) $commentdata['user_id'] = (int) $commentdata['user_id']; $commentdata['comment_parent'] = isset($commentdata['comment_parent']) ? absint($commentdata['comment_parent']) : 0; $parent_status = ( 0 < $commentdata['comment_parent'] ) ? wp_get_comment_status($commentdata['comment_parent']) : ''; $commentdata['comment_parent'] = ( 'approved' == $parent_status || 'unapproved' == $parent_status ) ? $commentdata['comment_parent'] : 0; // BEGIN TMAC MODIFICATIONS (don't use current timestamp but rather twitter timestamp) $commentdata['comment_author_IP'] = ''; $commentdata['comment_agent'] = 'Twitter Mentions as Comments'; $commentdata['comment_date'] = get_date_from_gmt( $commentdata['comment_date_gmt'] ); // END TMAC MODIFICATIONS $commentdata = wp_filter_comment($commentdata); $commentdata['comment_approved'] = wp_allow_comment($commentdata); $comment_ID = wp_insert_comment($commentdata); do_action('comment_post', $comment_ID, $commentdata['comment_approved']); if ( 'spam' !== $commentdata['comment_approved'] ) { // If it's spam save it silently for later crunching if ( '0' == $commentdata['comment_approved'] ) wp_notify_moderator($comment_ID); $post = &get_post($commentdata['comment_post_ID']); // Don't notify if it's your own comment if ( get_option('comments_notify') && $commentdata['comment_approved'] && ( ! isset( $commentdata['user_id'] ) || $post->post_author != $commentdata['user_id'] ) ) wp_notify_postauthor($comment_ID, empty( $commentdata['comment_type'] ) ? $commentdata['comment_type'] : '' ); } return $comment_ID; } /** * Retrieves twitter profile image given a twitter username, stores in comment meta * @param string twitterID twitter handle to lookup * @param int comment_id ID of comment to store meta on (for caching) * @since .1a * @returns string url of profile image */ function tmac_get_profile_image( $twitterID, $comment_id) { //Check to see if we already have the image stored in comment meta $image = get_comment_meta($comment_id, 'tmac_image', true); //If we don't already have the immage, call the twitter API if (!$image) { $data = tmac_query_twitter( $twitterID ); $image = $data->profile_image_url; //Cache the image URL add_comment_meta($comment_id, 'tmac_image', $image, true); } return $image; } /** * Checks for previous tweet-commments by the author and tries to retrieve their cached real name * @param string $twitterID handle of twitter user * @returns string their real name * @since .2 */ function tmac_get_author_name( $twitterID ) { global $wpdb; //Check to see if twitter user has previously commented, if so just grab their name $name = $wpdb->get_var( $wpdb->prepare( "SELECT comment_author FROM $wpdb->comments WHERE comment_author_email = %s and comment_approved = '1' LIMIT 1", $twitterID . '@twitter.com' ) ); //if they do not previosly have a comment, or that comment doesn't have a real name, call the Twitter API if ( empty( $name ) | substr($name, 0, 1) == '@' ) { //Query the API $data = tmac_query_twitter( $twitterID ); //If we hit the API limit, kick if ( !$data ) return false; //Because our query will return the name in the form of REAL NAME (@Handle), split the string at "(@" $name = substr( $data->name, strrpos($data->name, '(@') ); } //return the name return $name; } /** * Formats a comment authors name in either the Real Name (@handle) or @handle format depending on information available * @param string $twitterID twitter handle of user * @returns string the formatted name * @since .2 */ function tmac_build_author_name( $twitterID ) { //get the cached real name or query the API $real_name = tmac_get_author_name( $twitterID ); //If we don't have a real name, just use their twitter handle if ( !$real_name ) $name = '@' . $twitterID; //if we have their real name, build a pretty name else $name = $real_name . ' (@' . $twitterID . ')'; //return the name return $name; } /** * Calls the public twitter API and retrieves information on a given user * @param string $handle handle of twitter user * @returns array assoc. array of info returned * @since .1 */ function tmac_query_twitter( $handle ) { global $tmac_api_calls; $options = tmac_get_options(); //increment API counter $tmac_api_calls++; //if we are over the limit, kick if ( $tmac_api_calls > $options['api_call_limit'] ) return false; //build the URL $url = 'http://api.twitter.com/1/users/show/'. $handle .'.json'; //make the call $data = json_decode( wp_remote_retrieve_body( wp_remote_get( $url ) ) ); return $data; } /** * Filters default avatar since tweets don't have an e-mail but do have a profile image * @param string $avatar default image * @param object data comment data * @since .1a */ function tmac_filter_avatar( $avatar, $data) { //If this is a real comment (not a tweet), kick if ($data->comment_agent != 'Twitter Mentions as Comments') return $avatar; //get the url of the image $url = tmac_get_profile_image ( substr( $data->comment_author, 1 ), $data->comment_ID); //replace the twitter image with the default avatar and return return preg_replace("/http:\/\/([^']*)/", $url, $avatar); } add_filter('get_avatar', 'tmac_filter_avatar', 10, 2); /** * Tells WP that we're using a custom settings field */ function tmac_options_int() { register_setting( 'tmac_options', 'tmac_options' ); } add_action( 'admin_init', 'tmac_options_int' ); /** * Creates the options sub-panel * @since .1a */ function tmac_options() { ?>