Andy on WordPress

Photo Blog

BuddyPress Components 1.0 Beta 1 — December 15, 2008

BuddyPress Components 1.0 Beta 1

After ten months of work, BuddyPress components and themes are available for download in their first beta release form.

We’re looking for testers, so if the project interests you, give it a shot and please report any bugs you find. Each component and theme will be upgraded to a final 1.0 version once it’s clear that it’s running with no major problems.

If you’re interested in testing BuddyPress without downloading and installing it, head on over to the demo site and register for an account there. The demo site runs the latest development release of BuddyPress.

For more information on the release, check out the blog post on the BuddyPress website.

Creating Gravatar Enabled Conference Badges: A How-To — August 8, 2008

Creating Gravatar Enabled Conference Badges: A How-To

For the first time this year, WordCamp San Francisco conference badges will include your gravatar. Adding photos to conference badges is nothing new, however bringing your online gravatar into the offline world is a fairly exciting move.

I’d like to share how I created the PHP script to generate the badges. I hope people can re-use the script for future WordCamps, or even any other conferences. If you want to skip the tutorial and just download the script, here it is. I’ve released it under the GNU/GPL 2 license.

Step 1: The FPDF library

The FPDF library is a free to download and use, open source library that will generate PDF files without the need for any specific PHP libraries. The nice thing about it is the documentation is easy to read and has good examples.

Head on over and download the library. You’ll want to create a new directory to store everything in. I called mine “badge-gen” but you can call it whatever you like. Extract the FPDF library into a folder called “fpdf” in the root of your main directory.

Step 2: Create the generation script and include everything we need

Create two new PHP files in the root of your main directory and call one “generate.php” and the other “functions.php”. In the generate.php file we need to require everything we need to set up the environment:

require('fpdf/fpdf.php'); // require the FPDF library
require('functions.php'); // require the functions we are going to use

Step 3: Add image manipulation and download functions

In the functions.php file, we need to add two image manipulation functions and a function to fetch and download gravatars. The first image function will detect the file extension for an image, and the second will convert PNG files to JPG files. Identicons are PNG files with alpha transparency, unfortunately FPDF does not support alpha enabled PNG images, so we need to convert them to JPG images on the fly. You will need the GD image library installed with PHP on your server.

Add these functions to functions.php:

function get_file_by_curl( $file, $newfilename ) { 
    $out = fopen( $newfilename, 'wb' );   
    $ch = curl_init(); 
    curl_setopt( $ch, CURLOPT_FILE, $out ); 
    curl_setopt( $ch, CURLOPT_HEADER, 0 ); 
    curl_setopt( $ch, CURLOPT_URL, $file ); 
    curl_exec( $ch );    
    curl_close( $ch ); 

function get_image_extension($filename) {
	$type_mapping =  array( '1' => 'image/gif', '2' => 'image/jpeg', '3' => 'image/png' );
	@$size = GetImageSize( $filename );

	if ( $size[2] && $type_mapping[$size[2]] ) {
		if ( $type_mapping[$size[2]] == 'image/gif' )
		        return '.gif';

		if ( $type_mapping[$size[2]] == 'image/jpeg' )
			return '.jpg';

		if ( $type_mapping[$size[2]] == 'image/png' )
			return '.png';
	return '.jpg';

function pngtojpg( $file ) {
	if ( get_image_extension( $file ) == '.png' ) {
		$image = imagecreatefrompng( $file );
		imagejpeg( $image, $file . '.jpg', 80 );
		return $file . '.jpg';
	} else {
		return false;

Step 4: Add image download and template directories

We’ll need to make use of a few images for the badges. The entire background on the WordCamp badges is an image. Try and make your images 300dpi, and then scale them down to the size you need in the code. This will ensure that each badge prints in good quality, and doesn’t come out as a pixelated mess.

Store all your images in an “/images” directory in the root of your main folder. This example only includes one static image, the background we just mentioned. You can download the file here.

Due to the way that gravatar image URLs work (they don’t have any sort of file extension and are just a URL with GET variables and an MD5 of your email) we will need to download them before we can add them to badges. This is a limitation of the way images are used in the FPDF library.

Create another directory within your “/images” directory and call it “temp”. You will need to make this directory writable by the server, so either “chmod 777 temp” or use your FTP app to set the permissions. This is where gravatars will be downloaded and stored. If you forget to set the permissions on this folder, you will see a bunch of garbage text on the screen when you try and generate the badges (just a warning).

Finally, create a “/templates” directory in the root of your main folder. In this folder you can store badge page layout templates. For this example we will use a template for Avery Pin Style Name Badges 74549. If you need to use a different template, duplicate this file and make the modifications to the co-ordinates. I’d be happy to create a place to share layout templates if people let me know where to find them.

FPDF treats each PDF page as a canvas, where you set every item’s position using co-ordinates. The co-ordinate values represent millimeters allowing you to measure a normal sheet of paper to get badges positioning perfectly.

In your templates directory, create a new file called “avery74549.php” and add the following code:

// Add a page, but only on a multiple of 9 (as there are 8 badges per page)
if ( $counter == 1 || ( $counter % 9 == 1 ) ) {
	$pdf->AddPage('P', 'Letter');
	$counter = 1;

// Set the co-ordinates for all items in each of the badges
switch ( $counter ) {
	case 1:
		$background_x = 12.5;
		$background_y = 22;
		$avatar_x = 81;
		$avatar_y = 28;
		$text_x = 17.5;
		$text_y = 52;
	case 2:
		$background_x = 108.5;
		$background_y = 22;
		$avatar_x = 177;
		$avatar_y = 28;
		$text_x = 114;
		$text_y = 52;
	case 3:
		$background_x = 12.5;
		$background_y = 83;
		$avatar_x = 81;
		$avatar_y = 88;
		$text_x = 17.5;
		$text_y = 113;
	case 4:
		$background_x = 108.5;
		$background_y = 83;
		$avatar_x = 177;
		$avatar_y = 88;
		$text_x = 114;
		$text_y = 113;
	case 5:
		$background_x = 12.5;
		$background_y = 144;
		$avatar_x = 81;
		$avatar_y = 150;
		$text_x = 17.5;
		$text_y = 174;			
	case 6:
		$background_x = 108.5;
		$background_y = 144;
		$avatar_x = 177;
		$avatar_y = 150;
		$text_x = 114;
		$text_y = 174;			
	case 7:
		$background_x = 12.5;
		$background_y = 205;
		$avatar_x = 81;
		$avatar_y = 211;
		$text_x = 17.5;
		$text_y = 235;			
	case 8:
		$background_x = 108.5;
		$background_y = 205;
		$avatar_x = 177;
		$avatar_y = 211;
		$text_x = 114;
		$text_y = 235;			

Step 5: The Beef

Now we have the environment set up, we can move on to the actual generation of the badges.

Open up your “generate.php” file, as this is the file we are going to edit from now on. The first step is to instantiate the FPDF class and store it in the object variable “$pdf”. Add the following below the existing code:

// Set up the new PDF object
$pdf = new FPDF();

// Set the text color to white.

// Remove page margins.
$pdf->SetMargins(0, 0);

// Disable auto page breaks.

Now we need to retrieve attendee information from somewhere, and load that into an array. You could query a database to retrieve this information, or you could hard code it into the file. You will need the attendees’ first name, last name, email address and optionally their blog URL.

For the sake of this how-to, we will hard code a couple of attendees into an array to use.

// Grab the attendee list
$attendees = array(
   array( 'first_name' => 'John', 'last_name' => 'Smith', 'email' => '', 'blog' => '' ),
   array( 'first_name' => 'Jane', 'last_name' => 'Doe', 'email' => '', 'blog' => '' ),
   array( 'first_name' => 'Kris', 'last_name' => 'Masters', 'email' => '', 'blog' => '' )

Now we have the attendee array set up, we can loop through each one and write each value to a badge in the PDF file:

// Loop through each attendee and create a badge for them
for ( $i = 0; $i < count($attendees); $i++ ) {
		// Grab the template file that will be used for the badge page layout

		// Download and store the gravatar for use, FPDF does not support gravatar formatted image links
		$grav_file_raw = 'images/temp/' . $attendees&#91;$i&#93;&#91;'first_name'&#93; . '-' . rand();
		$grav_data = get_file_by_curl( '' . md5($attendees&#91;$i&#93;&#91;'email'&#93;) . '?s=512&default=identicon', $grav_file_raw );
		// Check if the image is a png, if it is, convert it, otherwise add a JPG extension to the raw filename
		if ( !$grav_file = pngtojpg($grav_file_raw) ) {
			$grav_file_extension = get_image_extension($grav_file_raw);
			$grav_file = $grav_file_raw . $grav_file_extension;
			rename( $grav_file_raw, $grav_file );

		// Add the background image for the badge to the page
		$pdf->image('images/back.jpg', $background_x, $background_y, 96, 61);
		$pdf->image($grav_file, $avatar_x, $avatar_y, 21, 21);

		// Set the co-ordinates, font, and text for the first name
		$pdf->SetXY($text_x, $text_y);
		$pdf->MultiCell(86, 13,ucwords(stripslashes($attendees[$i]['first_name'])),0,'R');

		// Set the co-ordinates, font, and text for the last name
		$pdf->SetXY($text_x, $text_y + 11);
		$pdf->MultiCell(86, 13,stripslashes(ucwords($attendees[$i]['last_name'])),0,'R');

		// Remove http:// from blog URL's and also remove ending slashes
		$attendees[$i]['blog'] = str_replace('http://', '', $attendees[$i]['blog']);
		if ( $attendees[$i]['blog'][strlen($attendees[$i]['blog']) - 1] == '/' )
			$attendees[$i]['blog'][strlen($attendees[$i]['blog']) - 1] = '';

		// Set the co-ordinates, font, and text for the blog url
		$pdf->SetXY($text_x, $text_y + 17);
		$pdf->MultiCell(86, 13,$attendees[$i]['blog'],0,'L');

Finally once we have looped through all attendees and added a badge for each, we can output the PDF file to the browser so it can be saved or printed:

// Output the PDF file to the browser

That’s it! You can download the final source files here. Good luck creating gravatar enabled badges. Please ask any questions in the comments, or post links to show off your own conference badges.

Prepare, Don’t Escape! — June 25, 2008

Prepare, Don’t Escape!

Not a bad title for a post about code, so if you’re reading this expecting something non-geeky then look away now! Ready?

Since WordPress 2.5 a new $wpdb function has been included called ‘prepare’. I’ve been using the new function extensively throughout BuddyPress. As it’s so new, there are still quite a few plugin developers who are not aware of its existence.

So what does ‘$wpdb->prepare()’ do exactly? Simply put, it replaces the old ‘$wpdb->escape()’ function for escaping variables passed into an SQL statement. Escaping variables is great for preventing SQL injection attacks and keeping the bad dudes out.

With $wpdb->escape you would usually do something like this:

$field1 = $wpdb-&amp;gt;escape("Andy Peatling");
$field2 = $wpdb-&amp;gt;escape("It's like that, and that's the way it is.");
$id = $wpdb-&amp;gt;escape($_POST['id']);

$wpdb-&amp;gt;query( "INSERT INTO $wpdb-&amp;gt;sometable( id, field1, field2 ) VALUES ( $id, '$field1', '$field2' ) ");

This works great, but you still have to deal with remembering to put single quotes around strings, and calling the function for every single variable you want to pass into the query.

The $wpdb->prepare() method simplifies things further, generally making your life a lot easier by combing everything into one call:

$field1 = "Andy Peatling";
$field2 = "It's like that, and that's the way it is.";

$wpdb-&amp;gt;query( $wpdb-&amp;gt;prepare( "INSERT INTO $wpdb-&amp;gt;sometable( id, field1, field2 ) VALUES ( %d, %s, %s )", $_POST['id'], $field1, $field2 ) );

Notice that you no longer have to worry about quoting strings. Instead of including the actual variable name within the query you simply place a ‘%d’ for integers and ‘%s’ for strings. Then for the second parameter onwards you pass the variables in the same order they are in the query.

The new WordPress coding standards page touches briefly on the new prepare function. The WordPress Codex however still includes references to the escape method which I will be helping to update. has been updated to include references to the new prepare() method.

Leave any questions in the comments, I’d be happy to help.

A WordPress MU Social Network Platform — September 7, 2007

A WordPress MU Social Network Platform

When I wrote about turning WordPress MU into a social networking platform a little while back I never could have imagined the amount of interest it would generate.

I’ve heard from a lot of people. Some who are looking to build a new site, some running a site on old software, and others looking for extended WordPress MU functionality. It seems that people liked what they saw with ChickSpeak, and wondered if I would be offering the solution to the public.

BuddyPress is my offering, and although it is not close completion just yet, I wanted to let people into the development process with a dedicated blog.

Head on over and let me know your thoughts. A WordPress MU Based Social Network — July 1, 2007 A WordPress MU Based Social Network

WordPress MU (WPMU) is basically the multi-user version of WordPress, the popular blog/cms tool. The aim of WPMU is to allow for one installation to spawn multiple WordPress blog instances. Basically, you can install WPMU on your server and run as many individual WordPress instances as your box can handle.

WordPress MU has the basics of a social network right out of the box – individual member blogs, member profiles and the ability to scale well.

Don’t Hack – Just Plug

WordPress also has an excellent plugin API, as well as a whole host of quality pre-built plugins ready to download and activate. The key here is that I didn’t have to hack the core – I could just achieve the additional functionality needed by building dedicated plugins.

Plugins were built and used for private messaging, advanced profile management, online polls, photo management, multi-blog search and user credential management.

Not Blogs, But Member Home Pages

Member Home Page on ChickSpeak

The crucial part to the whole project was morphing WordPress MU to stop it from generating new blog instances and instead generating new member home pages.

A member home page includes a users own personal profile front and center, their own personal “journal” as a feature of their home page, as well as private messaging functionality.

To achieve the desired change it was down to making a new WordPress theme. The theme would have exactly the same look and feel as the core site – making it look like the new member home page was still part of the core site itself.

Within the theme, I removed the code that usually makes the blog posts front and center, and changed it to the code that outputs the users profile. The blog code was moved to the sidebar so it could still be accessed as the members “journal” feature.

Finally, the code to output the users new private messages was added to the sidebar, as well as some code to output polls, photos and other smaller bits and bobs.

A nice feature of WordPress MU is it places member pages on a subdomain, so any members home page can be found at A nice touch, as it’s then easy to remember the to link to your profile.

Adding Some BBPress Magic

BBPress Forums on ChickSpeak

The project also called for a fully featured discussion forum. The forum needed to work seamlessly with the site, using the same login credentials and the same look and feel. Another project called BBPress fit the bill perfectly. BBPress is a no-frills forum/bulletin board application built by the same guys (Automattic) as WordPress. It has the same style, plugin architecture and most importantly can share the credentials data and cookie information. Perfect.

Limiting Credentials

The final step was to limit the administration functionality that a member has on their own blog. This stops them from signing up new users, deleting content they shouldn’t be, or changing the theme of their member page. I created a simple plugin that disabled the menus for these settings in the WordPress admin interface. The pages could only be accessed by site-wide administrators if needed.

I’ve only really glazed on what I did with WordPress MU to turn it into a fully fledged social network engine – but you get the overall idea. I’d be happy to answer anyones specific questions if you have them.

ChickSpeak is up and running over at Feel free to take a look when you get a chance, I’d welcome any feedback. You can also click the image thumbnails in the article to get full screenshots.

Is Certain Bulletproofing Becoming Unnecessary? — April 11, 2007

Is Certain Bulletproofing Becoming Unnecessary?

Personally, since reading the book and even before that, I’ve made programming flexible and scalable (aka bulletproof) designs one of my top priorities.

The only trouble is I find it takes a whole lot longer to program something to be bulletproof, than it does just to whip it up the old fashioned way. It’s absolutely worth it, but it’s a lot more fiddling with images and extra markup in any case, which takes time.

Now, the aim for many of these bulletproof techniques is to keep your site design together when the browsers text is resized. Take a look at Dan’s site and resize the text in Firefox as an example of a great bulletproof design (he is the author after all!).

If you have a copy of IE7 installed, try bringing up Dan’s site and resizing the text again in there. See the difference?

IE7 has taken on something called “page zoom” which basically resizes everything on the page in unison. The first time I saw this was in Opera, and it’s a really nice feature. So instead of the text on your page bursting at the design seams when it’s resized, all the containing boxes and graphics will also resize at the same time.

When Opera was the only browser using page zoom it didn’t really matter, as Opera only counts for a very small percentage of users. Now that IE7 is using page zoom, it becomes a very different matter. We may end up with 70-80% of web users with page zoom as their default behavior.

If Firefox chipped into that, and switched to page zoom in their next version, we’re looking at perhaps 95% of internet users with page zoom instead of simple text resizing.

If that becomes the case, then would it be right to say that it’s pointless to do the extra work to make your designs bulletproof for text resizing? I personally think so.

Maybe I’m getting ahead of myself a little, it’ll take some time before IE7 picks up and overtakes IE6 as the major player. Its numbers however are moving fast thanks to the Windows automatic updates feature (and the fact IE6 is a security train wreck). IE7’s page zoom is also not up to the standard of Opera’s just yet.

So for now at least, I’m continuing with the good practice of bulletproofing for text resizing. I’m sure however, that in the next year or so, the practice will become close to redundant. Then we can all relax knowing that our sites will look great at any size.

At least, until we start talking about resolution independence. 😉

Adobe Device Central — March 28, 2007

Adobe Device Central

Device Central Screen

Adobe Device Central looks cool, very cool. I’ve not tried it in the public beta of Photoshop, which I now read has a beta version of it included.

I’ve had a bunch of clients recently ask for handheld stylesheets and thankfully I’ve had a Windows Mobile device on hand to test them out. I’m about to sell it though, and even with an actual device, I’m still limiting myself to one platform.

Has anyone spent time using this tool? If so, how have you found it so far? It looks great, but who knows how it will actually work until I get a *final* copy of it.

Come to think of it, maybe this is just for flash mobile… I really hope not, but I suppose that would make sense.

%d bloggers like this: