plugin_path = WP_PLUGIN_URL . '/friendfeed-comments/'; } else { $this->plugin_path = get_option('siteurl') . '/' . PLUGINDIR . '/friendfeed-comments/'; } $this->table_name = $wpdb->prefix . $this->table_name; $options = get_option($this->options_key); if (!$options['excludejslibrary']) { wp_enqueue_script($options['jslibrary']); } } /** * Callback to create the Settings menu option * */ function _create_options_menu_item() { add_options_page($this->plugin_name, $this->plugin_name, 9, __FILE__, array(&$this, 'options_page')); add_action('admin_notices', array(&$this, '_admin_notices')); } /** * Callback to display admin notices if needed (reminder to set the username) * */ function _admin_notices() { $options = get_option($this->options_key); if ((!$options || !$options['nickname']) && !$_POST['ff_nickname']) { echo "

FriendFeed Comments does not have a nickname set. You need to enter your FriendFeed nickname for the comments to be loaded.

"; } } /** * Callback to setup the plugin * */ function _install() { $this->create_table(); wp_schedule_event( time(), 'hourly', 'update_friendfeedcomments_hook' ); $options = get_option($this->options_key); if (!$options) { $options['nickname'] = ''; $options['apikey'] = ''; $options['servicename'] = 'blog'; $options['showcomments'] = false; $options['headline'] = false; $options['showform'] = true; $options['disableshowhide'] = false; $options['usestyles'] = true; $options['jslibrary'] = 'prototype'; $options['excludejslibrary'] = false; update_option($this->options_key, $options); } else { if (!$options['jslibrary']) { $options['jslibrary'] = 'prototype'; } } update_option($this->options_key, $options); } /** * Callback to unstall the plugin. * */ function _uninstall() { wp_clear_scheduled_hook('update_friendfeedcomments_hook'); } /** * Callback to add the needed items to the page header * */ function _add_page_header() { $options = get_option($this->options_key); if ($options['usestyles']) { print "\tplugin_path ."defaultStyle.css\" />\n"; } print "\t\n"; print "\t\n"; } /** * Add a section to the edit page to select the post * */ function _add_edit_form_section() { global $post; if ($_REQUEST['reloadff']) { $this->update_friendfeedcomments(); } $titles = get_option($this->titles_key); if ($post && $post->ID && is_array($titles) && count($titles) > 0) { $discussion = $this->get_discussion_for_post($post->ID); ?>

+FriendFeed Comments post

Hopefully you won't need to change this. The FriendFeed Comments plugin should link your post to the item on FriendFeed, but sometimes it can't. This is often due to the title of the post changing, but sometimes it just doesn't work. So if the wrong post, or none, is selected here, pick the right one and click save.

Linked to title; ?> on FriendFeed [Change]
set_post_for_entry($_POST['friendfeedcomments-post'], $_POST['post_ID']); $this->update_friendfeedcomments(); } } /** * Check if the debug flag is set by either in-code or by the ffdebugflag querystring value * * @return bool */ function is_debug() { return $this->is_debug || $_REQUEST['ffdebugflag']; } /** * Delete the stored username & password for the user & remove the cookie * */ function remove_authentication() { if ($_COOKIE[$this->cookie_key]) { $hash = $_COOKIE[$this->cookie_key]; $apikeys = get_option($this->apikeys_key); if ($apikeys && !is_array($apikeys)) { $apikeys = unserialize($apikeys); } if (is_array($apikeys)) { unset($apikeys[$hash]); } update_option($this->apikeys_key, $apikeys); setcookie($this->cookie_key, '', time() - 31536000, COOKIEPATH, COOKIE_DOMAIN); } } /** * Update the apikey for the user * * @param string $username * @param string $apikey */ function update_apikey($username, $apikey) { $apikeys = get_option($this->apikeys_key); if (!is_array($apikeys)) { $apikeys = array(); } $hash = md5($username + time()); $apikeys[$hash] = array($username, $apikey); update_option($this->apikeys_key, $apikeys); setcookie($this->cookie_key, $hash, time() + 31536000, COOKIEPATH, COOKIE_DOMAIN); } /** * Get the username & apikey stored for a user given the cookie * * @return array */ function get_authentication() { $auth = false; if ($_COOKIE[$this->cookie_key]) { $hash = $_COOKIE[$this->cookie_key]; $apikeys = get_option($this->apikeys_key); if (!is_array($apikeys)) { $apikeys = unserialize($apikeys); } if (is_array($apikeys)) { $auth = $apikeys[$hash]; } } return $auth; } /** * Format the title into a normalised string that can be used as a hash key * The inputed title has most non-alphanumeric characters replaced, then it's urlencoded * then md5 hashed * * @param string $title The input title * @return string The encoded string hash */ function format_title($title) { $normalised = $title; $normalised = str_replace(array("‘", "’", "“", "”", "`", '"', "'", ',', ':', urldecode('%93'), urldecode('’'), urldecode('‘'), urldecode('“'), urldecode('”')), '', $normalised); $normalised = urlencode($normalised); $normalised = preg_replace("/%E2%80%9./i", '', $normalised); if ($this->is_debug()) { $this->printr($title . ' - ' . $normalised . ' - ' . md5($normalised)); } return md5($normalised); } /** * Debug output. Utility method that wraps print_r in
 tags for easier viewing in HTML
	 *
	 * @param string $string The string to display
	 * @param bool $exit If true the script will exit immediately after diplaying
	 */
	function printr($string, $exit = false) {
		print "
";
		print_r($string);
		print "
"; if ($exit) { exit; } } /** * Checks whether the entries table exists * * @global $wpdb * @return bool True if the table exists */ function table_exists() { global $wpdb; return $wpdb->query($wpdb->prepare("show tables like '$this->table_name'")) > 0; } /** * Create a blank version of the table, checks for existance first **/ function create_table() { global $wpdb; if (!$this->table_exists()) { $sql = "CREATE TABLE $this->table_name ( entry_id varchar( 50 ) CHARACTER SET utf8 NOT NULL , title varchar( 200 ) CHARACTER SET utf8 NOT NULL , key_val varchar( 200 ) CHARACTER SET utf8 NOT NULL , post_id int( 10 ) unsigned default NULL , comments longtext CHARACTER SET utf8 NOT NULL , likes longtext CHARACTER SET utf8 NOT NULL , created_on datetime NOT NULL , PRIMARY KEY ( entry_id ) , UNIQUE KEY post_id ( post_id ) ) ENGINE = InnoDB COLLATE = utf8_general_ci"; $wpdb->query($wpdb->prepare($sql)); } } /** * Remove the data table * * @global $wpdb * */ function drop_table() { global $wpdb; $wpdb->query($wpdb->prepare("DROP TABLE IF EXISTS $this->table_name ;")); } /** * Remove all items from the table * * @global $wpdb * */ function empty_table() { global $wpdb; $wpdb->query($wpdb->prepare("TRUNCATE TABLE $this->table_name ;")); } /** * Update the entry in the database * * @param string $entry_id * @param array $comments * @param array $likes * @return int Positive if update was successful */ function update_entry($entry_id, $comments, $likes) { global $wpdb; if (is_array($comments)) { $comments = serialize($comments); } if (is_array($likes)) { $likes = serialize($likes); } $data = compact( 'comments', 'likes' ); return $wpdb->update($this->table_name, $data, array('entry_id' => $entry_id)); } /** * Insert an entry into the database * * @global $wpdb * @param string $entry_id * @param string $title * @param array $comments * @param array $likes */ function add_entry($entry_id, $title, $comments, $likes) { global $wpdb; if (is_array($comments)) { $comments = serialize($comments); } if (is_array($likes)) { $likes = serialize($likes); } $return = $wpdb->query( $wpdb->prepare("INSERT INTO $this->table_name (entry_id, title, key_val, post_id, comments, likes, created_on) VALUES ('%s', '%s', '%s', null, '%s', '%s', '%s')", $entry_id, $title, $this->format_title($title), $comments, $likes, current_time('mysql') )); } /** * Link an entry to a blog post, remove other links to that entry * * @param string $entry_id * @param int $post_id * @return int Positive if successful */ function set_post_for_entry($entry_id, $post_id) { global $wpdb; $wpdb->query($wpdb->prepare("UPDATE $this->table_name SET post_id = null where post_id = $post_id")); return $wpdb->update($this->table_name, array('post_id' => $post_id), array('entry_id' => $entry_id)); } /** * Tries to get the discussions for a post. If the discussion isn't currently linked to a post, * it will try to link it based on the title * * @param int $post_id * @param bool $check_cache * @return object The discussion object from the db */ function get_discussion_for_post($post_id, $check_cache = true) { global $wpdb; $discussion = ($check_cache ? wp_cache_get('post_' . $post_id, $this->cache_key) : false); if (!is_object($discussion)) { //Lookup based on post_id $discussion = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $this->table_name WHERE post_id = $post_id" ) ); if (!$discussion) { //Serialise the post's title & look based on that key $post = get_post($post_id); if ($post && $post->post_title) { $key = $this->format_title(trim($post->post_title)); $discussion = $wpdb->get_row($wpdb->prepare("SELECT * FROM $this->table_name WHERE key_val = '%s'", $key)); if ($discussion) { $discussion->post_id = $post_id; $this->set_post_for_entry($discussion->entry_id, $post_id); } } } //If the discussion was found, deserialise the comments & likes & add to the cache if ($discussion) { $discussion->comments = unserialize($discussion->comments); $discussion->likes = unserialize($discussion->likes); wp_cache_add('post_' . $post_id, $discussion, $this->cache_key); } } return $discussion; } /** * Load the discussions from the FriendFeed API * * @return void */ function update_friendfeedcomments() { $options = get_option($this->options_key); $friendfeed = new FriendFeed($options['nickname']); if ($options && $friendfeed) { if ($this->is_debug()) { $this->printr("Loading FriendFeed Data"); } $ff_entries = $friendfeed->fetch_user_feed($options['nickname'], $options['servicename']); if ($ff_entries && is_array($ff_entries->entries)) { //Load up the posts from FriendFeed up to the max number of posts to load set for ($i = $this->page_size ; $i <= $this->max_posts_to_load - $this->page_size; $i = $i + $this->page_size) { $temp_posts = $friendfeed->fetch_user_feed($options['nickname'], $options['servicename'], $i, $this->page_size); if ($temp_posts && is_array($temp_posts->entries)) { $ff_entries->entries = array_merge($ff_entries->entries, $temp_posts->entries); } else { $i = $this->max_posts_to_load; } } $blog_url = parse_url(strtolower(get_option('home'))); $match_count = 0; $titles = get_option($this->titles_key); if (!is_array($titles)) { $titles = array(); } foreach($ff_entries->entries as $entry) { $post_url = parse_url(strtolower($entry->service->profileUrl)); $is_same_blog = ( $blog_url['host'] == $post_url['host'] || $blog_url['host'] == 'www.' . $post_url['host'] || 'www.' . $blog_url['host'] == $post_url['host'] ) && ( ($post_url['path'] == $blog_url['path'] . '/') || ($post_url['path'] .'/' == $blog_url['path']) || ($post_url['path'] == $blog_url['path']) ); if ($is_same_blog) { if ($titles[$entry->id]) { $this->update_entry($entry->id, $entry->comments, $entry->likes); } else { $this->add_entry($entry->id, $entry->title, $entry->comments, $entry->likes); $titles[$entry->id] = $entry->title; } $match_count++; } } update_option($this->titles_key, $titles); if ($this->is_debug()) { $this->printr(count($ff_entries->entries) . " entries loaded from FriendFeed"); $this->printr("$match_count entries loaded, " . count($titles) . " total entries stored."); $this->printr('** Discussions **'); $this->printr($titles); $this->printr('** Posts **'); $this->printr($ff_entries); } } else { return false; } } return true; } /** * Remove all the data stored for the plugin * * @param bool $remove_table If true the database table will be dropped not just deleted */ function delete_all_data($remove_table = false) { delete_option($this->titles_key); if($remove_table) { $this->drop_table(); } else { $this->empty_table(); } } /** * Function to render the options page * */ function options_page() { $options = get_option($this->options_key); $error = false; if ($_POST["wp_friendfeed"]) { if ($_POST['ff_showdebug']) { $this->is_debug = true; } if ($_POST['Clear']) { $this->delete_all_data(); if ($this->update_friendfeedcomments()) { $message = "Discussions reloaded."; } else { $error = "Unable to retrieve content from FriendFeed. The API may be down or there may be connectivity problems"; } } elseif ($_POST['Delete']) { delete_option($this->options_key); $this->delete_all_data(true); unset($_POST); unset($options); $message = "All information related to this plugin has been deleted. To finish removing this plugin, deactivate it on the Plugins page"; } else { if (!$error) { $options['nickname'] = $_POST['ff_nickname']; $options['servicename'] = $_POST['ff_servicename']; $options['showcomments'] = $_POST['ff_showcomments']; $options['headline'] = $_POST['ff_headline']; $options['showform'] = $_POST['ff_showform']; $options['disableshowhide'] = $_POST['ff_disableshowhide']; $options['usestyles'] = $_POST['ff_usestyles']; $options['excludejslibrary'] = $_POST['ff_excludejslibrary']; $options['jslibrary'] = $_POST['ff_jslibrary']; update_option($this->options_key, $options); if ($this->update_friendfeedcomments()) { $message = "Settings Saved. Don't forget to put <?php wp_ffcomments(); ?> on your single post template to display the FriendFeed comments & likes."; } else { $error = "Unable to retrieve content from FriendFeed. The API may be down or there may be connectivity problems"; } } } if ($error) { $message = "Error: " . $error; } if ($message) { ?>
>

FriendFeed Comments

FriendFeed Nickname
Use default stylesheet />
If this is checked the plugin will import the default stylesheet for styling the display of the comments & likes lists. This is meant as a starting point, please feel free to use the styles & adapt them for your site.
Click here to view the default stylesheet.
Enable comments & likes form />
If this is checked the plugin will display a small form under the comments to allow the reader to add a comment or 'like' on the post FriendFeed.
Headline Text
This is the text that will be shown above the comments & likes. The tokens {comments} & {likes} will be replaced with the number of comments & likes for the post. Leave this blank to use the default "On FriendFeed, this post was liked by x people and commented on x times".
Show comments by default />
If this is checked the FriendFeed comments & likes will be shown by default. If not checked the user will have to click on the 'show' link to display them.
Disable show/hide button />
If this is unchecked the show/hide button will be displayed. Check this if you don't want people to change the layout of the comments.
FriendFeed Servicename
This is the name that FriendFeed knows your blog as. Unless you don't use the 'blog' service on FriendFeed, you probably won't need to change this.
Javascript Library
Advanced option. This plugin can use either the Prototype or JQuery. By default it runs with Prototype, but if your site already includes JQuery, Prototype doesn't work. If you're having issues with the dynamic features of the plugin, try changing this value.
Exclude Javascript Library value="1" />
Advanced option. If your theme already includes a version of the Prototype/Jquery javascript library & it's conflicting with this plugin, check this box. If you don't include Prototype or Jquery at all, this plugin won't work
Display debug information
Check this if you want to see the information that is being loaded by the plugin when you save. Only needed for troubleshooting.

Did you find this plugin useful? Please consider donating to help me continue developing it and other plugins.

\n"; for($i = 0; $i < $count; $i++) { $like = $likes[$i]; $output_string .= "\t\t\t\t
  • user->profileUrl}\">{$like->user->name}" . ($i < $count - 1 ? ", " : '') . "
  • \n"; } $output_string .= "\t\t\t\n"; } } return $output_string; } /** * Build up the string to display the list of comments. * * @param array $comments * @return string The rendered comments list to display as HTML */ function render_comments_list($comments) { $output_string = ''; if (!is_array($comments)) { $comments = unserialize ($comments); } if (is_array($comments)) { $output_string .= "\n"; } return $output_string; } /** * Render an individual comment * * @param object $comment * @return string The rendered comment to display */ function render_comment($comment) { $output_string = ''; $timeformat = get_option('time_format'); $dateformat = get_option('date_format'); $time = date($timeformat, $comment->date); $date = date($dateformat, $comment->date); $output_string .= "\t\t\t
  • \n"; $output_string .= "\t\t\t\tuser->profileUrl}\" class=\"profileImage\">user->nickname}/picture?size=medium\" alt=\"\" />"; $output_string .= "\t\t\t\t\n"; $output_string .= "\t\t\t\t
    " . make_clickable($comment->body) . "
    \n"; $output_string .= "\t\t\t
  • \n"; return $output_string; } /** * Render the output of the plugin * */ function display_comments() { global $post, $wp_query; if ( !$post && (is_single() || is_page() )) { $post = $wp_query->get_queried_object(); } $discussion = $this->get_discussion_for_post($post->ID); $options = get_option($this->options_key); if ($this->is_debug()) { $this->printr($options); $this->printr($discussion); } if ($discussion) { $ffpostid = $discussion->entry_id; $comment_count = (is_array($discussion->comments) ? count($discussion->comments) : 0); $like_count = (is_array($discussion->likes) ? count($discussion->likes) : 0); if ($options['headline']) { $headline_text = str_replace('{comments}', $comment_count, $options['headline']); $headline_text = str_replace('{likes}', $like_count, $headline_text); } else { $headline_text = 'On FriendFeed, this post was '; $headline_text .= "liked by $like_count " . ($like_count <> 1 ? 'people' : 'person'); $headline_text .= " and "; $headline_text .= " commented on $comment_count" . ($comment_count <> 1 ? ' times' : ' time'); } ?>
    \n"; print "\t\t
    \n\t\t"; if ($comment_count) { print $this->render_comments_list($discussion->comments); } print "
    \n"; if ($options['showform']) { $username = ''; $apikey = ''; $auth = $this->get_authentication(); if ($auth) { $username = $auth[0]; $apikey = $auth[1]; } ?>

    Add a comment on FriendFeed




    class="ff_authsaved" id="ff_authsaved_"> Logged in as [logout]
    />
    display_comments(); } ?>