Customizing Joomla 1.5


Update: Paceville.com is now online.

The other day I had to create some custom lists using data from JomSocial, creating a plugin for JomSocial was not a problem, great problem solved. Some hour later I had to manipulate some stuff in MyBlog, Christ a new plugin? Too much nonsensical work all of a sudden.

Including your script in Joomla’s index.php will do the trick though, like this for instance:

. . .
/**
 * INITIALISE THE APPLICATION
 *
 * NOTE :
 */
// set the language
$mainframe->initialise();

JPluginHelper::importPlugin('system');

// trigger the onAfterInitialise events
JDEBUG ? $_PROFILER->mark('afterInitialise') : null;
$mainframe->triggerEvent('onAfterInitialise');

require_once('plugins/community/community_ext.php');

/**
 * ROUTE THE APPLICATION
 *
 * NOTE :
 */
$mainframe->route();
. . .

I suppose since we include our stuff after onAfterInitialise we are able to access all the functionality, Joomla core and all included stuff.

Let’s take a look at my community extension:

defined( '_JEXEC' ) or die( 'Restricted access' );
if($GLOBALS['admin'] != true){
	require_once( JPATH_BASE . DS . 'components' . DS . 'com_community' . DS . 'libraries' . DS . 'core.php');
	require_once( JPATH_ROOT . DS . 'components' . DS . 'com_myblog' . DS . 'defines.myblog.php' );
	require_once( MY_COM_PATH . DS . 'task' . DS . 'base.php' );
	require_once( MY_COM_PATH . DS . 'functions.myblog.php' );
}

class plgCommunityExt{
	
	//put methods here
	
}

function cExt(){
	if(!empty($GLOBALS['cExt']))
		return $GLOBALS['cExt'];
	else{
		$GLOBALS['cExt'] = new plgCommunityExt();
		return $GLOBALS['cExt'];
	}
}

The cExt() global function lets us work with only one extension object wherever we are in the maze of different code that’s included in the form of plugins, components, modules and God knows what.

Note also that we don’t include the community and blog stuff if we use the class in the administrator back end code, the paths would end up being screwed there, besides the fact that they’re not needed there yet…

Let’s take a look at a few examples of member methods:

function db(){
	return empty($this->db) ? JFactory::getDBO() : $this->db;
}

function loadResult($sql){
	$this->db = $this->db();
	$this->db->setQuery($sql);
	return $this->db->loadResult();
}

function loadObject($sql){
	$this->db = $this->db();
	$this->db->setQuery($sql);
	return $this->db->loadObject();
}

function updateObject($tbl, $keys, $key){
	$this->db = $this->db();
	$sql = "UPDATE $tbl SET ";
	$arr = array();
	foreach($keys as $k)
		$arr[] = "$k = '{$_POST[$k]}'";
	$sql .= implode(',', $arr) . " WHERE $key = '{$_POST[$key]}'";
	$this->db->setQuery($sql);
	$this->db->query();
}

function loadObjectList($sql){
	$this->db = $this->db();
	$this->db->setQuery($sql);
	return $this->db->loadObjectList();
}

These are some utility functions wrapping commonly used Joomla functionality.

And a few examples of how they can be used to create a custom menu system:

function setMenuItems($pos){
	$sql = "SELECT DISTINCT menu.*
			FROM jos_menu menu, jos_modules module, jos_modules_menu AS connect
			WHERE menu.id = {$this->getArr['Itemid']}
			AND menu.id = connect.menuid
			AND module.id = connect.moduleid
			AND module.position = '$pos'";
	$this->curItem = $this->loadObject($sql);
	$this->parentMenu = $this->getParentMenu($pos);
	$this->childMenu = $this->getChildMenu($pos);
	$this->setCurItems();
}

function setCurItems(){
	if($this->curItem->parent == 0){
		$this->curParent = $this->curItem;
		$this->curChild = new stdClass();
	}else{
		$this->curChild = $this->curItem;
		foreach($this->parentMenu as $parent){
			if($parent->id == $this->curChild->parent){
				$this->curParent = $parent;
				break;
			}	
		}
	}
}

function frontPage(){
	return ($this->getArr['view'] == 'frontpage' && $this->getArr['option'] == 'com_content');
}

function getParentMenu($pos){
	$sql = "SELECT DISTINCT menu.*
			FROM jos_menu menu, jos_modules module, jos_modules_menu AS connect
			WHERE menu.parent = 0
			AND menu.id = connect.menuid
			AND module.id = connect.moduleid
			AND module.position = '$pos' ORDER BY menu.ordering";
	return $this->loadObjectList($sql);
}

function getChildSql($id, $pos){
	return "SELECT DISTINCT menu.*
			FROM jos_menu menu, jos_menu pmenu, jos_modules module, jos_modules_menu connect
			WHERE menu.parent = $id
			AND menu.id = connect.menuid
			AND module.id = connect.moduleid
			AND module.position = '$pos'
			ORDER BY menu.ordering";
}

function getChildMenu($pos){
	$col_name = $this->curItem->parent == 0 ? 'id' : 'parent';
	$sql = $this->getChildSql($this->curItem->$col_name, $pos);
	$tmp = $this->loadObjectList($sql);
	if(empty($tmp)){
		return array(); //$tmp = $this->loadObjectList( $this->getChildSql($this->parentMenu[0]->id, $pos) );
	}
	foreach($tmp as &$obj){
		foreach($this->parentMenu as $p){
			if($obj->parent == $p->id){
				$obj->pretty_link = $p->alias.'/'.$obj->alias;
				break;
			}
		}
	}
	return $tmp;
}

What you have above is a complete bypass of how Joomla’s shitty menu system normally works, where it seems to be nigh impossible to split up main menu items and their children.

The result is that we can do like this in the template HTML:

<?php
defined( '_JEXEC' ) or die( 'Restricted access' );

$cext = cExt();
$cext->setMenuItems('nav_main');

?>

. . .

<div id="nav_main_cont" class="clearfix">
	<div id="nav_main_left" class="clearfix">&nbsp;</div>
	<div id="nav_main_right" class="clearfix">&nbsp;</div>
	<div id="nav_main_center">
		<ul>
			<?php foreach($cext->parentMenu as $p): ?>
				<li class="<?php if($p->id == $cext->curParent->id) echo "current" ?>">
					<a href="<?php echo $p->alias ?>"> <?php echo $p->name ?> </a>
				</li>
			<?php endforeach ?>
		</ul>
	</div>
	<div id="ie_clearing">&nbsp;</div>
</div>

<div id="nav_sub_cont" class="clearfix">
	<div id="nav_sub_left" class="clearfix">&nbsp;</div>
	<div id="nav_sub_right" class="clearfix">&nbsp;</div>
	<div id="nav_sub_center">
		<ul>
			<?php foreach($cext->childMenu as $c): ?>
				<li class="<?php if($c->id == $cext->curChild->id) echo "current" ?>">
					<a href="<?php echo $c->pretty_link ?>"> <?php echo $c->name ?> </a>
				</li>
			<?php endforeach ?>
		</ul>
	</div>
	<div id="ie_clearing">&nbsp;</div>
</div>

Great, we now have the look and functionality demonstrated in the earlier CSS menu tutorial. We have the sub menu spatially separated from the main menu which enables us to have it look anyway we want, and/or put it anywhere we want. The main menu could for instance be horizontal and each child menu vertical and positioned to the left.

What happens is that we grab the menu assigned to the nav_main position, and all the children of the currently clicked menu item, if the clicked item is a child we grab its siblings, the result will be the childMenu, the parentMenu will always be the same.

Note that for the above to work you still need to setup your main menu just like normal, and make sure you select all its children and members when editing its module. And yes you still need to do that every time you you add an item, we’re not free of all the bullshit just yet :(

The clicked item gets to be a lovely pink :)

Lets look at another example, this time some JomSocial extras:

function getNumUnreadMsg(){
	$my =& JFactory::getUser();
	$inboxModel = & CFactory::getModel ( 'inbox' );
	$filter['user_id'] 	= $my->id;
	return $inboxModel->countUnRead( $filter );
}

function getPendingFriends(){
	$my =& JFactory::getUser();
	$friendModel = & CFactory::getModel ( 'friends' );
	return count( $friendModel->getPending( $my->id ) );
}

Note that we are able to utilize stuff from two different components (JomSocial and MyBlog) at the same time since we are downstream.

Those two will get the number of unread messages and the number of unapproved friend requests respectively. Anywhere we want.

For instance in the mod_login template:

<table border="0" width="236">
		<tr>
			<td width="140" height="10">
				<a href="<?php cExt()->echoCRoute('index.php?option=com_community&view=inbox') ?>">Inbox</a>
			</td>
			<td class="notification_btn" width="10">
				<a href="<?php cExt()->echoCRoute('index.php?option=com_community&view=inbox') ?>">
					<?php echo cExt()->getNumUnreadMsg() ?>
				</a>
			</td>
		</tr>
		<tr>
			<td height="10"><a href="#">Guestbook</a></td><td class="notification_btn" width="10"><a href="#">2</a></td>
		</tr>
		<tr>
			<td height="10">
				<a href="<?php cExt()->echoCRoute('index.php?option=com_community&view=friends&task=pending') ?>">Friendrequests</a>
			</td>
			<td class="notification_btn" width="10">
				<a href="<?php cExt()->echoCRoute('index.php?option=com_community&view=friends&task=pending') ?>">
					<?php echo cExt()->getPendingFriends() ?>
				</a>
			</td>
		</tr>
	</table>

Finally let’s take a look at some raw access:

function getFrontNewest($limit = 10){
	$sql = "SELECT a.*, u.name AS author, COUNT(c.contentid) AS comment_count
			FROM jos_content_frontpage AS f
			LEFT JOIN jos_content AS a ON f.content_id = a.id 
			LEFT JOIN jos_jomcomment AS c ON a.id = c.contentid
			LEFT JOIN jos_users AS u ON u.id = a.created_by
			WHERE a.state = 1
			GROUP BY a.id ORDER BY a.created DESC LIMIT 0, $limit";
	return $this->loadObjectList($sql);
}

Here we grab the newest articles and join to get some other pertinent data too, like for instance the number of comments on each article, the result can be seen in the finished design.

We display the result on our frontpage:

<?php foreach($cext->getFrontNewest() as $article): ?>
	<div class="article_teaser_box">
		<h2><?php echo $article->title ?></h2>
		<?php echo $article->introtext ?>
		<p><a href="<?php echo JRoute::_('index.php?option=com_content&view=article&id='.$article->id) ?>">Read More...</a></p>
		<table class="teaser_comments">
			<tr>
				<td class="num_comments">
					<a href="<?php echo JRoute::_('index.php?option=com_content&view=article&id='.$article->id) ?>">
						<?php echo $article->comment_count ?>
					</a> comments
				</td>
				<td class="author_date">By: <?php echo $article->author ?> on <?php $cext->echoDate( $article->created, 'l dS \of F h:i:s A' ) ?></td>
			</tr>
		</table>
	</div>
<?php endforeach ?>

I hope the above is a help and inspiration for all you out there who are stuck and need a shortcut. It’s not exactly the prettiest or most politically correct way to hack Joomla, but it is quick, and pretty painless.

Related Posts

Tags: , ,