beachcoder.co.uk

21Apr/12Off

Using anonymous functions to build WordPress plugins

I work in WordPress a lot, so I invariably use plugins to add functionality. Sometimes, if you can't find exactly what you want, you have to roll your own.

Whenever I think "It'd be quick enough to knock up plugin to do that" I get the annoying feeling of having to rewrite the plugin starting point. Deciding on a unique namespace or function prefix, setting up the admin menus, hooking into content, the usual. It's not a huge job, but I hate writing things I've done before.

Yes, I could build a template with the common functions, but that'd still mean changing all th function names, admin menu hooks and so on. Still annoying.

So I put together a template that uses anonymous functions. All I have to do is change the name of the plugin in two places (in an $info array and the initial comment) and that's it. I have an admin hook, admin menu, options namespace with save & load - it's all good to go. Because it uses anonymous functions, there are no conflicts; I can copy & paste the file 10 times if I want, and each copy will activate as a separate plugin.

Here's the template:

/*
Plugin Name: Plugin base
Plugin URI: http://www.example.com/
Description: Default plugin
Version: 1.0
Author: David
Author URI: http://www.example.com/
*/

$plugin=function(){

	// Set some global details here

	// Plugin name
	$info=array('name'=>'Plugin base');

	// Options namespace (tied to filename)
	$info['ns']=md5(__FILE__);

	// Update options
	if($_POST[$info['ns']])update_option($info['ns'],$_POST[$info['ns']]);

	// Get latest options
	$info['opts']=get_option($info['ns']);

	// Define admin control panel
	$admin=function()use($info){
		echo $info['name'];
	};

	// Add to admin menu (must appear after function definition)
	add_options_page($info['name'],$info['name'],8,__FILE__,$admin);
};
if(function_exists('add_action'))add_action('admin_menu',$plugin);

$p contains all the internal functions. That's where the magic is; $p defines everything on the fly. If multiple plugins are created this way, they're executed one after the other. $p gets overwritten each time and there are no conflicts.

You can even define functions that don't conflict with anything by dropping them into an array:

$info['fn']['test_function']=function($string){
	return $string;
}

These will be available in the scope of the $p function and therefore available to all functions defined within. I won't lie - variable scope can get a bit messy, but as long as you're passing variables around you should be OK.

One disadvantage is that anonymous functions are only available in PHP 5.3. And I can't honestly argue that this is any better than using a class definition. Although I use this, it's partly because it was an interesting exercise to put together - I didn't write it for maintenance by anyone else :)