Wednesday, November 14, 2012

Creating new homepage default widgets for vTiger


Create a new, custom "default widget" for the vtiger home page.  

We wanted to do this pretty badly. However, the vTiger documentation on the code sucks dead bunnies and the only post anywhere about how to do it was by someone whose native language was not english and who assumed "rather a lot" about the environment you were putting the modification into.


This post documents our process to get custom widgets running in vTiger 5.4.0. I make no guarantees that I didn't leave something out, but I tried by golly, and it's pretty good documentation as it sits. Good luck and happy programming!

-_ Rick


In general, default widgets can display rows of data from sql queries.  This description only explores that space.  If you want widgets to do something else... for example flip through a slide show of recent security videos, or scroll a list of recent telephone callers or something, that's beyond the scope of this discussion.  This is plenty hard enough due to the utter lack of documentation.  

Files affected:

modules/Users/Users.php
modules/Users/language/en_us.lang.php
modules/Home/language/en_us.lang.php
include/Home.php

Step 1:

Create and perfect a sql query using phpMyAdmin or some other tool that returns exactly the results you want to see in your widget. Test it until it's exactly right, and then copy it to notepad or something to hold for a bit.  

You can perform post-processing (You’ll see that below.) Try to keep your number of columns down.  Note that the columns names in your query do not need to match the column labels you want to use.  Note also that your columns can contain html including "A" tags to produce links.  But you must perfect this query before you ever start.

Step 2:

Decide on a "identifying code",  a name for your widget, and the label each of the columns to be displayed.  

Step 3:

Modify modules/Users/Users.php

Add your widget's identifying code you picked above to two arrays.   In this example we will use "SOLD" as the identifier.

First, modify $homeorder_array

var $homeorder_array = array('HDB','ALVT','PLVT','QLTQ','CVLVT','HLT','OLV','GRT',
'OLTSO','ILTI','MNL','OLTPO','LTFAQ', 'UA', 'PA', 'SOLD');

(we added 'SOLD' at the end of the list)

Do the same in the function getHomeStuffOrder($id)

$this->homeorder_array = array('UA', 'PA', 'ALVT','HDB','PLVT','QLTQ','CVLVT','HLT','GRT','OLTSO','ILTI',
'MNL','OLTPO','LTFAQ','SOLD');

Again, we added 'SOLD' to the end of the list.  Don't forget the comma.

The above will allow vtiger to pull the widget into your myprefrecnes view so you can select to make visible

Step 4:  

Add your widget to the list of widgets in Users.php. You might think that the widgets would be stored in a table and looped through, but no....  they're in three long chains of repetative code.  You have to add your widget to all three.  In this first segment, we add the widget to the code that creates the list of widgets a user can access. It is very annoying that The system only runs this routine when a user is created.  You will need to back-fill your existing users data in order for them to have this new cool widget. Since there were no provisions in the code for a person to add a widget, it probably seemed reasonable to the developers to have the widgets on/off toggles in the vtiger_homestuff table be populated when a user is created.  After all, they're never going to change.  Oh.  Right.  We're changing them.  

Anyway, so, we're going to add the code to add your widget to the DB when a user is created. After we're done, you can insert the widget into your existing users -- we'll discuss that later...

Find the function insertUserDetails($inVal).  You will see that it has a recurring theme, for each 'default widget' there is a block of code that starts with $S1= and $S2= etc etc...  in my copy this starts at or around line 1147.  Add yours at the bottom after $S14=  


//** Custom SOLD widget ID inserted into vtiger_homestuff
$s18=$adb->getUniqueID("vtiger_homestuff");
$visibility=$this->getDefaultHomeModuleVisibility('SOLD',$inVal);
$sql="insert into vtiger_homestuff values(?,?,?,?,?,?)";
$res=$adb->pquery($sql, array($s18,18,'Default',$uid,$visibility,'Sold Policies'));

Obviously, replace 'SOLD' with your widget's identifier, and 'Sold Policies' with your widget's title from step 1.

Now, scroll down about 40 lines and you will see a long series of two lines one that starts $sql, and the next starts $adb.  You need to insert your widget here as well.

//** Custom SOLD widget ID inserted into vtiger_homedefault
$sql="insert into vtiger_homedefault values(".$s18.",'SOLD',10,'Dashboard')";
$adb->query($sql);

Important note:  The last element in this insert statement must either be an active module in vtiger, or the word "Dashboard".  If you're just doing an arbitrary query widget, and you don't want it's availability linked to any specific module, then Dashboard is the appropriate choice.  If you only want people who have access to Opportunities or Contacts or PurchaseOrders or whatever to have access to this widget, feel free to use the module's name instead.  The availability of the widget will be linked to the availability of the module.

Step 5

In include/home.php within the function getDefaultDetails($dfid,$calCnt) add the code that will call your new custom widget's function that will return data.  

In include/home.php, in the function getDefaultDetails() there is a long series of if, else if, else if .....  You're going to add your call to the bottom of this chain immediately before the return line:  in my copy this is around line 484.  

}elseif($hometype=="SOLD" && vtlib_isModuleActive("Leads")){
if(isPermitted('Leads','index') == "yes"){
$home_values=$this->getSoldWidgetData($dfid);
}
}

Well, we really need to talk about that some more.  Several issues.  If you don't care if the "Leads" module is active, you don't need to have it in there.  The following version is perfectly ok for a widget that should be universally available to everyone.  

} elseif($hometype=="SOLD") {
$home_values=$this->getSoldWidgetData($dfid);
}

Step 6

In the call we inserted into step 5, we had the program set $home_values = $this->getSoldWidgetData($dfid).  In many of the other cases, the program uses a require_once or include_one to link to a different program file that contains the function that returns the data for the widget.  Since I'm going to be merging my changes into the source every time I update vtiger anyway, I would (and did) simply add it at the bottom of include/Home.php, thus the reference to $this.  You can do as you like.  

So, anyway, we need to create the custom function that retrieves your data.  The function needs to return an array loaded with all the details to display a widget.

You will need to write a similar function that returns the array the widget display code is looking for.

function getSoldWidgetData($dfid)

// First, do the query that gives you the data for the widget

$sql = ‘select state, city, products from vtiger_organization’;
//((((code to do the actual query))))
$result=$db->pquery($sql)

// Next, we make the title array that holds the info that
// goes at the top of the widget box.
// The first element can be a pointer to an image.  
// As an example, consider the image in the tag cloud widget.
// If you don't have an image, the first element can be blank.
// The second element is the title that should appear at the
// top of the box.  In order to be language indepent
// vtiger uses the $app_strings array to hold the labels for
// things, and those strings are built from the
// various languages files.   We will update those files later
// in this process.  
// The third element is a variable name for this widget.  
// Most of the widgets use a variable of the form home_widgetIDcode
// That seems reasonable to me, so I followed the trend.  

$title=array();
$title[]='myWidgetImage.gif';
$title[]=$app_strings['SOLD'];
$title[]='home_sold';

// The second array has the labels for the columns in the widget.  
// The number of elements here has to match the number of elements
// in the value array we will construct lower down.

$header=Array();
$header[]='State';
$header[]='Capital';
$header[]='Symbol';

// The third array is one array element for each row of
// data to be displayed in the widget box.  
// The row array entries then contain an array of the
// fields or columns going across.   
// so,  $entries[1] contains  $value['Kansas', 'Topeka', 'Wheat']

$entries=Array();

for($l=0; $l<$row_count; $l++){
$statename = $adb->query_result($result,$l,"statename");
$capname = $adb->query_result($result,$l,"capname");
$product = $adb->query_result($result,$l,"product");

$value=array();
$value[]='$statename;
$value[]='$capname';
$value[]=$product;
$entries[]=$value;
}

// Finally, we take the three arrays and shove them
// into a single $values array that we return.  

$values=Array('Title'=>$title,'Header'=>$header,'Entries'=>$entries);

if ( ($display_empty_home_blocks ) || (count($value)!= 0) )
return $values;
}




Step 7

Finally, we need to get your widget identifier into the various language files. In my case that was
modules/Users/language/en_us.lang.php
modules/Home/language/en_us.lang.php

these files are each one giant array specification, and you just need to insert your identifier anywhere in the array...

//Add new widget(s) name
'SOLD'=>'States we sold stuff in',
//end


Step 8

Now, create a new user. Then, use phpmyadmin or something to go find the entries for the new user in vtiger_homestuff. The record will have entries that contain a unique identifier for this widget,18,'Default',The userID,0 which means this widget is visible,and the title you set for the widget -- in our case 'States we sold stuff in'. Make those changes in both language files. If you need to, modify other languages files in a similar way.

At this point, log out, log in as a user with this widget and by golly, it ought to come up.
Post a Comment