Here's a little background:
One of my clients wants to allow comments on their web site. However, they would like to "feature" particularly good comments and "hide" others. They do not want to delete the "hidden" comments. This was a criteria of the blog, which is why I chose to host it on s9y.
I am pasting the steps I used to make this feature. If anyone can point me in the direction for making this modular it would be greatly appreciated!
--Keith
Code: Select all
<!-- SQL: -->
<!-- First, alter the database: -->
ALTER TABLE `serendipity_comments` ADD `is_featured` ENUM( '0', '1' ) NOT NULL DEFAULT '0';
<!-- [blog root]/templates/[template-name|default]/comments.tpl -->
<!-- Replace everything -->
{foreach from=$comments item=comment name="comments"}
<a id="c{$comment.id}"></a>
{if $comment.is_featured == "0" and $hiddenOn <> "true"}{assign var="hiddenOn" value="true"}<div style="display:none;" id="hiddenComments" name="hiddenComments">{/if}
<div id="serendipity_comment_{$comment.id}" class="serendipity_comment serendipity_comment_author_{$comment.author|@makeFilename} {if $entry.author == $comment.author}serendipity_comment_author_self{/if} {cycle values="comment_oddbox, comment_evenbox"}" style="padding-left: {$comment.depth*20}px">
<div class="serendipity_commentBody">
{if $comment.body == 'COMMENT_DELETED'}
{$CONST.COMMENT_IS_DELETED}
{else}
{$comment.body}
{/if}
</div>
<div class="serendipity_comment_source">
<a class="comment_source_trace" href="#c{$comment.id}">#{$comment.trace}</a>
<span class="comment_source_author">
{if $comment.email}
<a href="mailto:{$comment.email}">{$comment.author|@default:$CONST.ANONYMOUS}</a>
{else}
{$comment.author|@default:$CONST.ANONYMOUS}
{/if}
</span>
{if $comment.url}
(<a class="comment_source_url" href="{$comment.url}" title="{$comment.url|@escape}">{$CONST.HOMEPAGE}</a>)
{/if}
{$CONST.ON}
<span class="comment_source_date">{$comment.timestamp|@formatTime:$CONST.DATE_FORMAT_SHORT}</span>
{if $entry.is_entry_owner}
(<a class="comment_source_ownerlink" href="{$comment.link_delete}" onclick="return confirm('{$CONST.COMMENT_DELETE_CONFIRM|@sprintf:$comment.id:$comment.author}');">{$CONST.DELETE}</a>)
{/if}
{if $entry.allow_comments AND $comment.body != 'COMMENT_DELETED'}
(<a class="comment_reply" href="#serendipity_CommentForm" id="serendipity_reply_{$comment.id}" onclick="document.getElementById('serendipity_replyTo').value='{$comment.id}'; {$comment_onchange}">{$CONST.REPLY}</a>)
<div id="serendipity_replyform_{$comment.id}"></div>
{/if}
</div>
</div>
{if $comment.is_featured == "0" and $hiddenOn == "true"}{assign var="hiddenOn" value="false"}</div>{/if}
{foreachelse}
<div class="serendipity_center nocomments">{$CONST.NO_COMMENTS}</div>
{/foreach}
<!-- blog/include/functions_comments.inc.php -->
<!-- replace the function serendipity_fetchComments with: -->
<?php
function serendipity_fetchComments($id, $limit = null, $order = '', $showAll = false, $type = 'NORMAL', $where = '') {
global $serendipity;
$and = '';
if (!empty($limit)) {
$limit = serendipity_db_limit_sql($limit);
} else {
$limit = '';
}
if ($type == 'comments' || empty($type)) {
$type = 'NORMAL';
} elseif ($type == 'trackbacks') {
$type = 'TRACKBACK';
} elseif ($type == 'comments_and_trackbacks') {
$type = '%';
}
if (!empty($id)) {
$and .= " AND co.entry_id = '" . (int)$id ."'";
}
if (!$showAll) {
$and .= ' AND co.status = \'approved\'';
}
$and .= $where;
if ($serendipity['dbType'] == 'postgres') {
$group = '';
$distinct = 'DISTINCT';
} else {
$group = 'GROUP BY co.is_featured,co.id';
$distinct = '';
}
// changed this line below:
// co.entry_id, co.timestamp, co.title, co.email, co.url, co.ip, co.body, co.type, co.subscribed,
// removed co.email for privacy reasons
// changed ORDER BY
$query = "SELECT $distinct
co.id,
co.entry_id, co.timestamp, co.title AS ctitle, co.url, co.ip, co.body, co.type, co.subscribed, co.is_featured
co.author,
e.title,
e.timestamp AS entrytimestamp,
e.id AS entryid,
e.authorid,
co.id AS commentid,
co.parent_id AS parent_id
FROM
{$serendipity['dbPrefix']}comments co
LEFT JOIN {$serendipity['dbPrefix']}entries e ON (co.entry_id = e.id)
WHERE co.type LIKE '" . $type . "' AND co.entry_id > 0 $and
$group
ORDER BY co.is_featured DESC, co.timestamp DESC,
" . ($where != '' ? '' : 'co.id') . " " . ($order != '' ? $order : '') . "
$limit";
$comments = serendipity_db_query($query, false, 'assoc');
if (!is_array($comments)) {
return array();
}
serendipity_plugin_api::hook_event('fetchcomments', $comments);
return $comments;
}
?>
<!-- Add to [blog root]/include/admin/comments.inc.php -->
<!-- Add after /* We are asked to delete a comment */ -->
<?php
/* Toggle the feature of a comment */
if ( isset($serendipity['GET']['adminAction']) && $serendipity['GET']['adminAction'] == 'feature' ) {
/* Flip the toggle status of the is_featured field */
if($serendipity['GET']['featureNow']=="0") {
$isfeat = "1";
define("COMMENT_FEATURED","The comment has been featured.");
} else {
$isfeat = "0";
define("COMMENT_FEATURED","The comment is no longer featured.");
}
$sql = "UPDATE `{$serendipity['dbPrefix']}comments` SET `is_featured` = '".$isfeat."' WHERE `id` = '". (int)$serendipity['GET']['id']."' LIMIT 1;";
serendipity_db_query($sql);
echo sprintf(COMMENT_FEATURED, $serendipity['GET']['id']);
}
?>
<!-- Around line 376, replacing this: -->
$comment = array(
'fullBody' => $rs['body'],
'summary' => serendipity_mb('substr', $rs['body'], 0, $summaryLength),
'status' => $rs['status'],
'type' => $rs['type'],
'id' => $rs['id'],
'title' => $rs['title'],
'timestamp' => $rs['timestamp'],
'referer' => $rs['referer'],
'url' => $rs['url'],
'ip' => $rs['ip'],
'entry_url' => serendipity_archiveURL($rs['entry_id'], $rs['title']),
'email' => $rs['email'],
'author' => (empty($rs['author']) ? ANONYMOUS : $rs['author']),
'entry_id' => $rs['entry_id']
);
<!-- With this: -->
$comment = array(
'fullBody' => $rs['body'],
'summary' => serendipity_mb('substr', $rs['body'], 0, $summaryLength),
'status' => $rs['status'],
'type' => $rs['type'],
'id' => $rs['id'],
'title' => $rs['title'],
'timestamp' => $rs['timestamp'],
'referer' => $rs['referer'],
'url' => $rs['url'],
'ip' => $rs['ip'],
'entry_url' => serendipity_archiveURL($rs['entry_id'], $rs['title']),
'email' => $rs['email'],
'author' => (empty($rs['author']) ? ANONYMOUS : $rs['author']),
'entry_id' => $rs['entry_id'],
'is_featured'=> $rs['is_featured']
);
<!-- Immediately BEFORE REFERER (Around Line 456) -->
<!-- Replace the empty <td> cell: -->
<!-- <td width="40%"> </td> -->
<!-- With: -->
<td width="40%"><strong>Featured</strong>:
<?php
if ( empty($comment['is_featured'])||$comment['is_featured']=='0' ) {
echo 'No';
} else {
echo 'Yes';
}
?></td>
<!-- Immediately After <?php echo DELETE ?></a> around line 491 -->
<a href="?serendipity[action]=admin&serendipity[adminModule]=comments&serendipity[adminAction]=feature&serendipity[id]=<?php echo $rs['id'] ?>&serendipity[featureNow]=<?php echo $rs['is_featured'] ?>" class="serendipityIconLink" title="<?php echo FEATURE; ?>"><img src="<?php echo serendipity_getTemplateFile('admin/img/star.png'); ?>" alt="<?php echo FEATURE ?>" /><?php echo Feature ?></a>
<!-- In blog/plugins/serendipity_plugin_comments/serendipity_plugin_comments.php:
Replace the $q = query around line 130 with:
-->
$q = 'SELECT c.body AS comment,
c.timestamp AS stamp,
c.author AS user,
e.title AS subject,
e.id AS entry_id,
c.id AS comment_id,
c.type AS comment_type,
c.url AS comment_url,
c.title AS comment_title,
c.is_featured AS is_featured
FROM '.$serendipity['dbPrefix'].'comments AS c,
'.$serendipity['dbPrefix'].'entries AS e
WHERE e.id = c.entry_id
AND NOT (c.type = \'TRACKBACK\' AND c.author = \'' . serendipity_db_escape_string($serendipity['blogTitle']) . '\' AND c.title != \'\')
AND c.status = \'approved\'
ORDER BY is_featured,c.timestamp DESC
LIMIT ' . $max_entries;
<!-- Add this to the main template -->
<script language="javascript" type="text/javascript" src="toggleComments.js"></script>
<!-- And create the filetoggleComments.js and save it in the path above -->
function toggleComments(divid) {
if(document.getElementById) {
obj = document.getElementById(divid);
if(obj.style.display=='none') {
obj.style.display = '';
} else {
obj.style.display = 'none';
}
}
}
<!-- Add to [templates]/[template|default]/entries.tpl around line 156: -->
<div class="serendipity_comments"><a href="javascript:toggleComments('hiddenComments');" onMouseOver(window.status='Show/Hide Comments'); onMouseOut(window.status=''); title="Show/Hide All Comments">Show/Hide All Comments</a><br /><br /></div>
<!-- Replace your entire "entries.tpl" (default or your template) with this: -->
<!-- ENTRIES START -->
{serendipity_hookPlugin hook="entries_header" addData="$entry_id"}
{foreach from=$entries item="dategroup"}
<div class="serendipity_Entry_Date">
{if $dategroup.is_sticky}
<h3 class="serendipity_date">{$CONST.STICKY_POSTINGS}</h3>
{else}
<h3 class="serendipity_date">{$dategroup.date|@formatTime:DATE_FORMAT_ENTRY}</h3>
{/if}
{foreach from=$dategroup.entries item="entry"}
<h4 class="serendipity_title"><a href="{$entry.link}">{$entry.title}</a></h4>
<div class="serendipity_entry serendipity_entry_author_{$entry.author|@makeFilename} {if $entry.is_entry_owner}serendipity_entry_author_self{/if}">
{if $entry.categories}
<span class="serendipity_entryIcon">
{foreach from=$entry.categories item="entry_category"}
{if $entry_category.category_icon}
<a href="{$entry_category.category_link}"><img class="serendipity_entryIcon" title="{$entry_category.category_name|@escape}{$entry_category.category_description|@emptyPrefix}" alt="{$entry_category.category_name|@escape}" src="{$entry_category.category_icon}" /></a>
{/if}
{/foreach}
</span>
{/if}
<div class="serendipity_entry_body">
{$entry.body}
</div>
{if $entry.is_extended}
<div class="serendipity_entry_extended"><a id="extended"></a>{$entry.extended}</div>
{/if}
{if $entry.has_extended and not $is_single_entry and not $entry.is_extended}
<br /><a href="{$entry.link}#extended">{$CONST.VIEW_EXTENDED_ENTRY|@sprintf:$entry.title}</a><br /><br />
{/if}
<div class='serendipity_entryFooter'>
{$CONST.POSTED_BY} <a href="{$entry.link_author}">{$entry.author}</a>
{if $entry.categories}
{$CONST.IN} {foreach from=$entry.categories item="entry_category" name="categories"}<a href="{$entry_category.category_link}">{$entry_category.category_name|@escape}</a>{if not $smarty.foreach.categories.last}, {/if}{/foreach}
{/if}
{if $dategroup.is_sticky}
{$CONST.ON}
{else}
{$CONST.AT}
{/if} <a href="{$entry.link}">{if $dategroup.is_sticky}{$entry.timestamp|@formatTime:DATE_FORMAT_ENTRY} {/if}{$entry.timestamp|@formatTime:'%H:%M'}</a>
{if $entry.has_comments}
{if $use_popups}
| <a href="{$entry.link_popup_comments}" onclick="window.open(this.href, 'comments', 'width=480,height=480,scrollbars=yes'); return false;">{$entry.label_comments} ({$entry.comments})</a>
{else}
| <a href="{$entry.link}#comments">{$entry.label_comments} ({$entry.comments})</a>
{/if}
{/if}
{if $entry.has_trackbacks}
{if $use_popups}
| <a href="{$entry.link_popup_trackbacks}" onclick="window.open(this.href, 'comments', 'width=480,height=480,scrollbars=yes'); return false;">{$entry.label_trackbacks} ({$entry.trackbacks})</a>
{else}
| <a href="{$entry.link}#trackbacks">{$entry.label_trackbacks} ({$entry.trackbacks})</a>
{/if}
{/if}
{if $entry.is_entry_owner and not $is_preview}
| <a href="{$entry.link_edit}">{$CONST.EDIT_ENTRY}</a>
{/if}
{$entry.add_footer}
</div>
</div>
<!--
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<rdf:Description
rdf:about="{$entry.link_rdf}"
trackback:ping="{$entry.link_trackback}"
dc:title="{$entry.title_rdf|@default:$entry.title}"
dc:identifier="{$entry.rdf_ident}" />
</rdf:RDF>
-->
{$entry.plugin_display_dat}
{if $is_single_entry and not $use_popups and not $is_preview}
{if $CONST.DATA_UNSUBSCRIBED}
<br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_UNSUBSCRIBED|@sprintf:$CONST.UNSUBSCRIBE_OK}</div><br />
{/if}
{if $CONST.DATA_TRACKBACK_DELETED}
<br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_TRACKBACK_DELETED|@sprintf:$CONST.TRACKBACK_DELETED}</div><br />
{/if}
{if $CONST.DATA_TRACKBACK_APPROVED}
<br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_TRACKBACK_APPROVED|@sprintf:$CONST.TRACKBACK_APPROVED}</div><br />
{/if}
{if $CONST.DATA_COMMENT_DELETED}
<br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_COMMENT_DELETED|@sprintf:$CONST.COMMENT_DELETED}</div><br />
{/if}
{if $CONST.DATA_COMMENT_APPROVED}
<br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_COMMENT_APPROVED|@sprintf:$CONST.COMMENT_APPROVED}</div><br />
{/if}
<div class="serendipity_comments serendipity_section_trackbacks">
<br />
<a id="trackbacks"></a>
<div class="serendipity_commentsTitle">{$CONST.TRACKBACKS}</div>
<div class="serendipity_center">
<a rel="nofollow" style="font-weight: normal" href="{$entry.link_trackback}" onclick="alert('{$CONST.TRACKBACK_SPECIFIC_ON_CLICK|@escape:html}'); return false;" title="{$CONST.TRACKBACK_SPECIFIC_ON_CLICK|@escape}">{$CONST.TRACKBACK_SPECIFIC}</a>
</div>
<br />
{serendipity_printTrackbacks entry=$entry.id}
</div>
{/if}
{if $is_single_entry and not $is_preview}
<div class="serendipity_comments serendipity_section_comments">
<br />
<a id="comments"></a>
<div class="serendipity_commentsTitle">{$CONST.COMMENTS}</div>
<div class="serendipity_center">{$CONST.DISPLAY_COMMENTS_AS}
{if $entry.viewmode eq $CONST.VIEWMODE_LINEAR}
({$CONST.COMMENTS_VIEWMODE_LINEAR} | <a href="{$entry.link_viewmode_threaded}#comments" rel="nofollow">{$CONST.COMMENTS_VIEWMODE_THREADED}</a>)
{else}
(<a rel="nofollow" href="{$entry.link_viewmode_linear}#comments">{$CONST.COMMENTS_VIEWMODE_LINEAR}</a> | {$CONST.COMMENTS_VIEWMODE_THREADED})
{/if}
</div>
<br />
{serendipity_printComments entry=$entry.id mode=$entry.viewmode}
{if $entry.is_entry_owner}
{if $entry.allow_comments}
<div class="serendipity_center">(<a href="{$entry.link_deny_comments}">{$CONST.COMMENTS_DISABLE}</a>)</div>
{else}
<div class="serendipity_center">(<a href="{$entry.link_allow_comments}">{$CONST.COMMENTS_ENABLE}</a>)</div>
{/if}
{/if}
<a id="feedback"></a>
{foreach from=$comments_messagestack item="message"}
<div class="serendipity_center serendipity_msg_important">{$message}</div>
{/foreach}
{if $is_comment_added}
<br />
<div class="serendipity_center serendipity_msg_notice">{$CONST.COMMENT_ADDED}</div>
{elseif $is_comment_moderate}
<br />
<div class="serendipity_center serendipity_msg_notice">{$CONST.COMMENT_ADDED}<br />{$CONST.THIS_COMMENT_NEEDS_REVIEW}</div>
{elseif not $entry.allow_comments}
<br />
<div class="serendipity_center serendipity_msg_important">{$CONST.COMMENTS_CLOSED}</div>
{else}
<br />
<div class="serendipity_comments"><a href="javascript:toggleComments('hiddenComments');" onMouseOver(window.status='Show/Hide Comments'); onMouseOut(window.status=''); title="Show/Hide All Comments">Show/Hide All Comments</a><br /><br /></div>
<div class="serendipity_section_commentform">
<div class="serendipity_commentsTitle">{$CONST.ADD_COMMENT}</div>
{$COMMENTFORM}
</div>
{/if}
</div>
{/if}
{$entry.backend_preview}
{/foreach}
</div>
{foreachelse}
{if not $plugin_clean_page}
{$CONST.NO_ENTRIES_TO_PRINT}
{/if}
{/foreach}
<div class='serendipity_entryFooter' style="text-align: center">
{if $footer_prev_page}
<a href="{$footer_prev_page}">« {$CONST.PREVIOUS_PAGE}</a>
{/if}
{if $footer_info}
({$footer_info})
{/if}
{if $footer_next_page}
<a href="{$footer_next_page}">» {$CONST.NEXT_PAGE}</a>
{/if}
{serendipity_hookPlugin hook="entries_footer"}
</div>