Ronald Huereca
Description: Allows you and your users to edit their comments inline. Admin and editors can edit all comments.
Special Thanks: An extra special thanks goes out to Vivien from Inspiration Bit (http://www.inspirationbit.com). Without her, this plugin release wouldn't have been possible. Brett Terpstra from Circle Six Design (http://blog.circlesixdesign.com) helped fix a rather major bug as well during testing. Thank you Brett.
Copyright 2007 Ronald Huereca (email : ron alfy [a t ] g m ail DOT com)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
if (function_exists('wp_enqueue_script')) {
wp_enqueue_script('ajax_edit_comments', get_bloginfo('wpurl') . '/wp-content/plugins/wp-ajax-edit-comments/js-includes/wp-ajax-edit-comments.js.php', array('jquery'), '1.0');
}
class WPrapAjaxEditComments {
var $commentClassName = "editComment"; //Do not edit this name
var $commentAuthorName = "editAuthor"; //Do not edit this name
var $skipDiv = false;
var $minutes = 30;
var $admin = "true";
var $cookieName = "WPrapAjaxEditCommentId";//Do not edit this name
var $optionsName = "WPAjaxEditComments"; //Do not edit this name
var $userOptionsName = "WPAjaxEditAuthorUserOptions";
var $adminOptions = false;
var $userOptions = false; //Do not edit this name
var $isAdminPage = "false";
//constructor
function WPrapAjaxEditComments() {
}
//Run when the plugin is first activated
function init() {
$this->getAdminOptions();
}
//Returns an array of admin options
function getAdminOptions() {
if ($this->adminOptions == false) {
$optionsName = $this->optionsName;
$adminOptions = array(
'allow_editing' => 'true',
'minutes' => '30',
'edit_text' => 'You may click on your name and/or comment to edit.',
'show_timer' => 'true'
);
$options = get_option($optionsName);
if (!empty($options)) {
foreach ($options as $key => $option)
$adminOptions[$key] = $option;
}
update_option($optionsName, $adminOptions);
$this->adminOptions = $adminOptions;
}
return $this->adminOptions;
}
//Returns an array of user options
function getUserOptions() {
global $user_email;
if ($this->userOptions == false) {
if (empty($user_email)) {get_currentuserinfo();}
if (empty($user_email)) { return ''; }
$optionsName = $this->userOptionsName;
$defaults = array('author_editing' => 'true',
'comment_editing' => 'true',
'admin_editing' => 'false',
'inline_editing' => 'false',
'show_links' => 'false'
);
$userOptions = get_option($optionsName);
if (!isset($userOptions)) {
$userOptions = array();
}
//See if an older version doesn't match the new defaults
if (empty($userOptions[$user_email])) {
$userOptions[$user_email] = $defaults;
update_option(optionsName, $userOptions);
} else {
foreach ($userOptions[$user_email] as $key => $option)
$defaults[$key] = $option;
$userOptions[$user_email] = $defaults;
//update_option(optionsName, $userOptions);
}
$this->userOptions = $userOptions;
}
return $this->userOptions;
}
//Adds a paragraph to the beginning of the text
//Takes in the text, a comment ID, and a post ID
function addEditParagraph($text, $id, $postId) {
if (!$this->canEditPostsPage($postId)) {
//todo - Add an option so admin can disable this
$text = "
" . $text;
return $text;
}
return $text;
}
//Add in place holders for the Edit, Delete, Spam, Disapprove buttons - Skip out if in the admin panel
function addApprovalParagraph($text, $commentId, $postId) {
if (empty($commentId) || empty($postId) || is_admin()) { return $text; }
global $user_email;
if (empty($user_email)) {
get_currentuserinfo();
}
if (empty($user_email)) { return $text; }
$author_options = $this->getUserOptions();
//Get the author options
if (!empty($author_options[$user_email])) {
if ($author_options[$user_email]['show_links'] == "true") { return $text; }
}
$links = '';
if (current_user_can('edit_post', $postId))
$links .= 'Edit | Delete | Spam';
if (strlen($links) > 0)
$text = $text . '
[ ' . $links . ' ]
';
return $text;
}
//Returns true or false depending if the admin can inline edit
function canInlineEdit() {
global $user_email;
if (empty($user_email)) {
get_currentuserinfo();
}
if (empty($user_email)) { return "true"; } //not logged in so they don't have a choice
$author_options = $this->getUserOptions();
//Get the author options
if (!empty($author_options[$user_email])) {
if ($author_options[$user_email]['inline_editing'] == "true") { return "false"; }
}
return "true";
}
//Adds a div to the comment text with a class name so that the AJAX can change the text to a textbox
function addCommentDiv($text) {
global $comment;
$className = "post";
if (is_admin()) { $className = "admin"; }
if (empty($comment)) { return $text; }
if (!$this->canEdit($comment->comment_ID, $comment->comment_post_ID) || !$this->canEditComment()) { return $text; }
//Skip this if admin
$text = $this->addEditParagraph($text, $comment->comment_ID, $comment->comment_post_ID);
if ($this->skipDiv) { return $text; }
//Regular expression to check if there is a div already added
$pattern = '/div class=\"' . $this->commentClassName . '\"/i';
//If there is not a div already, add it in
if (!preg_match($pattern, $text)) {
$text = '
' . $text . '
';
}
$text = $this->addApprovalParagraph($text, $comment->comment_ID, $comment->comment_post_ID);
return $text;
} //End function addCommentDiv()
function addAuthorSpan($text) {
global $comment;
$className = "post";
if (is_admin()) { $className = "admin"; }
if (!$this->canEdit($comment->comment_ID, $comment->comment_post_ID) || !$this->canEditAuthor()) { return $text; }
//Regular expression to check if there is a div already added
$pattern = '/span class=\"' . $this->commentAuthorName . '\"/i';
//If there is not a div already, add it in
if (!preg_match($pattern, $text)) {
$text = '' . $text . '';
}
return $text;
} //End function addAuthorDiv()
//Prints out the admin page
function printAdminPage() {
$WPAjaxEditComments = $this->getAdminOptions();
if (!empty($savedOptions)) {
$WPAjaxEditComments = $savedOptions;
}
if (isset($_POST['update_wp_ajaxEditCommentSettings'])) {
$error = false;
$updated = false;
//Validate the comment time entered
if (isset($_POST['wpAJAXCommentTime'])) {
$commentTimeErrorMessage = '';
$commentClass = 'error';
if (!preg_match('/^\d+$/i', $_POST['wpAJAXCommentTime'])) {
$commentTimeErrorMessage = "Comment time must be a numerical value";
$error = true;
} elseif($_POST['wpAJAXCommentTime'] < 1) {
$commentTimeErrorMessage = "Comment time must be greater than one minute.";
$error = true;
} else {
$WPAjaxEditComments['minutes'] = $_POST['wpAJAXCommentTime'];
$updated = true;
}
if (!empty($commentTimeErrorMessage)) {
?>
JS();
}
}//End function addHeaderJS
function addAdminHeaderJS() {
global $user_email;
if (empty($user_email)) {
get_currentuserinfo();
}
if (empty($user_email)) { return; }
$author_options = $this->getUserOptions();
//Get the author options
if (!empty($author_options[$user_email])) {
if ($author_options[$user_email]['admin_editing'] == "true") { return; }
}
$this->JS();
}
function JS() {
echo "\n";
}
//Returns a comment for editing in a textbox
//Takes in a comment id
function getComment($id) {
global $wpdb;
if (!$this->canEdit($id, $post->ID)) { return 0; }
//mysql_query("SET NAMES 'utf8'", $conn);
$comment = $wpdb->get_row("SELECT * FROM $wpdb->comments WHERE comment_ID = ".$id);
if (!$comment) { return 0; }
//Get the comment ready for the textbox
$content = apply_filters('comment_edit_save', $comment->comment_content);
return $content;
}//End function getComment
function deleteComment($id) {
$comment = get_comment($id);
if (!$comment) { return false; }
if ( current_user_can( 'edit_post', $comment->comment_post_ID) ) {
if (!wp_delete_comment($id)) { return true; }
} else {
return false;
}
return true;
}
function spamComment($id) {
$comment = get_comment($id);
if (!$comment) { return false; }
if ( current_user_can( 'edit_post', $comment->comment_post_ID) ) {
if (!wp_set_comment_status($id, 'spam')) { return false; }
} else {
return false;
}
return true;
}
function disapproveComment($id) {
global $post; if (empty($post)) { return; }
if ( current_user_can( 'edit_post', $post->ID ) && current_user_can( 'moderate_comments' ) )
if (!wp_set_comment_status( $id, 'hold' )) { return false; }
else return false;
return true;
}
//Strips the ID to just numbers
function getCommentID($id) {
preg_match('/([0-9]+)$/i', $id, $matches);
if (is_numeric($matches[1])) {
return $matches[1];
} else {
return 0;
}
} //End function getCommentID
//Returns the text such as "You may click on author/comment to edit"
function getEditText() {
$options = $this->getAdminOptions();
return apply_filters('the_title',$options['edit_text']);
}
//Returns how much time is left to edit on a comment in a comma deliminated variable
//Returns $minutes,$seconds
//Takes in a comment ID
//One concern here is if the admin increases the time in the admin panel - The user will be under the impression that there is more time to edit than there really is. This is a minor and rare bug, so I chose to leave it alone.
function getTimeLeft($id) {
global $wpdb;
if (empty($id)) { return "0,0"; }
$adminEdit = $this->getAdminOptions();
$adminMinutes = $adminEdit['minutes'];
$query = "SELECT UNIX_TIMESTAMP(comment_date) time FROM $wpdb->comments where comment_ID = $id";
//Get the IP, Date, and Timestamp
$comment = $wpdb->get_row($query, ARRAY_A);
$timestamp = $comment['time'];
//Check to see if there's a valid cookie
//Get the time elapsed since making the comment
$time = time()-$timestamp;
$timeLeft = ($adminMinutes * 60) - $time; //seconds
if ($timeLeft <= 0) { return "0,0"; }
$minutesPassed = floor($timeLeft/60);
$seconds = $timeLeft - ($minutesPassed*60);
return "$minutesPassed,$seconds";
}//end function getTimeLeft
//Saves the author to the database
/*id = The comment id
url = The author's url
name = The author's name*/
function saveAuthor($id, $url, $name) {
global $wpdb;
if (!$this->canEdit($id, $post->ID)) { return 0; }
if (!isset($name)) {
return 0;
}
if (trim($name) == '') { return 0; }
$url = urldecode($url);
$name = urldecode($name);
$url = trim(apply_filters('comment_url', $url));
$saveUrl = apply_filters('pre_comment_author_url', $url);
$name = apply_filters('comment_author', $name);
$saveName = apply_filters('pre_commment_author_name', $name);
if(!$wpdb->query("UPDATE $wpdb->comments SET comment_author = '{$saveName}', comment_author_url = '{$saveUrl}' WHERE comment_ID = $id")) {
return 0;
}
$url = stripslashes($url);
$name = stripslashes($name);
$returnText = '';
if (!empty($url)) {
$returnText = '' . $name . '';
} else {
$returnText = $name;
}
//For WP Cache
if (function_exists("wp_cache_get_postid_from_comment")) {
wp_cache_get_postid_from_comment($id);
}
return $returnText;
} //End function saveAuthor
//Saves the edited comment to the database
function saveComment($id, $content) {
global $wpdb, $post;
if (trim($content) == '') { return 0; }
if (!$this->canEdit($id, $post->ID)) { return 0; }
$content = urldecode($content);
$content = apply_filters('comment_save_pre', $content);
$saveContent = apply_filters('pre_comment_content', $content);
if(!$wpdb->query("UPDATE $wpdb->comments SET comment_content = '{$saveContent}' WHERE comment_ID = $id")) {
return 0;
}
$this->skipDiv = true;
$content = apply_filters('comment_text', $content);
$content = $this->addEditParagraph($content, $id, $post->ID);
$this->skipDiv = false;
//For WP Cache
if (function_exists("wp_cache_get_postid_from_comment")) {
wp_cache_get_postid_from_comment($id);
}
return stripslashes($content);
} //end function saveComment
//Determines if a comment can be edited or not based on the ID and time elapsed
//$id = The comment id
//$postId = The post id for the comment
//Returns true if the comment can be edited, false if not
function canEdit($id, $postId) {
global $wpdb;
if (empty($id)) { return false; }
//Return true if the user can edit the comment
if ($this->canEditPostsPage($postId)) { return true; }
//Checks to see if the admin has allowed comment editing
$adminEdit = $this->getAdminOptions();
$adminEdit = $adminEdit['allow_editing'];
if (empty($adminEdit)) {
$adminEdit = $this->admin;
}
if ($adminEdit != 'true') {
return false;
}
$query = "SELECT UNIX_TIMESTAMP(comment_date) time, comment_author_IP, comment_date_gmt FROM $wpdb->comments where comment_ID = $id";
//Get the IP, Date, and Timestamp
$comment = $wpdb->get_row($query, ARRAY_A);
$hash = md5($comment['comment_author_IP'] . $comment['comment_date_gmt']);
$timestamp = $comment['time'];
//Check to see if there's a valid cookie
if (isset($_COOKIE[$this->cookieName . $id . $hash])) {
//Get the time elapsed since making the comment
$time = time()-$timestamp;
$minutesPassed = round(((($time%604800)%86400)%3600)/60);
//Get the time the admin has set for minutes
$minutes = $this->getAdminOptions();
$minutes = $minutes['minutes'];
if (!is_numeric($minutes)) {
$minutes = $this->minutes;
}
if ($minutes < 1) {
$minutes = $this->minutes;
}
//Compare the minutes passed to the admin minutes
if ($minutesPassed) {
if ($minutesPassed > $minutes) { return false; }
}
return true;
}
return false;
}//end function canEdit
//Returns true if a person can edit a post/page
//Returns false otherwise
//Called by canEdit() and setCommentCookie
function canEditPostsPage($postId) {
//Stolen, err, borrowed from edit_comment_link()
if (!current_user_can('edit_page', $postId)) {return false; }
if (!current_user_can('edit_post', $postId)) {return false; }
return true;
}//end function canEditPostsPage
//Returns true unless the user has disabled author editing
function canEditAuthor() {
global $user_email;
if (empty($user_email)) {
get_currentuserinfo();
}
if (empty($user_email)) { return true; }
$author_options = $this->getUserOptions();
//Get the author options
if (!empty($author_options[$user_email])) {
if ($author_options[$user_email]['author_editing'] == "false") { return false; }
}
return true;
} //end function canEditAuthor
//Returns true unless the user has disabled comment editing
function canEditComment() {
global $user_email;
if (empty($user_email)) {
get_currentuserinfo();
}
if (empty($user_email)) { return true; }
$author_options = $this->getUserOptions();
//Get the author options
if (!empty($author_options[$user_email])) {
if ($author_options[$user_email]['comment_editing'] == "false") { return false; }
}
return true;
}
//Sets a comment cookie for the commentator (treat as a private function)
function setCommentCookie($commentId) {
global $comment, $wpdb;
//Return if setting the cookie is unnecessary
if ($this->canEditPostsPage($post->ID)) { return $commentId; }
//Get the IP, Date, and Timestamp
if (empty($comment)) {
$comment = $wpdb->get_row("SELECT * FROM $wpdb->comments where comment_ID = $commentId", ARRAY_A);
}
$hash = md5($comment['comment_author_IP'] . $comment['comment_date_gmt']);
//Get the time the admin has set for minutes
$minutes = $this->getAdminOptions();
$minutes = $minutes['minutes'];
if (!is_numeric($minutes)) {
$minutes = $this->minutes;
}
if ($minutes < 1) {
$minutes = $this->minutes;
}
//Set the cookie
$cookieName = $this->cookieName . $commentId . $hash;
$value = $cookieName;
$expire = time()+60*$minutes;
if (!isset($_COOKIE[$cookieName])) {
setcookie($cookieName, $value, $expire, COOKIEPATH, COOKIE_DOMAIN);
}
return $commentId;
} //end function setCommentCookie
}//End Class WPrapAjaxEditComments
if (class_exists("WPrapAjaxEditComments")) {
$rap_ajaxComment = new WPrapAjaxEditComments();
}
//Initialize the admin panel
function WPrapAjaxEditComments_ap() {
global $rap_ajaxComment;
if (!isset($rap_ajaxComment)) {
return;
}
if (function_exists('add_options_page')) {
add_options_page('AJAX Edit Comments', 'AJAX Edit Comments', 9, basename(__FILE__), array(&$rap_ajaxComment, 'printAdminPage'));
}
if (function_exists('add_submenu_page')) {
add_submenu_page('profile.php', "AJAX Edit Comments Options","AJAX Edit Comments", 9, basename(__FILE__), array(&$rap_ajaxComment, 'printAuthorPage'));
}
}
//Template tag WPrapAjaxEditComments_CanEdit
//Returns true if a user can edit - False if they can't - Must be run within the loop
//Also returns false if people are admins
function WPrapAjaxEditComments_CanEdit() {
global $comment, $rap_ajaxComment;
//If we're not in the loop, return false
if (!isset($comment) || !isset($rap_ajaxComment)) { return false; }
//If admin, return false
if ($rap_ajaxComment->canEditPostsPage($comment->comment_post_ID)) {
return false;
}
//Find out if the user can edit
if ($rap_ajaxComment->canEdit($comment->comment_ID, $comment->comment_post_ID)) {
return true;
}
return false;
}
//Yay, actions.
if (isset($rap_ajaxComment)) {
add_action('admin_menu', 'WPrapAjaxEditComments_ap');
add_action('admin_head', array(&$rap_ajaxComment, 'addAdminHeaderJS'));
add_action('wp_head', array(&$rap_ajaxComment, 'addHeaderJS'));
add_action('comment_post', array(&$rap_ajaxComment, 'setCommentCookie'));
add_action('activate_wp-ajax-edit-comments/wp-ajax-edit-comments.php', array(&$rap_ajaxComment, 'init'));
//Yay, filters.
add_filter('comment_text', array(&$rap_ajaxComment, 'addCommentDiv'), '1000'); //Low priority so other HTML can be added first
add_filter('get_comment_author_link', array(&$rap_ajaxComment, 'addAuthorSpan'), '1000'); //Low priority so other HTML can be added first
}
?>