Universal Commenting Module (Handler)


Well-known member
Hey, developers!

Writing addons for XenForo we have to deal with comments very often. Comments for pictures, events and other entities. So I have an passion to write the separate commenting module that can be associated with any entity. It will allow to unify all the comments in many different addons.

It will look just like profile post. Comments will keep content_type and content_id of associated entity like each Handler does.

So I'm interest the developer's opinion. Are you ready to integrate such thing with your addons? Of course if it will be easy to use and well coded.


yes and no;) (depending on implemention)

As i saw this in IPB, i started making plans for a own xf version.
I agree that the current situation with implementing a comment feature for own add-ons isn't so easy & nice as it could be, because we need to implement too much stuff which should be IMO handled by XF framework....
We have the abstract discussionmessage datawriter which makes the creating/saving easier BUT there's nothing for the output process.

We still need a own model for every comment type (and in 99% you'll have the same fields in the comment tables)
Also we need search,alert,etc.. handlers for every comment type.

Why not have an "mapper" which handles all this stuff(creating,notifingn,checking permissions and output) and all we have to do is to create the comment config and send it to the helper...
If there would be a naming convention, we wouldn't need anything.. only the comment handler name and the Framework would handle everything...

comment name: link

table: link_comment

because of the standard db structure (check XenForo_DataWriter_DiscussionMessage ), the framework would also know all relevant fields everything else could be injected ...

if you use the naming convention and name all the permissions like "can_comment", can_edit, etc... and put them into the permission group link, it would also be able to handle the permission check for you.....

that's a part of my proof of concept i started some months ago:
  class TestComment extends Ragtek_FW_CommentRenderer
        protected function _getJoinFields($fetchOptions)
      // if the table have own naming convention, we can overwrite the column names here, that's probably also something for the dw and model which should be refactored once i have a stable version
      protected $_remap = array('comment_id' => 'id',
                                  'comment_author_id' => 'user_id',
                                  'comment_author_name' => 'username',
                                  'comment_text' => 'message',
                                  'comment_ip_address' => 'ip',
                                  'comment_date' => 'message_date',
                                  'comment_approved' => 'approved',
                                  'comment_parent_id' => 'node_id');
        * liefert die haupttabelle für die kommentare zurück
        function getTable()
            return 'xf_ragtek_commenttest';
      // if we use the name conventions, we don't need this. this will be build by the abstract class...
      function  init()
            $this->_tableName = 'xf_ragtek_commenttest';
            $this->_contentType = 'test';
            $this->_searchhandler = 'ragtek_commenttest_sh';
            $this->_alerhandler = 'ragtek_commemttest_ah';
            $this->_perPage = '100';
            $this->_permissionGroup = 'ragtek_commenttest';
For output:
$commentHandler = Ragtek_FW_Commenthandler::create('TestComment');
$commentsHtml = $commentHandler->fetchCommentsFormatted($this->_input);
Inserting comment:
$commentHandler = Ragtek_FW_Commenthandler::create('TestComment');
$data = array(
                                                              'user_id' => $userId,
                                                              'message' => $message,
                                                              'node_id' => $page['node_id']
$lastDate = $this->_input->filterSingle('last_date', XenForo_Input::UINT);
$commentsHtml = $commentHandler->fetchLatestCommentsByDate($page['node_id'], $lastDate);
That's just a proof of concept, too many things aren't implemented as they should to follow the MVC rules.


Well-known member
So you want keep comments to different content types in different tables and use different Handlers for Alert, Report etc?
It is a variant. And the problem of different Models you pointed can be solved by using DiscussionMessageDefinition which keeps table structure info.
It can be used in model as well as in Post and ProfilePost DataWriters.
And developer will just need to extend DiscussionMessageDefinition class to create commenting for his content type.


So you want keep comments to different content types in different tables and use different Handlers for Alert, Report etc?
Yes, personally i would prefer separating this stuff because you wouldn't need additional tables for extra data and the table wouldn't be blown up unnecessary.....
Just think of the table size in 1-2 years if you have comments for the gallery, articles, links, shopitems, etc...

Seperate Alert,report,search handler "wouldn't" be necessary if you use the naming convention, because the framework could/would handle all this stuff.. This would be IMO unnecessary c&p code..

But that's only my opinion;)


Well-known member
any news about this?:)
Finally decided to make it based on threads and posts.
We add 2 field to xf_post: target_id and target_type and they become completely universal.
And there will be one big advantage of such approach: import from vBulletin or other forum will be straightforward.
Don't need to convert albums, cms articles and blogs. It will be keeped in database the same it was imported.

Threaded comments (already done http://do4a.com/threads/1570/):
---Article (post: target_id=0, target_type=post, post_id=100 )
------Comment (post: target_id=101, target_type=post, post_id=102 )
---------Comment (post: target_id=102, target_type=post, post_id=103 )
---Comment (post: target_id=0, target_type=post, post_id=104 )
------Comment (post: target_id=114, target_type=post, post_id=105 )

User's albums ( in TODO list ):
Thread (specified for all ragtek's albums):
---Album (post: target_id=0, target_type=post, post_id=200 )
------Photo (attachment: content_id=200, content_type=post, attachment_id = 1000)
---------Comment (post: target_id=1000, target_type=attachment, post_id=201 )
---------Comment (post: target_id=1000, target_type=attachment, post_id=202 )
---------Comment (post: target_id=1000, target_type=attachment, post_id=203 )
------Photo (attachment: content_id=200, content_type=post, attachment_id = 1001)
---------Comment (post: target_id=1001, target_type=attachment, post_id=204 )
---------Comment (post: target_id=1001, target_type=attachment, post_id=205 )
---------Comment (post: target_id=1001, target_type=attachment, post_id=206 )
---Album (post: target_id=0, target_type=post, post_id=201 )
------Photo (attachment: content_id=201, content_type=post, attachment_id = 1002)
---------Comment (post: target_id=1002, target_type=attachment, post_id=207 )
---------Comment (post: target_id=1002, target_type=attachment, post_id=208 )
---------Comment (post: target_id=1002, target_type=attachment, post_id=209 )
------Photo (attachment: content_id=201, content_type=post, attachment_id = 1003)
---------Comment (post: target_id=1003, target_type=attachment, post_id=210 )
---------Comment (post: target_id=1003, target_type=attachment, post_id=211 )
---------Comment (post: target_id=1003, target_type=attachment, post_id=212 )

Diary ( in TODO list ):
Thread (specified for ragtek's diary):
---Entry (post: target_id=0, target_type=post, post_id=200 )
------Comment (post: target_id=200, target_type=post, post_id=201 )
------Comment (post: target_id=200, target_type=post, post_id=202 )
------Comment (post: target_id=200, target_type=post, post_id=203 )
---Entry (post: target_id=0, target_type=post, post_id=201 )
------Comment (post: target_id=201, target_type=post, post_id=204 )
------Comment (post: target_id=201, target_type=post, post_id=205 )
------Comment (post: target_id=201, target_type=post, post_id=206 )


Well-known member
This would be a very useful add on as implementing this has been a pain, and it would be nice to have a group of dev maintain a healthy commenting module. Side note, if you need help or code review, message me I'm happy to help. github user andrewe.