Composr Supplementary: Making an addon (part 2)
Written by Chris Graham
Potentially Outdated Tutorial
This supplementary tutorial might be outdated as it was written for a previous version of Composr CMS (version 10).
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://yourbaseurl/?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 'mini-module'.
Here is our adminzone/pages/mini-modules_custom/admin_tracking.php file:
Code (PHP)
<?php
/*
Simple script to track advertising purchase successes.
Requires the Composr super_logging option enabled.
*/
$success = array();
$joining = array();
$failure = array();
$users_done = array();
$advertiser_sessions = $GLOBALS['SITE_DB']->query('SELECT member_id,s_get,ip,date_and_time FROM ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'stats WHERE date_and_time>' . strval(time() - 60 * 60 * 24) . ' AND s_get LIKE \'' . db_encode_like('%<param>from=%') . '\'');
foreach ($advertiser_sessions as $session) {
if (array_key_exists($session['member_id'], $users_done)) {
continue;
}
$users_done[$session['member_id']] = 1;
if (!preg_match('#<param>from=([\w\d]+)</param>#', $session['get'], $matches)) {
continue;
}
$from = $matches[1];
$user = $session['member_id'];
if (!array_key_exists($from, $success)) {
$success[$from] = 0;
$failure[$from] = 0;
$joining[$from] = 0;
}
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 member_id=' . strval($user) . ' AND date_and_time>=' . strval($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_url'], 0, 200)) . ')</p>';
}
$ip = $GLOBALS['SITE_DB']->query_select_value_if_there('stats', 'ip', array('the_page' => 'site/pages/modules/join.php', 'member_id' => $user), '', 1);
$user = ($ip === null) ? null : $GLOBALS['SITE_DB']->query_value_if_there('SELECT member_id FROM ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'stats WHERE ' . db_string_equal_to('ip', $ip) . ' AND member_id>0');
if ($user !== null) {
$joining[$from]++;
}
$test = ($user === null) ? null : $GLOBALS['SITE_DB']->query_select_value_if_there('stats', 'id', array('the_page' => 'site/pages/modules_custom/purchase.php', 'member_id' => $user));
if ($test !== null) {
$success[$from]++;
} else {
$failure[$from]++;
}
}
echo '<p><b>Summary</b>...</p>';
echo 'Successes...';
print_r($success);
echo '<br />';
echo 'Joinings...';
print_r($joining);
echo '<br />';
echo 'Failures...';
print_r($failure);
?>
/*
Simple script to track advertising purchase successes.
Requires the Composr super_logging option enabled.
*/
$success = array();
$joining = array();
$failure = array();
$users_done = array();
$advertiser_sessions = $GLOBALS['SITE_DB']->query('SELECT member_id,s_get,ip,date_and_time FROM ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'stats WHERE date_and_time>' . strval(time() - 60 * 60 * 24) . ' AND s_get LIKE \'' . db_encode_like('%<param>from=%') . '\'');
foreach ($advertiser_sessions as $session) {
if (array_key_exists($session['member_id'], $users_done)) {
continue;
}
$users_done[$session['member_id']] = 1;
if (!preg_match('#<param>from=([\w\d]+)</param>#', $session['get'], $matches)) {
continue;
}
$from = $matches[1];
$user = $session['member_id'];
if (!array_key_exists($from, $success)) {
$success[$from] = 0;
$failure[$from] = 0;
$joining[$from] = 0;
}
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 member_id=' . strval($user) . ' AND date_and_time>=' . strval($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_url'], 0, 200)) . ')</p>';
}
$ip = $GLOBALS['SITE_DB']->query_select_value_if_there('stats', 'ip', array('the_page' => 'site/pages/modules/join.php', 'member_id' => $user), '', 1);
$user = ($ip === null) ? null : $GLOBALS['SITE_DB']->query_value_if_there('SELECT member_id FROM ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'stats WHERE ' . db_string_equal_to('ip', $ip) . ' AND member_id>0');
if ($user !== null) {
$joining[$from]++;
}
$test = ($user === null) ? null : $GLOBALS['SITE_DB']->query_select_value_if_there('stats', 'id', array('the_page' => 'site/pages/modules_custom/purchase.php', 'member_id' => $user));
if ($test !== null) {
$success[$from]++;
} else {
$failure[$from]++;
}
}
echo '<p><b>Summary</b>...</p>';
echo 'Successes...';
print_r($success);
echo '<br />';
echo 'Joinings...';
print_r($joining);
echo '<br />';
echo 'Failures...';
print_r($failure);
?>
We call up the mini-module by going to http://yourbaseurl/adminzone/?page=admin_tracking, as we saved it as a page in the Admin Zone.
The mini-module 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 Composr 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, Composr 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.
Exercises
Players module
Make a mini-module that shows the top 10 point givers, and the top 10 point recipients.Be imaginative
Make a mini-module of your own design, and release it as an addon.Points challenge
60 https://composr.app points will be given to any user that releases a working Composr 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
- Making an addon (part 1)
- Making an addon (part 3)
- Composr site structure
- The Composr programming framework
- Introduction to programming
- Guide to web technologies (including HTML, CSS, and JavaScript)
- Tempcode programming
- Manually editing your database with phpMyAdmin
- Code Book, contents and introduction
- PHP website
Feedback
Please rate this tutorial:
Have a suggestion? Report an issue on the tracker.