Store
Community Documentation

v3 Knowledgebase

Adding User Group to User Browse. (Ver 3+)

I noticed, while reading through the forum threads, that some would like to see the User's Group name included with the data presented in the browse user page. It seemed to me that this should not be too difficult to implement, so I tinkered with the code a bit and found a way to do this. Then it was suggested that I do a knowledgebase article and, not being one to dismiss such a request easily, I present this now for your consideration.

The first task when faced with a challenge is to assess what you have and what is available to work with. In this case, when we look at the browse user page, we see an array of picture/text boxes. Under the picture is some text which is the user's name. It would make sense to place the Group Name directly under this text.

Now, we need to find out what we have to work with. One way to do this is to look at the data that is already available. If we go to the user browse template, we can find the code for this and see what the original programmers have included. In this case, we can see that the data that they are using mostly comes from an array called $aUsers. What is in this array? One quick way to answer this question is to temporarily insert code to display the array. Somewhere on the template (not within the iteration loop!!) you could place the code
HTML:
{$aUsers|print_r}
. This will show you the content of the array. As you scan through the data looking for the user group name, you find that it is not there. This will represent your first 'darn' (or your choice of curse).

You do see that the user group id is included in the data, so if you wanted to, you could just insert this under the user's name and make it look something like "User Group 3". But who am I kidding? No one wants to see that. User groups need to have names that make sense and whose name implies a sense of social order and importance that our vanity requires.

Looking at the database table structure, we see that user_group_id is included in the user table, but the user group name is in the 'title' field of the user_group table. So to get the information that we need, we have to provide a way to return this field with the other data when it is called originally. There is a way, when making an SQL request, to link two tables and get information from either or both tables.

This may be a good time to look at the code that supplies the data we are discussing. We have been looking at the user.browse template code. The data for this is sent from the user.browse controller. We can look at this code and see this:
PHP:
list($iCnt$aUsers) = Phpfox::getService('user.browse')->conditions($oFilter->getConditions())
    ->
callback($aCallback)
    ->
sort($oFilter->getSort())
    ->
page($oFilter->getPage())
    ->
limit($iPageSize)
    ->
online($bIsOnline)
    ->
extend((isset($bExtendContent) ? true $bExtend))
    ->
featured($mFeatured)
    ->
pending($bPendingMail)
    ->
custom($aCustomSearch)
    ->
gender($bIsGender)
    ->
get(); 


This seems to represent an object that allows you to set a bunch of parameters and then, with the application of the ->get at the end, return the data that we are interested in. Now we can look at the user.browse service file around the get function.

Looking down through the code, we can see near the bottom where the data is called.

PHP:
$aUsers $this->database()->select('u.status_id as unverified, ' . ($this->_bExtend 'u.*, ufield.*' Phpfox::getUserField()))
    ->
from($this->_sTable'u')
    ->
join(Phpfox::getT('user_field'), 'ufield''ufield.user_id = u.user_id')
    ->
where($this->_aConditions)
    ->
order($this->_sSort)
    ->
limit($this->_iPage$this->_iLimit$iCnt)
    ->
group('u.user_id')
    ->
execute('getSlaveRows'); 


We see that there is no link to the user_group table and to get the data we need, we must call this data in a way that will allow access to that table.

One thing that I noticed as I began to look at phpFox code is that there seems to be included within the database
API a mechanism where you can build conditional requirements within the object and they will be applied when the database call is made. Looking up from the above code, there is a block of code that looks like this:
PHP:
if (defined('PHPFOX_IS_ADMIN_SEARCH'))
{
    
$this->database()->select('ug.title AS user_group_title, ')->join(Phpfox::getT('user_group'), 'ug''ug.user_group_id = u.user_group_id'); 


It turns out that this is exactly what we need to call the information for the user group. Why is it here? Because (as indicated by the conditional statement) the admincp browse feature does include the user group with the returned info. So in order to get this information, all we need to do is insert one line of code somewhere before the database call. This would be a good time to look for hooks.

Looking up through the service file code, we find a hook around line 249. This one is called 'user.service_browse_get__cnt'.
NOTE, before ver 3.1.0 beta 1 the code near the end looks like
PHP:
{return eval($sPlugin

This was changed after the above mentioned version and if you want to let this code work with versions prior to this then you must hack the file to remove the 'return' portion of the code. So it should look like
PHP:
{eval($sPlugin
If you are using ver 3.1.0 then you do not need to change this. Note 2. If you ever change a core file, always make a duplicate copy of the file that you can restore if you really screw up the code while changing it. (rule 47: Always have a backup)(The rule reference can be taken from either NCIS or Zombieland).

So we can go to the admincp and select extensions->create new plugin.
Leave the product as 'phpFox'
Set the module as 'user'
Name the plugin something appropriate.
Select 'user.service_browse_get_cnt' (between 1/3 and 1/2 way down the list)
Leave the Active toggle as 'yes'
Insert this code into the code block:
PHP:
if (!defined('PHPFOX_IS_ADMIN_SEARCH'))
{
$this->database()->select('ug.title AS user_group_title, ')->join(Phpfox::getT('user_group'), 'ug''ug.user_group_id = u.user_group_id');


NOTE: Remember, we discovered that this service call is also used for the admincp browse and it already uses this code, so we need it only to apply to non-admin searches.

Applying this plugin will cause the data that we need to be included with the $aUsers data. Now we need to alter the template a bit in order to display our new information.

A good way to do this is to use the template edit feature in the admincp. Go to AdminCP->manage themes ->edit templates (on whatever themes you want this applied to) -> user -> browse (controller). Down near the bottom (line 281 of 334) you will find code that looks like:

VERSION 3.0:
HTML:
<div class="user_browse_user">
	{$aUser|user|split:25}
	{if Phpfox::isModule('friend')}
	{if $aUser.mutual_friends > 0}
	<div class="user_browse_mutual_friend">

ADD CODE BETWEEN LINE 2 AND 3

<div class="user_browse_user">
	{$aUser|user|split:25}
	{$aUser.user_group_title|split:25}
	{if Phpfox::isModule('friend')}
	{if $aUser.mutual_friends > 0}
	<div class="user_browse_mutual_friend">


Version 3.1:
HTML:
<div class="user_browse_user">
	{$aUser|user:'':'':50|split:12}
	{if Phpfox::isModule('friend')}
	{if $aUser.mutual_friends > 0}
	<div class="user_browse_mutual_friend">

ADD CODE BETWEEN LINE 2 AND 3

<div class="user_browse_user">
	{$aUser|user:'':'':50|split:12}<br />
	{$aUser.user_group_title|split:12}
	{if Phpfox::isModule('friend')}
	{if $aUser.mutual_friends > 0}
	<div class="user_browse_mutual_friend">


Note: The $aUser here is a single record from the $aUsers array.

With this code in place and all caches cleared, you should now have the user group displayed under the user's name.

One final note. When doing this plugin, I had a lot of trouble making the applied changes to the template work. After a lot of wasted time trying to figure out why it didn't work, I finally discovered that on my dev site, I have a dev.sett.php file which does a lot of good things for developing the site, but one thing that I hadn't noticed before was a setting:

PHP:
// Use live templates and not those from the database 
define('PHPFOX_LIVE_TEMPLATES'true); 


This will effectively prevent any changes made to the template in the admincp from working. To alleviate this, you can double slash the define line or rename the dev.sett.php file temporarily while working on this project.

I hope this article is informative and useful. I have tested this on ver 3.0 (with the core hack mentioned) and on ver 3.1 with no problems. If you run into problems after trying this, leave a comment and I will try to address it.

Webwolf

NOTE: In later versions of phpfox, there are 2 places that need to be changed in the template. Look around lines 280 and 330 for the {$aUser...} code.