HTML Logo by World Wide Web Consortium ( Click to learn more about our commitment to accessibility and standards.

Moving forward with Composr

ocPortal has been relaunched as Composr CMS, which is now in beta. ocPortal 9 will be superseded by Composr 10.

Head over to for our new site, and to our migration roadmap. Existing ocPortal member accounts have been mirrored.

ocPortal Tutorial: Making an addon (part 2)

Written by Chris Graham, ocProducts
Welcome to the second of our series of addon making tutorials. If you haven't yet read the first tutorial then it's advisable that you do so before reading this one.

Making a tracking module

Today we're going to make a module that will allow you to track visitors progress through your website, for all those who enter your website with a special 'from' label in the URL (e.g. http://baseurl/?from=affiliate1).

We'll also keep tally of whether they visited the purchase module and whether they joined, to get an idea on how 'successful the visit was' from the webmaster's point of view.

As with the previous tutorial, we'll avoid making things difficult for ourselves, and just write our code in English, without using templates. As we're making a module this time, we'll be implementing using a 'minimodule'.

Here is our adminzone/pages/minimodules_custom/admin_tracking.php file:




Simple script to track advertising purchase successes.
Requires the ocPortal super_logging option enabled.


$advertiser_sessions=$GLOBALS['SITE_DB']->query('SELECT the_user,get,ip,date_and_time FROM '.$GLOBALS['SITE_DB']->get_table_prefix().'stats WHERE date_and_time>'.(string)(time()-60*60*24).' AND s_get LIKE \''.db_encode_like('%<param>from=%').'\'');
foreach ($advertiser_sessions as $session)
   if (array_key_exists($session['the_user'],$users_done)) continue;

   if (!preg_match('#<param>from=([\w\d]+)</param>#',$session['get'],$matches)) continue;

   if (!array_key_exists($from,$success))

   echo '<b>Tracking information for <u>'.$from.'</u> visitor</b> ('.$session['ip'].')....<br />';
   $places=$GLOBALS['SITE_DB']->query('SELECT the_page,date_and_time,referer FROM '.$GLOBALS['SITE_DB']->get_table_prefix().'stats WHERE the_user='.(string)intval($user).' AND date_and_time>='.(string)intval($session['date_and_time']).' ORDER BY date_and_time');
   foreach ($places as $place)
      echo '<p>'.escape_html($place['the_page']).' at '.date('Y-m-d H:i:s',$place['date_and_time']).' (from '.escape_html(substr($place['referer'],0,200)).')</p>';

   $user=is_null($ip)?NULL:$GLOBALS['SITE_DB']->query_value_null_ok_full('SELECT the_user FROM '.$GLOBALS['SITE_DB']->get_table_prefix().'stats WHERE '.db_string_equal_to('ip',$ip).' AND the_user>0');
   if (!is_null($user)) $joining[$from]++;
   if (!is_null($test)) $success[$from]++; else $failure[$from]++;

echo '<p><b>Summary</b>...</p>';
echo 'Successes...';
echo '<br />';
echo 'Joinings...';
echo '<br />';
echo 'Failures...';


Thumbnail: Our minimodule in action on Heavily censored to protect our and our visitors privacy ;).

Our minimodule in action on Heavily censored to protect our and our visitors privacy ;).

We call up the minimodule by going to http://baseurl/adminzone/?page=admin_tracking, as we saved it as a page in the Admin Zone.

The minimodule is actually very simple – mainly it just looks for all the hits to the website where a 'from' parameter was given, and then puts out all the URLs they visited since entering the site, by date, along with some other basic information. It also looks for whether each hit user joined or went to purchase and tallies it against each 'from' value it finds.

But but but…

You said

But, you just threw out that code and it worked?! That kind of thing doesn't happen for me. I could never do that.

I can ensure you I certainly didn't just throw out that code ;). The reality is that even the best programmers, when they're lucky, spend half their time writing code and half of their time fixing what they thought was already perfect.

Persistence is vital. In fact, when you're learning, mistakes are vital. The absolute best way to learn to program is by making mistakes, because the process of debugging forces you to look really deeply at what's going on, giving you a much better understanding than you likely had before. In this example I used some SQL and, as a learner, you might not really understand SQL yet. When I first wrote SQL I didn't understand it either, and what I wrote back then was based on copying patterns I'd seen other people use. If there was a mistake in my SQL the process of debugging it would force me to really understand how it worked, expanding my knowledge. After time, things get easier and easier, and you're able to achieve better results, be able to build more complex systems with greater ease. I'm sure you don't know your way through the ocPortal API yet, but eventually you will learn it and before all too long you won't even have to look things up a lot of the time, even when writing huge modules.

If you're really serious about programming, read lots of books and write lots of addons, starting small and working your way up. In time, you'll be as good as the professionals. There's a good chance, based on our demographics, that you're still in education – well, ocPortal could be a good medium for you to develop professional skills that could get you a job (even one with us, in the long term) – this, and real interest, are the true motivation for most Open Source work.


Players module

Make a minimodule that shows the top 10 gift point givers, and the top 10 gift point receivers.

Be imaginative

Make a minimodule of your own design, and release it as an addon.

Points challenge

60 points will be given to any user that releases a working ocPortal addon that is likely useful to more than one person.
To claim your prize, post in the Addons forum and 'report post' with the phrase '60 points please' in your report.

See also