I often download plugins to look at the code hoping I’ll learn something from the developers methods and coding style. Often I find myself frustrated reading through poorly written plugins. It’s not that they’re bad developers, they just haven’t focused enough on alternative coding styles and refining how they go about programming their plugins. Here’s a quick step-by-step on how I write my WordPress Plugins hoping to influence other developers.
Start off by creating a php file containing the name of your plugin, eg, my-plugin.php. Add your standard plugin information to the top of your plugin file inside your php tags, these headers tell WordPress that this file is a plugin. So far your file should look something like the following from my IP Ban plugin:
<?php /* Plugin Name: IP Ban Plugin URI: http://w3prodigy.com/wordpress-plugins/ip-ban/ Description: Returns 'Page Not Found' 404 error message for IP's visiting your blog specified in the IP Ban option on the Discussion Options page. Author: Jay Fortner Author URI: http://w3prodigy.com Version: 0.1 Tags: anti-spam, ban, ip, plugin, privacy, security, spam License: GPL2 */
Start off your plugins php code by instantiating a new object, my IP Ban plugin has two objects, one object for the plugin and another object for the plugins options, I instantiate the options objects when my plugin object is called.
new IP_Ban;
class IP_Ban {
function IP_Ban()
{
$this->__construct();
} // function
function __construct()
{
new IP_Ban_Options;
# Place your add_actions and add_filters here
} // function
} // class
class IP_Ban_Options {
function IP_Ban_Options()
{
$this->__construct();
} // function
function __construct()
{
# Place your add_actions and add_filters here
} // function
} // class
Adding actions and filters inside of an object is a little different when it comes to the callback parameter. Instead of add_action( 'init', 'my_init' ); we supply an array to the second parameter stating the object to use followed by a function in that object add_action( 'init', array( &$this, 'init' );. By creating an object we can safely recreate function names already created by WordPress.
If I wanted my plugin object to hook into the init and admin_init actions, I would create these functions inside of my object.
class IP_Ban {
function IP_Ban()
{
$this->__construct();
} // function
function __construct()
{
new IP_Ban_Options;
add_action( 'admin_init', array( &$this, 'admin_init' ) );
add_action( 'init', array( &$this, 'init' ) );
} // function
function admin_init()
{
# perform your code here
} // function
function init()
{
# perform your code here
} // function
} // class
It’s as simple as that to create clean and safe plugins. If you also wanted to have both the init and admin_init perform the same action, you can create another function containing the code to be performed by both actions.
class IP_Ban {
function IP_Ban()
{
$this->__construct();
} // function
function __construct()
{
new IP_Ban_Options;
add_action( 'admin_init', array( &$this, 'admin_init' ) );
add_action( 'init', array( &$this, 'init' ) );
} // function
function admin_init()
{
$this->ban_check();
} // function
function init()
{
$this->ban_check();
} // function
function ban_check()
{
# perform your code here
} // function
} // class
Remember that options object we created at step 2? Let’s go ahead and hook into the admin_init action and call the add_settings_field and register_setting functions to create our options on an existing page. When using the add_settings_field function, I specify array( &$this, 'ip_ban' ); as my callback function, this means that in $this object, use the ip_ban method in that method we display the field information for that option. You should create your own methods.
class IP_Ban_Options {
function IP_Ban_Options()
{
$this->__construct();
} // function
function __construct()
{
add_action( 'admin_init', array( &$this, 'admin_init' ) );
} // function
function admin_init()
{
add_settings_field(
$id = 'ip_ban',
$title = "Banned IP's",
$callback = array( &$this, 'ip_ban' ),
$page = 'discussion'
);
register_setting( $option_group = 'discussion', $option_name = 'ip_ban' );
} // function
function ip_ban()
{
$value = get_option('ip_ban');
# echo your form fields here containing the value received from get_option
} // function
} // class
Now you can go off doing your thing. If you find yourself interested in developing your own coding style, I highly recommend the WordPress Coding Standards.
You can view the final product of my plugin by downloading IP Ban from the WordPress Plugin Directory
Jay. Thanks for posting this. I’ve looked all over for a class layout like this. I’m quite new to php and kept staring at the settings functions wondering how I would build a class around them. Great Stuff!
Thanks Phillip!
Phillip, this something similar that I’ve been looking all over for almost a week. I’ve been looking for a class for the settings API but can’t find one anywhere. However, I’m wondering if this code is fit for a class. Now I’m not versed in OOP but I know a bit. My thinking is why build a class if there is no data persistence needed? Also isn’t a class supposed to be trimmed down to abstract elements and then extended by new class objects with objects needed for the new class? I know I’m rambling here but it should be obvious I’m very confused about how to write a class for the settings api. I feel obsessed with it but have no starting point using that code. Any suggestions to feed my troubled mind? Thanks
WordPress plugins help extend the core code which is where the data persistence exists, I use the OOP approach because it provides a cleaner method of writing the code to extend upon. Often plugin developers use difficult naming conventions and a large assortment of writing styles which lead to inconsistencies in the code. Perhaps I titled the post wrong, regardless the take-away from this article should be the organization and consistency of programming styles as it makes a huge difference in how we are perceived as developers.
Jay. Sorry for calling you Phillip.
Thanks for this, Jay.
Two questions I have been unable to answer by scouring the web for a couple of days:
1. For an OOP plugin, how do I make a template tag available, that the user can use in their theme, and can optionally pass in a parameter?
I tried making a function in my plugin file OUTSIDE of the class definition, but it’s not working out.
2. Is there a way to pass parameters to a filter function? That is, I’d like my plugin to filter the_content, but it needs to know the post_id in order to do the filtering I want.
Sorry if this isn’t making sense, my head’s spinning at this point.
Thanks again for a great tutorial.
Paul
Paul -
Writing template tags using an OOP approach can be frustrating, some recommend writing a function outside of the namespace implementing the object. The best solution I’ve been able to find is to create my own custom action using WP’s add_action function, then in the template I can use do_action to call the references associated. So if I used add_action( ‘my_action’, array( &$this, ‘my_action’ ); to create the action in my namespace, I would use do_action( ‘my_action’ ); in the template.
To pass parameters to a filter function you would have to define those parameters in your apply_filters call as additional parameters. Or if you’re referring to filtering existing filters using add_filter then you can specify the number of accepted parameters in the fourth parameter.
The WordPress Codex can be of great help, but the source is always the best place for information.
Hello Jay,
I”m curious as to the PHP 4.0-ish code. Is there a particular reason for using this older OOP syntax ?
Hi Steve,
The original concept of this posting was to provide a basic understanding of how to use the OOP syntax while writing a WordPress plugin or functions.php file. I’ve updated it to demonstrate how to use this approach using PHP5 with PHP4 fall-back.
Aahh, ok, thanks for this example. I had a bookmark to info about using the array parameter for the add_action call but lost it somehow. Glad I found your example.
I had trouble when I went to add an admin_menu action in my admin_init function. I assumed that admin_init was the first thing that would fire, and so I would then register my admin_menu stuff within the admin_init function.
However, I came to realize that the admin_menu action fires before the admin_init action:
http://codex.wordpress.org/Plugin_API/Action_Reference#Actions_Run_During_an_Admin_Page_Request
Rather than add both the admin_menu and admin_init to my constructor, I simply changed your example code to:
add_action( 'admin_menu', array( &$this, 'admin_init' ) );
And then just combined everything that was going to go in my admin_menu function into the admin_init function.
Any potential pitfalls with this approach?
I believe you’ve misunderstood the approach. The second parameter of the add_action function simply states which function/method you’re loading for that hook, if you wanted to add a function to the admin_menu hook then you would create a method called admin_menu. [
add_action( 'admin_menu', array( &$this, 'admin_menu' );]Additionally, you can call the add_action function in your admin_init method if needed; but this is rarely needed and you may need to just look at the priorities in which your hooks load into the actions.
Hi Jay,
Thanks for the great article – it’s the best I have found with regard be developing WordPress plugins using OOP rather than procedural code.
I agree with your comment about consistency of programming styles. I see too much inconsistency in systems such as Joomla, WordPress, etc.
Hi Jay – thanks for informative article and help us all develop better plugins :>) … question, i’ve been working on a WP Multisite 3.1 Network MU plugin with a function that controls which admin menu pages are called … on one post i read to use admin_init in the action call and in other post i read admin_menu … both seem to work and wondering if you can weigh in which is best to use … below is my function and thanks in advance for any pointers you can share … cordially, chuck scott
/* Remove admin menu pages for everybody less than Administrator */
function cs_remove_admin_menu_pages () {
global $current_user;
get_currentuserinfo();
if (!current_user_can('activate_plugins')) {
remove_menu_page('upload.php'); // Media
remove_menu_page('link-manager.php'); // Links
remove_menu_page('plugins.php'); // Plugins
remove_menu_page('themes.php'); // Appearance
remove_menu_page('users.php'); // Users
remove_menu_page('tools.php'); // Tools
remove_menu_page('options-general.php'); // Settings
}
}
/* add_action( 'admin_init', 'cs_remove_admin_menu_pages' ); */
add_action( 'admin_menu', 'cs_remove_admin_menu_pages', 30 );
Hey Chuck,
It all comes down to the loading order. WordPress operates on a procedural structure, in your case admin_init comes before admin_menu, you typically need to apply your hooks after WordPress instantiates (the `wp` hook) and before the hook your fixing too.
In your code, admin_init comes first and admin_menu comes later, with admin_menu you’re setting a late priority meaning your function will run later than the standard hooks. In your case, I would use admin_init since you’re removing elements from the admin_menu action. This is clearly debatable.
Hi, this is a really helpful framework. Here is a dumb question: Can you talk a little about why we are sending WP the reference array from &$this rather than $this itself? I am still trying to learn how the callback system works so please excuse my ignorance.
Hey! Great write-up, thank you very much. Clears up a few WP-specific idiosyncrasies for me.