Blog 4 umbraco 2.0.5 – Comments

Monday, December 07, 2009 by Administrator

Today we'll make an improvement to blog 4 umbraco that shouldn't have any impact on the frontend of the blog but will make it much easier to handle comment spam and moderate comments. We'll move away from storing the comments as documents and store them in a database table instead. We'll fetch them with some xslt extensions (haven't heard of xslt extensions, be sure to check out the umbraco.tv chapter /documentation/videos/for-developers/xslt-extensions/introduction-to-xslt-extensions)

First

The first step is to create this new table, we'll need to store the post id, the actual comment (name, email, website, comment), the timestamp and we'll also add a spam field.

CREATE TABLE [Comment](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [blogid] [int] NOT NULL,
    [postid] [int] NOT NULL,
    [name] [nvarchar](250) NULL,
    [email] [nvarchar](250) NULL,
    [website] [nvarchar](250) NULL,
    [comment] [text] NULL,
    [spam] [bit] NULL,
    [created] [datetime] NULL,
CONSTRAINT [PK_Comment] PRIMARY KEY CLUSTERED
(
    [id] ASC
)

(this is the sql server create script, we'll also include a vistadb and mysql create script in the installer)

Storing comments

Instead of creating a comment document with the umbraco api we'll update the method to insert a record in the new table using the umbraco datalayer (to make sure this can be executed on sql server, vistadb and mysql)

ISqlHelper SqlHelper = DataLayerHelper.CreateSqlHelper(umbraco.GlobalSettings.DbDSN);
            SqlHelper.ExecuteNonQuery(
                @"insert into Comment(blogid,postid,name,email,website,comment,spam,created)
                    values(@blogid,@postid,@name,@email,@website,@comment,@spam,@created)",
                 SqlHelper.CreateParameter("@blogid", blogid),
                SqlHelper.CreateParameter("@postid", blogpost.Id),
                SqlHelper.CreateParameter("@name", name),
                SqlHelper.CreateParameter("@email", email),
                SqlHelper.CreateParameter("@website", website),
                SqlHelper.CreateParameter("@comment", comment),
                SqlHelper.CreateParameter("@spam", false),
                SqlHelper.CreateParameter("@created", DateTime.Now));

Showing comments

For showing the comments we'll add some new methods to our blog xslt extensions. Basicly I want to select all comments or select the comment for a specific post. So I'll need a GetComments() method and a GetCommentsForBlog(int id) method. Both will return some xml (XPathNodeIterator) that will look like this:

<comments>

<comment id="2" postid="1206" created="7/12/2009 16:22:28">

<name>Tim Geyssens</name>

<email>myemail@domain.com</email>

<website>http://www.umbraco.org</website>

<message>This should be stored in the database</message>

</comment>

</comments>

We'll also use the umbraco datalayer to execute these queries and we'll add a method that creates the comment xml from a RecordsReader.

public static XPathNodeIterator GetCommentsForPost(int id)
      {

          ISqlHelper SqlHelper = DataLayerHelper.CreateSqlHelper(umbraco.GlobalSettings.DbDSN);
          IRecordsReader rr = SqlHelper.ExecuteReader(
              "select * from comment where postid = @postid and spam != 1",
               SqlHelper.CreateParameter("@postid", id));

          return CommentsToXml(rr);
      }

 

private static XPathNodeIterator CommentsToXml(IRecordsReader rr)
        {
            XmlDocument xd = new XmlDocument();

            XmlNode x = umbraco.xmlHelper.addTextNode(xd, "comments", "");

            while (rr.Read())
            {
                XmlNode c = xd.CreateElement("comment");

                c.Attributes.Append(umbraco.xmlHelper.addAttribute(xd, "id", rr.GetInt("id").ToString()));
                c.Attributes.Append(umbraco.xmlHelper.addAttribute(xd, "postid", rr.GetInt("postid").ToString()));
                c.Attributes.Append(umbraco.xmlHelper.addAttribute(xd, "created", rr.GetDateTime("created").ToString()));

                c.AppendChild(umbraco.xmlHelper.addCDataNode(xd, "name", rr.GetString("name")));
                c.AppendChild(umbraco.xmlHelper.addCDataNode(xd, "email", rr.GetString("email")));
                c.AppendChild(umbraco.xmlHelper.addCDataNode(xd, "website", rr.GetString("website")));
                c.AppendChild(umbraco.xmlHelper.addCDataNode(xd, "message", rr.GetString("comment")));

                x.AppendChild(c);
            }

            xd.AppendChild(x);

            return xd.CreateNavigator().Select(".");
        }

 

With the new xslt extensions in place we'll just need to update our xslt to fetch the comments from these.

So this is how the list comments xslt will look after the update:

<h3 id="comments">
<xsl:value-of select="count(BlogLibrary:GetCommentsForPost($currentPage/@id)//comment)"/> comment(s)  for  &#8220;<xsl:value-of select="$currentPage/@nodeName"/>&#8221;</h3>

<ol class="commentlist">
<xsl:for-each select="BlogLibrary:GetCommentsForPost($currentPage/@id)//comment">

<li class="alt" id="comment-{@id}">
<div class="commentcontent">
    <div class="commentgravatar" style="float:right;margin-right: 5px;">
        <img width="40px" height="40px" src="{BlogLibrary:getGravatar(./email, 40, '')}" alt="Gravatar of {./name}"/>
    </div>
    <cite>  <xsl:value-of select="./name"/> </cite> Says: <br />
    <small class="commentmetadata"><xsl:value-of select="umbraco.library:LongDate(@created)"/> </small>
    <xsl:value-of select="umbraco.library:ReplaceLineBreaks(./message)" disable-output-escaping="yes"/>
</div>

</li>
</xsl:for-each>
</ol>

That's it, the blog comments are now stored/fetched from a table instead of using documents.

21 comment(s) for “Blog 4 umbraco 2.0.5 – Comments”

  1. Gravatar ImageLee Says:

    These posts are excellent chaps - Really good stuff for people like me :)

    I do have a question for this one though Tim, how are you going to enable administration of the comments? Custom usercontrol in the dashboard? Or is this going to be the next blog?

  2. Gravatar ImageJesper Ordrup Says:

    Great example of how to use extensions to use db.

    Usually I think it's easier to have the comments in Umbraco with out of the box caching, ui for administration, no need to dev xtensions .. but of cause if you have sh*loads of comments then it might be a good thing.

    I guess that a later post will show why :-)

  3. Gravatar ImageTim Geyssens Says:

    @Lee @Jesper, yup we'll look at that in a future chapter

  4. Gravatar ImageChris Houston Says:

    Hi Tim,

    Nice post, one thought on this is what about sites that are on multiple load balanced servers?

    I thought the idea of storing all the content in the Umbraco XML file meant that it made sites easily scalable by adding new servers that just required the Umbraco.config XML file updated on each server, but by using XSLT extensions that access the DB directly you are then reliant on the DB for serving content?

    Just a thought and for most I am sure it won't be a consideration.

    Chris

  5. Gravatar ImageJonas M Says:

    Hi Tim,

    Like the others said: Thanks for an interesting post.

    One question popped up though: Did you consider storing the IP address of the poster along with the comment?

    Cheers,
    Jonas

  6. Gravatar ImageNico Lubbers Says:

    Very good series of posts!!

    One minor thing: Shouldn't you use **ntext** instead of text for the comments fields to support unicode?

    Nico

  7. Gravatar ImageDouglas Robar Says:

    I love these posts!!


    One minor optimization...

    Save the result of BlogLibrary:GetCommentsForPost($currentPage/@id)//comment) to a variable. That way you only hit the database once rather than twice.

    cheers,
    doug.

  8. Gravatar ImageTim Geyssens Says:

    @Nico, @Douglas both true, will be like that in the final package.

  9. Gravatar ImageBarney Says:

    I've often wondered what would be the right approach to managing such content. Sometimes creating documents when you just want to manage records just feels wrong to me.

    I'm hoping that reading such practical and intelligent posts will soak through into my own practical know-how, eventually :)

    Thanks chaps - keep it up!
    Barney

  10. Gravatar ImageSebastiaan Janssen Says:

    Maybe I'm missing something, but by storing the comments in a seperate table, how would you delete unwanted comments or mark them as spam manually?
    There's no umbraco interface to deal with these comments any more, so you'd need to reach into your database?

  11. Gravatar ImageTim Geyssens Says:

    @Sebastiaan no worries, we'll add comment moderation in a future chapter

  12. Gravatar Imageandrew smith Says:

    so about comment moderation. how can i set this up?

  13. Gravatar Imagejh Says:

    RE: andrew smith

    http://our.umbraco.org/projects/blog-4-umbraco/using-blog-4-umbraco/7079-Comment-Moderation,-How

  14. Gravatar Imagew Says:

    sfdfsd

  15. Gravatar Imagemartha Says:

    Could someone please explain how I am able to setup the comment moderation with the script? Thanks!

  16. Gravatar Imageuros Says:

    Hi, could somebody be so nice and explain,where to save those scripts? THX

  17. Gravatar ImageMedvision Medline Says:

    Wow, its very nice script and also useful, and please let me know where to save the scripts? if so it will be very nice

  18. Gravatar ImageDominican Republic villas Says:

    One minor thing: Shouldn't you use **ntext** instead of text for the comments fields to support unicode?

  19. Gravatar Imagesanthosh Says:

    Nice post, one thought on this is what about sites that are on multiple load balanced servers?

    I thought the idea of storing all the content in the Umbraco XML file meant that it made sites easily scalable by adding new servers that just required the Umbraco.config XML file updated on each server, but by using XSLT extensions that access the DB directly you are then reliant on the DB for serving content?

    Just a thought and for most I am sure it won't be a consideration

  20. Gravatar ImageMLM Says:

    Great post! Thanks for this!

  21. Gravatar ImageAll Blond Says:

    Hello,
    Ok can you tel if 4.7.1 already have all this or we should do it? Because as far as I can see database already have table. Need to know about rest of the staff. So far comment does not get stored or appear on the blog at all...
    Thanks

Leave a comment