An Extension Autopsy from Dr. Jones
Greetings! My name is Derek, and I’m a Mac. It’s great to be on the development team, and under the ever watchful eye and furrowed brow of Paul, I’ll be posting DevBlog entries from time to time as well.
Recently on my own blog I presented an extension that adds some functionality to the member registration process that I see requested from time to time: requiring submission of a birthday during member registration. The hooks used and the script itself is rather simple, and can be used as a basic skeleton for adding other standard ExpressionEngine member fields to your registration form. For instance, Paul whipped up an extension recently that handles uploading an avatar upon submission. In order to help new developers understand what’s happening behind the scenes, I’m going to dissect my Register Birthday extension.
class Register_birthday
{
var $settings = array();
var $name = 'Register Birthday';
var $version = '1.0';
var $description = 'Allows use of birthday fields in member registration';
var $settings_exist = 'n';
var $docs_url = 'http://expressionengine.com/downloads/details/register_birthday/';
// CONSTRUCTOR
function Register_birthday($settings='')
{
$this->settings = $settings;
}
This is a very basic class definition and constructor for our extension. It defines some variables for us, rather self explanatory, and these are all standard in ExpressionEngine extensions. If the extension had some settings, we would have a settings function to handle that for us.
Now skip down to the activate_extension() function. These database inserts are standard, and are described in the User Guide. Here’s how they break down.
'class' => "Register_birthday",
'method' => "add_birthday",
'hook' => "member_member_register",
...
'class' => "Register_birthday",
'method' => "verify_fields",
'hook' => "member_member_register_start",
We’re telling ExpressionEngine that when it executes the “member_member_register” hook, that it should use the add_birthday method in the Register_birthday class (that’s us!) And that when it’s time to execute scripts for the “member_member_register_start” hook, that it should use the verify_fields method in the Register_birthday class (us again!). Now if you look at the two other functions in our extension, it should be clear what’s going on. In mod.member_register.php when this code is encountered:
/* -------------------------------------------
/* 'member_member_register_start' hook.
/* - Take control of member registration routine
/* - Added EE 1.4.2
*/
$edata = $EXT->call_extension('member_member_register_start');
if ($EXT->end_script === TRUE) return;
/*
/* -------------------------------------------*/
ExpressionEngine is going to use our verify_fields() function (method). So let’s look at that now, as this is the first extension called. This extension hook is one of the first things encountered in the register_member() function of mod.member_register.php. It will execute before much has been processed. In fact, the only thing that occurs before this hook in the registration routine is checking to see that new registrations are allowed, that the user isn’t banned, and that they clear the blacklist. This hook also gives us a way to stop any further processing by the member registration routine, which will prove to be important.
On to our function, verify_fields():
global $EXT, $IN, $OUT;
Here we reference three global class objects: extension, input, and output. These happen to be core files, and you can view their variables and methods in core.extensions.php, core.input.php, and core.output.php respectively.
if ($IN->GBL('bday_d', 'POST') == "" || $IN->GBL('bday_m', 'POST') == "" || $IN->GBL('bday_y', 'POST') == "")
The $IN->GBL() method gives us an easy way to gain access to the $_POST array, which contains the data from our member registration form. In the markup given to use in the registration form for this extension, the default values for day, month, and year were all “”, an empty string. We can then use this to tell whether or not the user selected a value, or accidently forgot to use one of the drop-down fields. If any of the three select fields has an empty value, we’re going to execute the following code.
$EXT->end_script = TRUE;
This tells ExpressionEngine to stop any processing from going on after our extension turns the reins back over to the function it was called from. Remember that in the extension hook, ExpressionEngine uses
if ($EXT->end_script === TRUE) return;
which causes the calling function to prematurely return. We need to do this in our case because if we were to allow the register_member() function to continue processing, it will insert the user into the database, and we won’t have any birthday values to give it. We’d like to be friendly about this, though, so:
return $OUT->show_user_error('submission', 'You must submit a valid birthday');
Our extension will return gracefully and call the show_user_error() method to display a submission error from the Output class.
Now if we’ve gotten past this part, i.e. none of the three birthday fields were empty, then the register_member() function will go about its business until this hook:
// -------------------------------------------
// 'member_member_register' hook.
// - Additional processing when a member is created through the User Side
//
$edata = $EXT->call_extension('member_member_register', $data);
if ($EXT->end_script === TRUE) return;
//
// -------------------------------------------
By the time this hook is called, the member data has already been inserted into the database. So our first task is to reference the global database and input class objects, so let’s look at our next function, register_birthday($data):
global $DB, $IN;
The Database class has a very useful function for creating MySQL UPDATE strings for us. It speeds development and helps ensure proper syntax. So we’ll prepare an array of the field names and values that we want to insert. We’ll again use the Input class to access the data from the $_POST array, which we know will have valid values as this code will never execute if our valid_fields() function errors out. I did this all on one line in the extension code, but for readability in this reduced width text area, I’ve used multiple lines.
$birthday = array(
'bday_d' => $IN->GBL('bday_d', 'POST'),
'bday_m' => $IN->GBL('bday_m', 'POST'),
'bday_y' => $IN->GBL('bday_y', 'POST')
);
And now we’re ready to update the user’s information in the database that was already inserted by the member registration routine. The hook passed to us an array, $data, that contains some identifying information about the new user. One of the values is the username, which we will use to make sure we update the correct member’s information.
$DB->query($DB->update_string("exp_members", $birthday, "username = '".$DB->escape_str($data['username'])."'"));
The $DB->update_string() method takes three parameters. First, the name of the database table. Second, the array in $key => $val pairs, the $key being the name of the database field, and the $val being the value to be inserted. Third, is the “WHERE” portion of the query, that allows us to restrict which record(s) we are updating. In our case, that’s
"username = '".$DB->escape_str($data['username'])."'"
It’s good practice to escape data before inserting it into the database. In this case, since we used drop-down fields, it’s not particularly necessary, but it’s a beneficial practice to stick to, and the $DB->escape_str() method will handle this for us.
The $DB->update_string() method outputs a string like this:
UPDATE `exp_members` SET `bday_d` = '30', `bday_m` = '08', `bday_y` = '1978' WHERE username = 'the_username'
and our member now has the birthday set.
Hopefully this will encourage fresh developers who are shy of trying extensions to dig in and give them a go. This is a very basic example, and can be easily modified or expanded depending on your needs for member registration.





