Chapter 9. Development

This section is for developers.

Developing a ccomment plugin

In the context of CComment we will talk about 2 kinds of plugins. The standard joomla plugins (JPlugin) and CComment Plugin. You basically need the JPlugin to initialise the CComment component. The CComment plugin on the other side -> decides if the component should show the comment form, or read more buttons. It also creates a proper link to each comment, finds out who is the moderator of the item (article, photo, video etc) that the comment belongs to. Now that we know all this, let us look at some code.

The JPlugin

If you don't know what a Joomla plugin is then make sure to read the joomla wiki over here.

Basically Joomla plugins allow developers to hook into the execution of an extension and execute some code. Let us look at an example. The Content extension in joomla (Article manager or com_content) is triggering an onContentAfterDisplay event. Our plugin joscomment is hooking to this event, decides if it has to start the component or not.

	public function onContentAfterDisplay($context, &$row, &$params, $page = 0)
	{
		$input = JFactory::getApplication()->input;
		if ($input->getCmd('option') != 'com_content')
		{
			return false;
		}

//		don't display comments if we are in print mode and the user doesn't want
//		the comments there
		if ($input->getCmd('print') && !$this->params->get('printView', 0))
		{
			return false;
		}

		JLoader::discover('ccommentHelper', JPATH_SITE . '/components/com_comment/helpers');
		return ccommentHelperUtils::commentInit('com_content', $row, $params);
	}

The first lines of this code actually decide if we should initialise the CComment component or not. We don't need to show the component, if the plugin is executed in another component for example (that is why we check the option). Then we check if print option is set and if we should show the component in printview.

The most important lines are those here:

JLoader::discover('ccommentHelper', JPATH_SITE . '/components/com_comment/helpers');
return ccommentHelperUtils::commentInit('com_content', $row, $params);

The first line tells Joomla where it can find the ccommentHelper classes and the second line actually initialises our component. As you can see we pass a $row & $params object. The $row contains information about the current item (in this case an article, but depending on the component it can be a photo or video etc). The row will be passed directly to our ccomment plugin (more on ccomment plugins in the next section). The $params object contains configuration information for the current item. If the component that you are writing the plugin for doesn't have a $params object you can pass a null.

[Note]Note

Not all components support Plugin events. If you are integrating CComment with an extension that doesn't support plugin events you'll just need to echo the initialisation of CComment directly in the view file. For example like this:

<?php
JLoader::discover('ccommentHelper', JPATH_SITE . '/components/com_comment/helpers');
echo ccommentHelperUtils::commentInit('com_content', $row, $params);
?>

replace com_content with the name of the component that you are integrating.

The CComment plugin

The ccomment plugins are located in administrator/components/com_comment/plugins/ . In this folder each plugin is placed in its own folder that follows the following shema com_nameofcomponent - for example com_content, com_k2, com_docman (basically the joomla option variable). Each plugin has 2 files -> settings.php & nameofcomponent.php (for com_content -> content.php ; for com_k2 -> k2.php). The settings.php file is being executed only in the backend when the user creates a configuration. The nameofcomponent.php file is being executed both in the backend and frontend.

Settings.php

The settings.php file should contain a class with a name following the convention ccommentComponentNAMEOFCOMPONENTSettings . The class should extend ccommentComponent settings. The only function that this class should implement is the getCategories function. This function should return an array of objects with id & title. Those objects will be shown on the settings screen in the backend and the user will be able to select the categories where CComment is allowed.

Figure 9.1. Categories selection in the backend

Categories selection in the backend

Let us look at an example:

class ccommentComponentContentSettings extends ccommentComponentSettings
{
	/**
	 * categories option list used to display the include/exclude category list in setting
	 * must return an array of objects (id,title)
	 *
	 * @return array() - associative array (id, title)
	 */
	public function getCategories()
	{
		$db = JFactory::getDBO();

		$query = $db->getQuery(true);
		$query->select('id, title');
		$query->from('#__categories');
		$query->where('published = 1');
		$query->where('extension = ' . $db->quote('com_content'));
		$query->order('title ASC');

		$db->setQuery($query);
		$options = $db->loadObjectList();

		return $options;
	}

}

The above code is the content of settings.php for com_content. As you can see the ccommentComponentContentSettings extends the ccommentComponentSettings class and implements the getCategories function. If the component that you are integrating CComment with doesn't support categories, then you can just create the Class without implementing the getCategories function. In this case we will use the getCategories function from the parent class that returns an empty array.

Nameofcomponent.php (content.php, k2.php, docman.php etc)

Unfortunatly or fortunatly components are developed by different developers all with different skill sets. Some of them are following the joomla conventions, others are not. Sometimes the joomla conventions are not clear enough and it is up to the developer to create code that he likes. This leads us with a problem - how to integrate a comment system with each joomla component? It is not an easy task and it currently cannot be 100% automated. For example there are components that use the variable id to identify a resource, but there are other components that use article_id to identify a resource. Because of the we need a way to internally deal with different kinds of component. This is where the nameofcomponent.php (content.php, k2.php etc) file comes into play. The file contains a class that should be named as follows ccommentComponentNAMEOFCOMPONENTPlugin. This class should extend the ccommentComponentPlugin class. For example if we are creating a plugin for com_content this is how our class should look like:

class ccommentComponentContentPlugin extends ccommentComponentPlugin
{

}

The ccommentComponentPlugin is an abstract class that defines the structure for your CComment plugin. It is located in administrator/components/com_comment/library/component

abstract class ccommentComponentPlugin {

	/**
	 * @param $row
	 * @param null $params - JRegistry object with config information for the item
	 */
	public function __construct($row = null, $params = null)
	{
		if($row) {
			$this->row = $row;
		}
		if($params) {
			$this->params = $params;
		}

	}

	/**
	 * With this function we determine if the comment system should be executed for this
	 * content Item
	 * @return bool
	 */
	public abstract function isEnabled();

	/**
	 * This function decides whether to show the comments
	 * in an article/item or to show the readmore link
	 *
	 * If it returns true - the comments are shown
	 * If it returns false - the showReadon function will be called
	 * @param int - the content/item id
	 * @return boolean
	 */
	public abstract function isSingleView();

	/**
	 * This function determines whether to show the comment count or not
	 * @return bool
	 */
	public abstract function showReadOn();

	/**
	 * @param int  $contentId
	 * @param int  $commentId
	 *
	 * @param bool $xhtml
	 *
	 * @return string - the URL to the comment/item
	 */
	public abstract function getLink($contentId, $commentId = 0, $xhtml = true);

	/**
	 * @param $ids - the ids of the items that we look for title
	 *
	 * @return mixed - array with objects (id, title) sorted by id
	 */
	public abstract function getItemTitles($ids);

	/**
	 * Different component have different names for the id (id, article_id, video_id etc)
	 * That is why we need a function that can reliably return the ID of the item in question
	 *
	 * @return - id of content Item
	 */
	public function getPageId()
	{
		return $this->row->id;
	}

	/**
	 * Returns the id of the author of an item
	 *
	 * @param int $contentId
	 *
	 * @return mixed
	 */
	public abstract function getAuthorId($contentId);

}

The __construct function expects a $row and $params object. As you can see from the code however -> we cannot rely on the $row object beeing present at all times.

The isEnabled function will determine if CComment should be initialised for the current item (article, video etc) depending on the user configuration (selected category, disabled for specific item etc)

The isSingleView function will determine if we are currently in single view for the specific item. If we are, then we will show the comment form together with all comment. If we aren't the showReadOn() function will be called and it will determine if CComment needs to show a "write comment" button or not.

The getLink function is called whenever we need to know the link to a specific item or comment. Generally the links that CComment generate look like this: index.php?option=com_comment&task=comment.goToComment&id=10 (10 is the id of the comment). When the user clicks on this link CComment is going to load the necessary plugin and execute the getLink function by passing to it the contentid, commentid & boolean xhml (the xhtml parameter will determine if the link generated should have the & replaced by &amp;). You should make sure that the link that you generate in the getLink function is the same as the one the component generates. This means if the component generates a link with a category id and alias in it, you should also have the category id and alias in it.

For example the link to com_content look like this:

index.php?option=com_content&view=article&id=1:article-alias&catid=1:category-alias&Itemid=435

The link that the getLink function generates should be exactly the same only with the addition of an anchor for example:

index.php?option=com_content&view=article&id=29121:new-article&catid=972:uncategorized&Itemid=435#ccomment-comment=325

Having the anchor tag will tell CComment that it has to show comment 325 (if you use pagination, then ccomment will be loaded on the page where comment 325 is and will center on it)

Creating the same link as the component that we integrate CComment with will guarantee that when the user enables SEF CComment will generate correct links.

The getItemTitles is returning an array with objects each with id & title for the item that the comment belongs to. For example this function is used in the backend on the comments list view - the Content Item column. This function expects an array with content ids.

The getPageId function returns the id of the row object. Depending on the component you will most probably won't need to override this function, but if you are integrating with a component that doesn't use the variable name id for the row, but for example article_id, you'll need to override this function and return the correct id there.

The getAuthorId function return the id of the user that has created the content item we are commenting in. Used to determine if the currently logged in user is the author of the content item and if the "content creator moderator" function is set to yes, then this user will have moderator priviligies in this item.