PHP class for threaded comments

Filed under: PHP | 11 Comments »

I had to set up a simple threaded comments system in a PHP project yesterday and didn’t find any standout options. The presentation requirements were pretty simple and my only real code requirement was to use a single SQL query (using a self-referencing parent_id foreign key field) to fetch the comments. I didn’t want to mess with a full-on tree either (that would be overkill as I’d never need to walk up the tree, just needed to show all the comments for a single object).

What I found was either laughably pathetic or various Wordpress plug-ins that were even more hard to parse than the main Wordpress codebase.

I ended up writing a simple class that accomplishes it without getting too fancy. The main meat of the class is a recursively called method (Threaded_comment::print_parent()) that prints a comment and then its children. The class as I have shared below will need modification depending on how you use it, for my use I modified it to be a CodeIgniter library and output comments using a View file. Simple enough. It’s set-up as an example, not a full-on third party library. I am sure I’ll have to hack on it more, but hopefully it helps someone.

Update: Note that this code is not running the comments you see below–that’s powered by WordPress’ native comment feature (which also does threading). The code below is if you want to setup a threaded comment system in your own PHP application. You could certainly attempt to run it on a WordPress install, but there would be no point because the feature is already seamlessly built-in.

class Threaded_comments
{

    public $parents  = array();
    public $children = array();

    /**
     * @param array $comments
     */
    function __construct($comments)
    {
        foreach ($comments as $comment)
        {
            if ($comment['parent_id'] === NULL)
            {
                $this->parents[$comment['id']][] = $comment;
            }
            else
            {
                $this->children[$comment['parent_id']][] = $comment;
            }
        }
    }

    /**
     * @param array $comment
     * @param int $depth
     */
    private function format_comment($comment, $depth)
    {
        for ($depth; $depth > 0; $depth--)
        {
            echo "\t";
        }

        echo $comment['text'];
        echo "\n";
    }

    /**
     * @param array $comment
     * @param int $depth
     */
    private function print_parent($comment, $depth = 0)
    {
        foreach ($comment as $c)
        {
            $this->format_comment($c, $depth);

            if (isset($this->children[$c['id']]))
            {
                $this->print_parent($this->children[$c['id']], $depth + 1);
            }
        }
    }

    public function print_comments()
    {
        foreach ($this->parents as $c)
        {
            $this->print_parent($c);
        }
    }

}

Here’s the example usage with the data provided as an array. Remember that if your data is in another format you’ll have to modify the class.


$comments = array(  array('id'=>1, 'parent_id'=>NULL,   'text'=>'Parent'),
                    array('id'=>2, 'parent_id'=>1,      'text'=>'Child'),
                    array('id'=>3, 'parent_id'=>2,      'text'=>'Child Third level'),
                    array('id'=>4, 'parent_id'=>NULL,   'text'=>'Second Parent'),
                    array('id'=>5, 'parent_id'=>4,   'text'=>'Second Child')
                );

$threaded_comments = new Threaded_comments($comments);

$threaded_comments->print_comments();

Example Output:

Parent
	Child
		Child Third level
Second Parent
	Second Child

Latest posts

11 Responses to “PHP class for threaded comments”

  1. Kevin Day says:

    Thanks, that’s a great easy-to-follow example. I just plugged it into my application in about 10 minutes. I was considering a whole tree-based approach like you mentioned above but this is perfect.

  2. Vernon says:

    Thanks a lot. I’m actually working on a CodeIgniter project where I’m doing comments and wanted to do threaded comments. I did a quick Google for “php+threaded+comments” and came up first with the “laughable attempt” and then your great article… that just happens to be right in the CodeIgniter alley! Made my Friday a lot easier, thanks!

  3. thinsoldier says:

    Thanks, this is so much simpler than the code I started writing.

  4. Aziz Light says:

    Great Job. I was trying to figure out how to do something similar myself. Is that your CodeIgniter implementation of the class or did you do an CI emplementation of this class? Either was it would be great if you could submit the code for the CI Implementation if that’s OK with you.

    • The CodeIgniter version is slightly modified (mainly that it outputs using a View file), but the logic is identical. I switched it around so that the constructer loaded the CI instance ($this->CI =& get_instance()) as you can’t have arguments on CI library constructers. The constructer in the given class was changed into a method called load(). And then format_comment() was modified to output to the View file: echo $this->CI->load->view(‘comment/comment’, $data, TRUE);

      Feel free to mash it up however you’d like–it’s simple enough that I figured I would just show the recipe.

  5. Danny says:

    BTW how many lvls are there?
    mean like

    parent
    child lvl 1
    child lvl 2
    child lvl 3
    child lvl X

    • JG says:

      There is no set cap, that’s something you need to decide on your own (only allow replies to comments below whatever depth you want). For example when I used it, I only showed the reply button for comments three or fewer levels deep.

Leave a Reply