t("Flat list - collapsed"), 2 => t("Flat list - expanded"), 3 => t("Threaded list - collapsed"), 4 => t("Threaded list - expanded"));
$GLOBALS["corder"] = array(1 => t("Date - newest first"), 2 => t("Date - oldest first"));
function comment_help() {
$output .= t("
The comment module enables users to submit posts that are directly associated with a piece of content, a node. These associated posts are called comments. Comments may be threaded, which means that Drupal keeps track of multiple subconversations around a piece of content. Threading helps to keep the comment conversation organized. Users are presented with several ways to view the comment conversation, and if desired, users may easily choose a flat presentation of comments instead of a threaded one. Further, users may choose to order their comments view by newest comments first or by oldest comments first. Finally, users may view a folded list, where only comment subjects are displayed, or an expanded list, where the whole comment is shown.
");
$output .= t("
Since a busy site generates lots of comments, Drupal takes care to present a personalized view of comments for each user. A user can setup how they want they comments displayed -- Threaded/Flat, Expanded/Folded -- and how many comments to display per page. If there are more comments than you have configured to display on a page, navigation links are displayed. The home page displays, for the current user, the number of read and unread comments for a given node. Also, the tracker module (when installed) displays all recent comments on the site. Finally, comments which the user has not yet read are highlighted with a red star (this graphic may depend on the current theme).
");
$output .= t("
Comments behave like other user submissions in Drupal. Specifically, if the administrator has enabled them, ". l("filters", "admin/system/filters") .", like smileys and HTML, work fine. Also, throttles are usually enabled to prevent a single user from spamming the web site with too many comments in a short period of time.
");
$output .= t("
Administrators may control which roles are allowed to submit, submit without moderation, view and administer comments using the \"post comments\", \"post comments without approval\", \"access comments\", and \"administrate comments\" ". l("user permissions", "admin/user/permission") .". Additionally, administrators may set the default display view, edit or search through comments on the ". l("comments admininistration page", "admin/comment") .".
");
$output .= t("
If you really have a lot of comments, you can enable moderation. You assign ". l("moderation permissions", "admin/user/permission") ." to role(s), then setup some \"". l("moderation votes","admin/comment/moderation/votes") ."\"; these votes will appear to moderators in a dropdown menu near the comment. You also have to assign, for every role and every vote, ". l("a value", "admin/comment/moderation/matrix") .", which can be either positive or negative. This allows, if you wish, some roles to have greater \"weight\" in their moderation. If you set a value to 0, that vote won't be available to that role. When a user moderates, the value of their vote is added or subtracted to the score of that comment. Next your have to setup the \"". l("Queue settings", "admin/system/modules/queue") ."\" to allow a moderated comment to either be posted or dumped. Finally, you may want to setup the ". l("comment thresholds", "admin/comment/moderation/threshold") .": these are floor/ceiling values which users can set in the comment control panel. Thresholds are useful for hiding poorly rated comments from your users while they are reading.
");
return $output;
}
function comment_system($field) {
$system["description"] = t("Enables user to comment on content (nodes).");
$system["admin_help"] = t("Comments can be attached to any node. Below are the settings for comments. The display comes in two types, a \"flat list\" where everything is flush to the left side, and comments come in cronological order, and a \"threaded list\" where comments to other comments are placed immediately below the orignal, and slightly indented forming an outline of comments. They also come in two styles: \"expanded\", where you get to see both the title and the contents, and \"collapsed\" where you only see the titles. To set the default threshold you first have to set up thresholds in the comment management >> comment moderation >> thresholds area. Preview comment forces a user to click on a \"Preview\" button so they can see what their comment will look like before they can actually add the comment to the system. If \"New comment form\" is enabled then at the bottom of every comment page there will be a form too add a new comment.", array("%threshold" => url("admin/comment/moderation/filters")));
return $system[$field];
}
function comment_settings() {
global $cmodes, $corder;
$output .= form_select(t("Default display mode"), "comment_default_mode", variable_get("comment_default_mode", 4), $cmodes, t("The default view for comments. Expanded views display the body of the comment. Threaded views keep replies together."));
$output .= form_select(t("Default display order"), "comment_default_order", variable_get("comment_default_order", 1), $corder, t("The default sorting for new users and anonymous users while viewing comments. These users may change their view using the comment control panel. For registered users, this change is remembered as a persistent user preference."));
$output .= form_textfield(t("Default comments per page"), "comment_default_per_page", variable_get("comment_default_per_page", "50"), 5, 5, t("Default number of comments for each page; more comments are distributed in several pages."));
$result = db_query("SELECT fid, filter FROM moderation_filters");
while ($filter = db_fetch_object($result)) {
$thresholds[$filter->fid] = ($filter->filter);
}
$output .= form_select(t("Default threshold"), "comment_default_threshold", variable_get("comment_default_threshold", 0), $thresholds, t("Thresholds are values below which comments are hidden. These thresholds are useful for busy sites which want to hide poor comments from most users."));
$output .= form_select(t("Preview comment"), "comment_preview", variable_get("comment_preview", 1), array(t("Optional"), t("Required")), t("Must users preview comments before submitting?"));
$output .= form_select(t("New comment form"), "comment_new_form", variable_get("comment_new_form", 0), array(t("Disabled"), t("Enabled")), t("New comment form in the node page?"));
$output .= form_select(t("Comment controls"), "comment_controls", variable_get("comment_controls", 0), array(t("Above comments"), t("Below comments"), t("Above and below")), t("Position of the comment controls box."));
return $output;
}
function comment_user($type, $edit, &$user) {
switch ($type) {
case "view_public":
if ($user->signature) {
return form_item(t("Signature"), check_output($user->signature));
}
break;
case "view_private":
if ($user->signature) {
return form_item(t("Signature"), check_output($user->signature));
}
break;
case "edit_form":
// when user tries to edit his own data
return form_textarea(t("Signature"), "signature", $edit["signature"], 70, 3, t("Your signature will be publicly displayed at the end of your comments.") ." ". t("Allowed HTML tags") .": ". htmlspecialchars(variable_get("allowed_html", "
";
}
else {
/*
** Multiple comments view
*/
$query .= "SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.data, c.score, c.users FROM comments c LEFT JOIN users u ON c.uid = u.uid WHERE c.nid = '". check_query($nid) ."' AND c.status = 0";
if ($cid) {
$query .= " AND pid = '". check_query($cid) ."'";
}
$query .= " GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.timestamp, u.uid, u.name, u.data, c.score, c.users";
if ($order == 1) {
$query .= " ORDER BY c.timestamp DESC";
}
else if ($order == 2) {
$query .= " ORDER BY c.timestamp";
}
/*
** Start a form, to use with comment control and moderation
*/
$result = db_query($query);
$comment_num = db_num_rows($result);
if ($comment_num && ((variable_get("comment_controls", 0) == 0) || (variable_get("comment_controls", 0) == 2))) {
print "";
}
print "";
if ($comment_num && ((variable_get("comment_controls", 0) == 1) || (variable_get("comment_controls", 0) == 2))) {
print "";
}
}
/*
** If enabled, show new comment form
*/
if (user_access("post comments") && node_comment_mode($nid) == 2 && variable_get("comment_new_form", 0)) {
theme("box", t("Post new comment"), comment_form(array("nid" => $nid)));
}
}
}
function comment_perm() {
return array("access comments", "post comments", "administer comments", "moderate comments", "post comments without approval", "administer moderation");
}
function comment_link($type, $node = 0, $main = 0) {
if ($type == "node" && $node->comment) {
if ($main) {
/*
** Main page: display the number of comments that have been posted.
*/
if (user_access("access comments")) {
$all = comment_num_all($node->nid);
$new = comment_num_new($node->nid);
if ($all) {
$links[] = l(format_plural($all, "1 comment", "%count comments"), "node/view/$node->nid#comment", array("title" => t("Jump to the first comment of this posting.")));
if ($new) {
$links[] = l(format_plural($new, "1 new comment", "%count new comments"), "node/view/$node->nid#new", array("title" => t("Jump to the first new comment of this posting.")));
}
}
else {
if (user_access("post comments")) {
$links[] = l(t("add new comment"), "comment/reply/$node->nid", array("title" => t("Add a new comment to this page.")));
}
else {
$links[] = theme("comment_post_forbidden");
}
}
}
}
else {
/*
** Node page: add a "post comment" link if the user is allowed to
** post comments and if this node is not read-only
*/
if ($node->comment == 2) {
if (user_access("post comments")) {
$links[] = l(t("add new comment"), "comment/reply/$node->nid#comment", array("title" => t("Share your thoughts and opinions related to this posting.")));
}
else {
$links[] = theme("comment_post_forbidden");
}
}
else {
$links[] = t("Closed discussion: you can't post new comments.");
}
}
}
if ($type == "admin" && user_access("administer comments")) {
$help["general"] = t("Comments let users give feedback to content authors. Here you may review/approve/deny recent comments, and configure moderation if desired.");
$help["post-overview"] = t("Click on new or updated comments to see your latest comments, or comment approval queue to approve new comments.", array("%nup" => url("admin/comment/0"), "%queue" => url("admin/comment/1")));
$help["new-update"] = t("Below is a list of the latest comments posted your site. Click on a subject to see the comment, the author's name to edit the author's user information , \"edit comment\" to edit the comment, and \"delete comment\" to remove the comment.");
$help["queue"] = t("Below is a list of the comments posted to your site that need approval. To approve a comment click on \"edit comment\" and then change it's moderation status to Approved. Click on a subject to see the comment, the author's name to edit the author's user information, \"edit comment\" to edit the comment, and \"delete comment\" to remove the comment.");
$help["moderation-overview"] = t("If you have a get a lot of comments, you can enable comment moderation. Once moderation is enabled users can vote on a comment based on dropdown menus. votes sets up the names of each item, and the order of the menu, using weights. matrix sets up the value of each user's vote, and threshold sets up the levels at which a comment will be displayed.", array("%votes" => url("admin/comment/moderation/votes"), "%matrix" => url("admin/comment/moderation/matrix"), "%threshold" => url("admin/comment/moderation/threshold")));
$help["moderation-vote"] = t("Here is where you setup the names of each type of vote. Weight lets you set the order of the drop down menu. Click edit to edit a current vote weight. Notes:
you can have more than one type with the same name. The system does not protect you from this.
To delete a name/weight combiniation go to the edit area.
");
$help["moderation-matrix"] = t("Here is where you assign a value to each item in the dropdown. This value is added to the vote total, which is then divided by the number of users who have voted and rounded off to the nearest integer. Notes:
In order to use comment moderation, every text box on this page should be populated.
You must assign the moderate comments permission to at least one role in order to use this page.
Every box not filled in will have a value of zero, which will have the effect of lowering a comments over all score.
");
$help["moderation-threshold"] = t("Optional Here you can setup the name and minimum \"cut off\" score to help your users hide comments that they don't want too see. These thresholds appear in the Comment Control Panel. Click \"edit\" to edit the values of an already exsisting threashold. To delete a threshold click on \"edit\". ");
$help["initial"] = t("Here you can setup the initial vote value of a comment posted by each user role. This value is used before any other users vote on the comment. Note: Blank entries are valued at zero");
$help["search"] = t("Enter a simple pattern ( '*' maybe used as a wildcard match) to search for a comment. For example, one may search for 'br' and Drupal might return 'bread brakers', 'our daily bread' and 'brenda'.");
menu("admin/comment", "comment management", "comment_admin", $help["general"], 2);
menu("admin/comment/comments", "comment overview",NULL, $help["post-overview"], 2);
menu("admin/comment/comments/0", "new or updated comments", "comment_admin", $help["new-update"], 1);
menu("admin/comment/comments/1", "comment approval queue", "comment_admin", $help["queue"], 2);
menu("admin/comment/search", "search comments", "comment_admin", $help["search"], 8);
menu("admin/comment/help", "help", "comment_help", NULL, 9);
menu("admin/comment/edit", "edit comment", "comment_admin", NULL, 0, 1);
// comment settings:
if (user_access("administer moderation")) {
menu("admin/comment/moderation", "comment moderation", NULL, $help["moderation-overview"], 3);
menu("admin/comment/moderation/votes", "votes", "comment_admin", $help["moderation-vote"]);
menu("admin/comment/moderation/matrix", "matrix", "comment_admin", $help["moderation-matrix"]);
menu("admin/comment/moderation/filters", "thresholds", "comment_admin", $help["moderation-threshold"]);
menu("admin/comment/roles", "initial comment scores", "comment_admin", $help["initial"], 6);
}
}
return $links ? $links : array();
}
function comment_page() {
$op = $_POST["op"];
$edit = $_POST["edit"];
if (empty($op)) {
$op = arg(1);
}
switch ($op) {
case "edit":
theme("header");
comment_edit(check_query(arg(2)));
theme("footer");
break;
case t("Moderate comments"):
case t("Moderate comment"):
comment_moderate($edit);
drupal_goto(url("node/view/". $edit["nid"]));
break;
case "reply":
theme("header");
comment_reply(check_query(arg(3)), check_query(arg(2)));
theme("footer");
break;
case t("Preview comment"):
theme("header");
comment_preview($edit);
theme("footer");
break;
case t("Post comment"):
list($error_title, $error_body) = comment_post($edit);
if ($error_body) {
theme("header");
theme("box", $error_title, $error_body);
theme("footer");
}
else {
drupal_goto(url("node/view/". $edit["nid"]));
}
break;
case t("Save settings"):
$mode = $_POST["mode"];
$order = $_POST["order"];
$threshold = $_POST["threshold"];
$comments_per_page = $_POST["comments_per_page"];
comment_save_settings(check_query($mode), check_query($order), check_query($threshold), check_query($comments_per_page));
drupal_goto(url("node/view/". $edit["nid"], "mode=$mode&order=$order&threshold=$threshold&comments_per_page=$comments_per_page"));
break;
}
}
/**
*** admin functions
**/
function comment_node_link($node) {
if (user_access("administer comments")) {
/*
** Edit comments:
*/
$result = db_query("SELECT c.cid, c.subject, u.uid, u.name FROM comments c LEFT JOIN users u ON u.uid = c.uid WHERE nid = %d AND c.status = 0 ORDER BY c.timestamp", $node->nid);
$header = array(t("title"), t("author"), array("data" => t("operations"), "colspan" => 3));
while ($comment = db_fetch_object($result)) {
$rows[] = array(l($comment->subject, "node/view/$node->nid#$comment->cid"), format_name($comment), l(t("view comment"), "node/view/$node->nid#$comment->cid"), l(t("edit comment"), "admin/comment/edit/$comment->cid"), l(t("delete comment"), "admin/comment/delete/$comment->cid"));
}
if ($rows) {
$output = "
". t("Edit comments") ."
";
$output .= table($header, $rows);
}
return $output;
}
}
function comment_admin_edit($id) {
$result = db_query("SELECT c.*, u.name, u.uid FROM comments c LEFT JOIN users u ON c.uid = u.uid WHERE c.cid = %d AND c.status != 2", $id);
$comment = db_fetch_object($result);
// if a comment is "deleted", it's deleted
if ($comment) {
$form .= form_item(t("Author"), format_name($comment));
$form .= form_textfield(t("Subject"), "subject", $comment->subject, 70, 128);
$form .= form_textarea(t("Comment"), "comment", $comment->comment, 70, 15);
$form .= form_select(t("Status"), "status", $comment->status, array("published", "not published"));
$form .= form_hidden("cid", $id);
$form .= form_submit(t("Submit"));
$form .= form_submit(t("Delete"));
return form($form);
}
}
function comment_delete($edit) {
if ($edit["confirm"]) {
db_query("UPDATE comments SET status = 2 WHERE cid = %d", $edit["cid"]);
watchdog("special", "comment: deleted comment #". $edit["cid"]);
$output = "deleted comment.";
}
else {
$output .= form_item(t("Confirm deletion"), "");
$output .= form_hidden("cid", $edit["cid"]);
$output .= form_hidden("confirm", 1);
$output .= form_submit(t("Delete"));
$output = form($output);
}
return $output;
}
function comment_save($id, $edit) {
db_query("UPDATE comments SET subject = '%s', comment = '%s', status = %d WHERE cid = %d", $edit["subject"], $edit["comment"], $edit["status"], $id);
watchdog("special", "comment: modified '". $edit["subject"] ."'");
return "updated comment.";
}
function comment_admin_overview($status = 0) {
$result = pager_query("SELECT c.*, u.name, u.uid FROM comments c LEFT JOIN users u ON u.uid = c.uid WHERE c.status = '". check_query($status). "' ORDER BY c.timestamp DESC", 50);
$header = array(t("subject"), t("author"), t("status"), array("data" => t("operations"), "colspan" => 2));
while ($comment = db_fetch_object($result)) {
$rows[] = array(l($comment->subject, "node/view/$comment->nid/$comment->cid#$comment->cid", array("title" => htmlspecialchars(substr($comment->comment, 0, 128)))) ." ". (node_is_new($comment->nid, $comment->timestamp) ? theme_mark() : ""), format_name($comment), ($comment->status == 0 ? t("published") : t("not published")) ."
";
}
}
}
function comment_thread_max($comment, $threshold, $level = 0) {
/*
** We had quite a few browser specific issues: expanded comments below
** the top level got truncated on the right hand side. A range of
** solutions have been proposed and tried but either the right margins of
** the comments didn't line up well, or the heavily nested tables made
** for slow rendering and cluttered HTML. This is the best work-around
** in terms of speed and size.
*/
if ($level) {
print "
\n";
}
}
function comment_post_forbidden() {
global $user;
if ($user->uid) {
return t("You can't post comments.");
}
else {
return t("%login or %register to post comments", array("%login" => l(t("login"), "user/login"), "%register" => l(t("register"), "user/register")));
}
}
/**
*** misc functions: helpers, privates, history, search
**/
function comment_visible($comment, $threshold = 0) {
if ($comment->score >= $threshold) {
return 1;
}
else {
return 0;
}
}
function comment_moderate() {
global $moderation, $user;
if ($moderation) {
$result = db_query("SELECT mid, value FROM moderation_roles WHERE rid = %d", $user->rid);
while ($mod = db_fetch_object($result)) {
$votes[$mod->mid] = $mod->value;
}
$node = node_load(array("nid" => db_result(db_query("SELECT nid FROM comments WHERE cid = %d", key($moderation)))));
if (user_access("administer comments") || comment_user_can_moderate($node)) {
foreach ($moderation as $cid => $vote) {
if ($vote) {
if (($vote == 'offline') && (user_access("administer comments"))) {
db_query("UPDATE comments SET status = 1 WHERE cid = %d", $cid);
watchdog("special", "comment: unpublished comment #". $cid);
/*
** Fire a hook
*/
module_invoke_all("comment", "unpublish", $cid);
}
else {
$comment = db_fetch_object(db_query("SELECT * FROM comments WHERE cid = %d", $cid));
$users = unserialize($comment->users);
if ($user->uid != $comment->uid && !(comment_already_moderated($user->uid, $comment->users))) {
$users[$user->uid] = $vote;
$tot_score = 0;
foreach ($users as $uid => $vote) {
if ($uid) {
$tot_score = $tot_score + $votes[$vote];
}
else {
// vote 0 is the start value
$tot_score = $tot_score + $vote;
}
}
$new_score = round($tot_score / count($users));
db_query("UPDATE comments SET score = '$new_score', users = '%s' WHERE cid = %d", serialize($users), $cid);
/*
** Fire a hook
*/
module_invoke_all("comment", "moderate", $cid, $vote);
}
}
}
}
}
}
}
function comment_save_settings($mode, $order, $threshold, $comments_per_page) {
global $user;
if ($user->uid) {
$user = user_save($user, array("mode" => $mode, "sort" => $order, "threshold" => $threshold, "comments_per_page" => $comments_per_page));
}
}
function comment_num_all($nid) {
static $cache;
if (!isset($cache[$nid])) {
$comment = db_fetch_object(db_query("SELECT COUNT(c.nid) AS number FROM node n LEFT JOIN comments c ON n.nid = c.nid WHERE n.nid = %d AND c.status = 0 GROUP BY n.nid", $nid));
$cache[$nid] = $comment->number ? $comment->number : 0;
}
return $cache[$nid];
}
function comment_num_replies($id) {
static $cache;
if (!isset($cache[$nid])) {
$result = db_query("SELECT COUNT(cid) FROM comments WHERE pid = %d AND status = 0", $id);
$cache[$nid] = $result ? db_result($result, 0) : 0;
}
return $cache[$nid];
}
/**
* get number of new comments for current user and specified node
*
* @param $nid node-id to count comments for
* @param $timestamp time to count from (defaults to time of last user access to node)
*/
function comment_num_new($nid, $timestamp = 0) {
global $user;
if ($user->uid) {
/*
** Retrieve the timestamp at which the current user last viewed the
** specified node.
*/
if (!$timestamp) {
$timestamp = node_last_viewed($nid);
}
/*
** Use the timestamp to retrieve the number of new comments
*/
$result = db_result(db_query("SELECT COUNT(c.cid) FROM node n LEFT JOIN comments c ON n.nid = c.nid WHERE n.nid = %d AND timestamp > %d AND c.status = 0", $nid, $timestamp));
return $result;
}
else {
return 0;
}
}
function comment_thread_structure($comments, $pid, $depth, $structure) {
$depth++;
foreach ($comments as $key => $comment) {
if ($comment->pid == $pid) {
$structure[$comment->cid] = $depth;
$structure = comment_thread_structure($comments, $comment->cid, $depth, $structure);
}
}
return $structure;
}
function comment_user_can_moderate($node) {
global $user;
return (user_access("moderate comments"));
// TODO: || (($user->uid == $node->uid) && user_access("moderate comments in owned node")));
}
function comment_already_moderated($uid, $users) {
$comment_users = unserialize($users);
if (!$comment_users) {
$comment_users = array();
}
return in_array($uid, array_keys($comment_users));
}
function comment_search($keys) {
/*
** Return the results of performing a search using the indexed search
** for this particular type of node.
**
** Pass an array to the "do_search" function which dictates what it
** will search through, and what it will search for
**
** "keys"'s value is the keywords entered by the user
**
** "type"'s value is used to identify the node type in the search
** index.
**
** "select"'s value is used to relate the data from the specific nodes
** table to the data that the search_index table has in it, and the the
** do_search functino will rank it.
**
** The select must always provide the following fields - lno, title,
** created, uid, name, count
**
** The select statement may optionally provide "nid", which is a secondary
** identifier which is currently used byt the comment module.
*/
$find = do_search(array("keys" => $keys, "type" => "comment", "select" => "select s.lno as lno, c.nid as nid, c.subject as title, c.timestamp as created, u.uid as uid, u.name as name, s.count as count FROM search_index s, comments c LEFT JOIN users u ON c.uid = u.uid WHERE s.lno = c.cid AND s.type = 'comment' AND c.status = 0 AND s.word like '%'"));
return $find;
}
function comment_update_index() {
/*
** Return an array of values to dictate how to update the search index
** for this particular type of node.
**
** "last_update"'s value is used with variable_set to set the
** last time this node type (comment) had an index update run.
**
** "node_type"'s value is used to identify the node type in the search
** index (commentt in this case).
**
** "select"'s value is used to select the node id and text fields from
** the table we are indexing. In this case, we also check against the
** last run date for the comments update.
*/
return array("last_update" => "comment_cron_last", "node_type" => "comment", "select" => "SELECT c.cid as lno, c.subject as text1, c.comment as text2 FROM comments c WHERE c.status = 0 AND timestamp > ". variable_get("comment_cron_last", 1));
}
function comment_nodeapi(&$node, $op, $arg = 0) {
switch ($op) {
case "settings":
$output[t("comment")] = form_select("", "comment_$node->type", variable_get("comment_$node->type", 2), array("Disabled", "Read only", "Read/Write"));
return $output;
case "fields":
return array("comment");
case "form admin":
if (user_access("administer comments")) {
$selected = isset($node->comment) ? $node->comment : variable_get("comment_$node->type", 2);
$output = form_radio(t("Disabled"), "comment", 0, ($selected == 0));
$output .= form_radio(t("Read only"), "comment", 1, ($selected == 1));
$output .= form_radio(t("Read/write"), "comment", 2, ($selected == 2));
return form_item(t("Allow user comments"), $output);
}
break;
case "validate":
if (!user_access("administer nodes")) {
// Force default for normal users:
$node->comment = variable_get("comment_$node->type", 2);
}
break;
case "delete":
db_query("DELETE FROM comments WHERE nid = '$node->nid'");
break;
}
}
?>