EasyPageComments
By Mike "Pomax" Kamermans
I needed some simple but full-featured, login-less comments for several pages I'm running for presenting loose technology snippets to the world that I don't want to present through some CMS because the styling's going to be completely different, or the subject is just not related to my specifically-purposed websites. As such, I needed it to be modular, and require almost no work to drop into newly written pages. Looking at what I already had written for my Primer on Bezier curves I figured I already had something close to what I needed, just a bit too part-of-the-page, so I lifted it out, cleaned the code up, and added some of the features that were still missing, ending up with exactly what I need: A simple but full featured "drop it in, and glue it on with less than 10 lines of code" commenting system.
The styling's all CSS, so style it to look like whatever you think looks best, and get some comments going on for pages that are just random pages, rather than CMS-ed pages.
Features:
- Drop-in install
- Separate comments listing and comment form injection
- All elements can be individually styled using CSS
- Threaded commenting with nested replies
- Allows more than one comment section on a single page
- Email post and reply notification
- Posting as owner is password protected
- RSS feed link per comment section
- Simplified posting for users you say are logged in (no need for them to fill in their name and email address or security questions)
- Works in either simple or rich mode, depending on whether you need to support browsers that don't support JavaScript.
- Backed by SQLite (file based) databases, which makes it really easy to migrate and/or administrate
- Hash aware. Regardless of how late you generate comments, jumping to hash still works.
- Error highlighting when trying to post with missing or illegal form fields.
"Installing" EasyPageComments
There's no real installation to speak of - just grab EasyPageComments from github, or just download a zip file with the code:
After obtaining all the files, drop the EasyPageComments.php file (and optionally the EasyPageComments.js file) in the same dir as your page. Then depending on your preferred method of use, either:
a) add
require_once("EasyPageComments.php");
at the top of your page, in a php block, or
b) add
<script type="text/javascript" src="EasyPageComments.js"></script>
to your page's <head> block.
Generating the comments
The PHP way
Generating the comment list could not be easier. Okay, no, that's a lie, I guess it could be. But it's pretty damn easy. Just find the place where you want the comments to show up, and insert:
<?php $EasyPageComments->createCommentsList(); ?>
<?php $EasyPageComments->createCommentForm(); ?>
This will, in fact, store and list messages for "the current page", which is whatever your URL bar shows, minus the domain name. This is super convenient, but it also makes moving the page a little bit of work. Which is inconvenient. To make life easier again, the function can also take a pagename argument:
<?php $EasyPageComments->createCommentsList("My Page Name"); ?>
<?php $EasyPageComments->createCommentForm("My Page Name"); ?>
And now messages are stored and retrieved using that page name, rather than getting the page name from the URL. Handy-dandy.
The upside
Super-no-work-at-all solution, requiring one line to include the EasyPageComments.php package, one line to inject the comment list, and one line to inject the comment posting form.
Does not rely in JavaScript in any way, so it even works when people have NoScript and the like turned on.
The downside
Does not rely on JavaScript in any way, so posting a new comment reloads the page. Your users may also not be able to reply to other user's posts at the moment, as this relies on JavaScript being available at the moment.
The JavaScript way (recommended, really)
EasyPageComments also works with plain .html pages, in case you don't want to give your pages a .php extension. Simply implement these two functions for injecting the comments list and post form into your web page:
function showEasyPageComments(data) {
document.getElementById('idForListContainer').innerHTML = data;
}
function showEasyPageCommentForm(data) {
document.getElementById('idForFormContainer').innerHTML = data;
}
And then trigger them (at page load or DOMReady or something) by calling:
EasyPageComments.createCommentsList("My Page Name");
EasyPageComments.createCommentForm("My Page Name");
This page, for instance, uses the following JavaScript:
function showEasyPageComments(data) {
document.getElementById('EasyPageComments').innerHTML = data; }
function showEasyPageCommentForm(data) {
document.getElementById('EasyPageCommentForm').innerHTML = data; }
function addEasyPageComments() {
EasyPageComments.createCommentsList('EasyPageComments');
EasyPageComments.createCommentForm('EasyPageComments'); }
document.addEventListener("DOMContentLoaded", addEasyPageComments, false)
Because the javascript call makes it impossible for PHP to check which page it was called for (since you're calling the script directly, rather than as part of a specific page-request to the server), the page name is mandatory when using JavaScript.
Note that the JavaScript approach refreshes the comments list after posting a new comment, so make sure that showEasyPageComments(data) overwrites whatever is in your list container element, or things will look wrong for someone posting a comment.
The upside
Loading and posting is dynamic. You can add the comments block to your page only when the user requests comment functionality, and posting is handled in-place, without the page needing to be reloaded just to show the new comment, or errors with a faulty post.
The downside
If people block JavaScript, they won't get comment functionality until they unblock it. It's also a tiny bit more work to make it do its thing, although given the code already provided, it's about as much of a no-brainer to get things to work =)
A demonstrator
A demonstrator comments list for this page, inserted with PHP (and styled with this stylesheet):
alert("hi")
</script>
You can also post test comments, but because the demonstrator uses straight PHP injection, rather than javascript, posting will reload the entire page. Note that any posts to the demonstrator section get deleted after a few hours. For normal comments, use the comment section at the bottom of this page =)
Details
Nesting is automatic, and you can show it (or not) by using some CSS indenting. Custom styling for your own comments is also CSSable, so if you want to visually offset your own comments from everyone else's, you can.
In fact, there is quite a bit of styling that you can apply to the various elements, since essentially everything is either classed, or classless elements inside classed elements. All classes are prefixed with "EPC-" and certain elements in the post form have "EPC-..." id attributes, so you can hook into them with JavaScript, should you want to.
Every comment has its own anchor, and you can link to specific comments using them. For the PHP-generated code, hashes in the URL are not a problem, because the generated html already contains them. For the JavaScript-generated code, hashes in the URL are actually also just fine, because EasyPageComments.js will check for a URL hash, and keep it stored until you call the createCommentsList function, after which it'll tell the browser to jump to the specific comment indicated by the hash.
Email notification
EasyPageComments can send you an email every time someone posts a comment. This is enabled by setting the $notify variable to true, and filling in your email address as $to value. Note that even if you enable email notification, you will not receive emails for comments posted as yourself.
In additional to global notifications, EasyPageComments also lets people indicate whether or not they want to be notified by email whenever someone replies to their posts. This is done via a checkbox option in the comment posting form.
Getting the email #links right
NOTE: in order for the notification emails to contain the right comment #hash link, you must make sure that the $EPC_path variable points to your page. Thus, if your page is index.html, this variable should read:
$EPC_path = "index.html";
Owner posting by password
Because you know you're a trusted user, and because you don't want other people posing as you, filling in your nickname and email address and some comment that you would never write, posts by the owner are password protected. Rather than filling in your name and email address, plus answering the security question, you simply fill in your name, and the password you've set for your name in EasyPageComments.php:
// this is used to mark your own posts differently from everyone else's var $admin_alias = "MyNickName"; // the owner nickname is password protected, which is used in place of an email address var $admin_password = "This can be as long as you like; Unicode and case is respected.";
Even if you rely on PHP for your comment listing and post form, you will probably want to add EasyPageComments.js as on-page script, as its used to change the post form when the username happens to be yours. This is only a cosmetic change, but cosmetics are important on the web!
RSS
EasyPageComments will automatically set up RSS feeds for each comment thread you use, so you don't even have to worry about that. If you don't want this, you can turn off visibility for the "EPC-RSS-link" class, so the RSS link doesn't show, or you can turn RSS link generation off entirely by changing the EasyPageComments.php setting $rss = true; to $rss = false; instead.
Getting the RSS <link> URLs right
NOTE: in order for the RSS links to point to the correct webpage and #hash link, you must make sure that the $EPC_path variable points to your regular page. Thus, if your page is index.html, this variable should read:
$EPC_path = "index.html";
SQLite
Data is stored in SQLite databases, using SQLite3 format, with the following schema:
CREATE TABLE comments(id INTEGER PRIMARY KEY AUTOINCREMENT, page TEXT, name TEXT, email TEXT,
timestamp INTEGER, body TEXT, replyto INTEGER, notify INTEGER)
Thread topology uses the relation child.replyto → parent.id and that's pretty much everything special about the layout. There is no separate users table, because that's something you would use user authentication for anyway, you don't overload a comment system with that.
If you need to manipulate the data, I recommend using SQLiteManager, which is an extension for FireFox. I know it's weird, but so far the best application for managing SQLite databases is a browser plugin. That said, it's a really good browser plugin (and ignore the nonsense comment about it crashing Thunderbird. Why you would try to install it for Thunderbird when it's a FireFox plugin, I have no idea) and you can use XULRunner to make it run stand-alone too, of course.
EasyPageComments creates one database file per 'page', so if you want to use multiple comment sections on a single page, the messages will be tracked using different databases, so that messages from one comment thread can't accidentally end up in another comment thread.
Customising EasyPageComments settings
If you want to customise the settings for EasyPageComments, simply open the EasyPageComments.php file and adjust the values at the start of the script. They are fairly self-explanatory:
// this is used to mark your own posts differently from everyone else's
var $admin_alias = "YourNameHere!";
// the owner nickname is password protected, which is used in place of an email address
var $admin_password = "Entire Unicode passphrases work!";
// what should be the security question for this page?
var $security_question = "If I write a three, and then a seven, which number did I write?";
// what are valid security answers for this page?
var $security_answers = array("37", "thirty seven", "thirty-seven", "thirtyseven", "37");
// should comment threads get an auto-generated RSS feed button?
// (if true, remember to also set the $EPC_path variable, below)
var $rss = true;
// should you be notified by email when someone posts a comment?
// (if true, remember to also set the $EPC_path variable, below)
var $notify = true;
// what's the email address to send those notifications to?
var $to = "test@example.org";
// what's the subject you'd like?
var $subject = "[EasyPageComments] page comment posted";
// where can the sqlite database be found
var $db_dir = "./sqlite";
// This variable should contain the name of your page. If your
// page is "myfunkypage.php", then this variable should be set
// to that. Relative locations such as "../index.html" are
// allowed.
//
// EPC_path is used for RSS feeds elements as well as #hash
// links in email notifications, so if $rss and $notify are both
// set to "false", EPC_path will not be used, and its value is
// irrelevant.
var $EPC_path = "index.html";
Note that the $db_direntry simply says where you want your databases to reside. They don't need to exist yet, the script will make them if they don't exist yet, although the directory you want them to be in in has to exist. (The script won't make directories for you, only database files)
If you want to use the JavaScript approach, then you may want to put the .js and .php files in different directories. If this results in the JavaScript functions trying to call a .php file that isn't in the same directory as your page, you can modify the location the JavaScript should use for posting/getting the list by modifying the location in the EasyPageComments.js file:
EasyPageComments.EasyPageCommentLocation = "../moo/EasyPageComments.php";
Simply change this to the location of EasyPageComments.php relative to your page, and things should work just fine.
Using EasyPageComments with a user authentication system
If you have a user authentication system in place, you generally don't want the comment system to require your already-logged-in users to have to fill in their name and email address, and they're generally not required to fill in a security question, since they already logged in.
EasyPageComments lets you indicate that content is being generated for a trusted user by stating the user's name and email address before including EasyPageComments.php, using an associative array as follows:
// set the trusted user's name and email address
$EasyPageComments = array("name" => "UserBot5000",
"email" => "bigbot@userbot.net");
// make EasyPageComments magic happen
require_once("EasyPageComments.php");
If you're using the JavaScript approach, you will probably want to use a passthrough file. Making one is relatively easy, so let's say we make a file called "EPC-passthrough.php", it will only need to have to following content:
<?php
// session-based authentication handling code goes here
require_once("user_authentication_script.php");
$user = authenticate();
// set the trusted user's name and email address
$EasyPageComments = ($user->authenticated ? array("name"=>$user->name, "email"=>$user->email) : false);
// make EasyPageComments magic happen
require_once("EasyPageComments.php");
?>
This sets up trusted user content only if the user passed your authentication, generating the normal content otherwise. You will now also need to make the EasyPageComments.js script call this EPC-passthrough.php file instead of the normal EasyPageComments.php, so that user authentication can take place. This is almost trivially simple, only requiring you to tell JavaScript what the new file's location is:
// Set alternate EasyPageComments location
EasyPageComments.EasyPageCommentLocation = "EPC-passthrough.php";
// build comments list
EasyPageComments.createCommentsList('My Page Name');
// build comment post form
EasyPageComments.createCommentForm('My Page Name');
Comments
To show that one page can have multiple comment threads (but also because a demonstrator is not the "real" thing), there's also the actual comment thread for this page. If you have any questions or suggestions, do let me know by posting a comment!
