Tutorial Details
- Program: WordPress
- Version: 3.0+
- Difficulty: Beginner
- Estimated Completion Time: 30 minutes
We’ve been talking a lot about “Best Practices” here on Wptuts lately. Today, we’ll cover some important best practices for creating a WordPress plugin. From security tips to namespacing tricks, follow these rules and you’ll do no wrong. Whether you’re a budding new plugin developer or a time-tested veteran, these simple rules and suggestions will make you a better developer (and the community will thank you for it!)
Rule 01: Have a Strategy
Yes, a strategy. Try this checklist:
- Is my plugin just for fun/demonstration purposes or for everyday use in the real world?
- Am I writing it to contribute to the community, to promote myself or to earn income?
- Can I afford the time to offer support to users?
- Have similar plugins already been written? Check the WordPress Plugin Repository.
These questions are important because they impact on how seriously you need to take issues such as coding standards, updates, security, support and documentation. Even if you’re just writing a plugin for your own use or for the use of your colleagues, you need to think hard about how you’re going to go about it so that you don’t make a rod for your own back.
Rule 02: Use Consistent and Clear Coding Standards
Which do you prefer, this?
function parsefile($imagedata,$file){
if(!in_array($imagedata['mime'], array('image/jpeg','image/png','image/gif'))){
$result['error']='Your image must be a jpeg, png or gif!';
}elseif(($file['size']>200000)){
$result['error']='Your image was '.$file['size'].' bytes! It must not exceed '.MAX_UPLOAD_SIZE.' bytes.';
}
return $result;
}
Or this?
/*
processes the uploaded image, checking against file type and file size
*/
function parse_file($image_data, $file){
if(!in_array($image_data['mime'], unserialize(TYPE_WHITELIST))){
$result['error'] = 'Your image must be a jpeg, png or gif!';
}elseif(($file['size'] > MAX_UPLOAD_SIZE)){
$result['error'] = 'Your image was ' . $file['size'] . ' bytes! It must not exceed ' . MAX_UPLOAD_SIZE . ' bytes.';
}
return $result;
}
Simple things like consistent spacing, indenting, informative variable naming and succinct comments are a good place to start. That’s the only difference in the examples above. WordPress has an excellent guide to coding standards. If you code to a standard your code will be easier to understand, edit and debug.
Use Namespacing
There are two ways to construct a WordPress plugin: as a bunch of functions or as a class. Keep in mind that the functions in your plugin get thrown into the global namespace with all the other non-namespaced functions, which means that if you have a function named plugin_init then it’s probably going to conflict with the same function written by someone else at some point. The obvious way to fix this issue is to prefix the function name with something unique. I like to use the first letters of my plugin name, so if I had a plugin called My Great Plugin, I would call the above function mgp_plugin_init, and the same for the rest of my functions.
But a better way is to create a class for your plugin, that way all functions will be namespaced under the name of the class and even better, you can now use short, common method (function) names.
class my_class{
function hello_world(){
return 'Hello World!';
}
function goodbye_world(){
return 'Goodbye World!';
}
}
Then you could access your class methods under the its own namespace:
$my_new_plugin = new my_class(); echo $my_new_plugin->hello_world(); echo $my_new_plugin->goodbye_world();
Rule 03: Take Security Seriously
Making your plugin secure is the single most important step to take, but many developers discount security or relegate it to the status of an afterthought. Don’t make that mistake.
Sanitize inputs, escape outputs
You should especially make yourself familiar with:
If you use a function such as wp_insert_post, WordPress will sanitize that data for you. Similarly, if you use the database methods $wpdb->insert or $wpdb->update, WordPress will sanitize the data. But if you choose to access the database more directly with something like $wpdb->get_result, then you should use wpdb->prepare to prevent sql injections of malicious code.
Instead of:
$admin_posts = $wpdb->get_results( "SELECT ID, post_title FROM $wpdb->posts WHERE post_status = 'publish' AND post_author = 1" );
You would use:
$admin_posts = $wpdb->get_results($wpdb->prepare( "SELECT ID, post_title FROM $wpdb->posts WHERE post_status = %s AND post_author = %d", 'publish', 1 ));
In the above example, %s is a placeholder for string input (publish) and %d is a placeholder for numeric input (1). You can use as many placeholders as you need.
Use Nonces for Form and URL Verification
It’s important to know that when a form or url is posted back to WordPress, that it was your WordPress site that actually generated it and not some third party or malicious agent. To take care of this aspect of security, we use nonces. A nonce is a number used once.
For a form, we generate a nonce field using wp_nonce_field that will be included in our form as a hidden field:
wp_nonce_field('my_nonce', 'my_nonce_submit');
Because it’s now a hidden field in our form, it’ll come back to us when the form is submitted. We can then check that the nonce is valid using wp_verify_nonce:
wp_verify_nonce($_POST['my_nonce_submit'], 'my_nonce') )
That will return true if the nonce verifies.
For a url (links in emails, browser urls), you can create a nonced url with wp_nonce_url:
$nonced_url = wp_nonce_url('http://my_site.com?action=register&id=123456', 'register_nonce');
That would create a url like this…
http://my_site.com?action=register&id=123456&_wpnonce=250d696dc6
…which you could send in a registration confirmation email. You would then check the incoming url for a nonce with the same id using the check_admin_referer function and proceed with verification if true.
if($_GET['action'] == 'register'){
if(check_admin_referer('register_nonce')){
if(verify_id($_GET['id'])){
echo 'Registration verified!';
}
}else{
echo 'Registration verification FAILED!';
}
}
Rule 04: Access Web Services Intelligently
The internet is full of web services providing us with everything from weather forecasts to stock quotes to the latest tweets from Twitter. The most efficient way for a plugin to access remote data is to use the HTTP API which will handle your request in the background, using the most efficient of the five possible remote methods that PHP exposes. It’s like a one-stop shop for webservice access.
This uses the wp_remote_get method (a wrapper function of the HTTP class) to get a page body:
$page_data = wp_remote_get('http://site.com/page');
if($page_data['response']['code'] == 200){
$body = $page_data['body'];
}
Same with wp_remote_post to login:
$args = array(
'login' => 'login_name',
'password' => 'my_password'
);
$response = wp_remote_post('http://site.com/login', $args);
Rule 05: Internationalization
This doesn’t have to be a big deal but is essential if you want to reach the widest audience possible. At a minimum all you need do is prepare your plugin with the _e() and __() functions and worry about the texdomain afterwards.
It’s all explained very well in this wp.tutsplus article by Tom McFarlin and here at the WordPress codex.
Rule 06: Load Only What You Need
When you go away overnight, you don’t take as much with you as you would if you were going on vacation for a month. So treat your plugin the same way: only load the stylesheets, javascript and other scripts that you need for that page or section of the site. At the very least, don’t load admin scripts on the frontend and vice-versa.
if(is_admin()){
//load my plugin stuff for the admin pages
}else{
//load my plugin stuff for the frontend
}
Rule 07: Tidy Up After Yourself
When you activate a plugin, you will see a deactivate link appear in the plugins admin page. But deactivating only stops the plugin from functioning. After deactivation, you then get a delete link. The delete link is the key to tidying up after yourself. It should really be called uninstall.
If you create a file named uninstall.php in the same directory as you plugin, the code in this file will be run when the user clicks delete.
if(defined('WP_UNINSTALL_PLUGIN') ){
//delete options, tables or anything else
}
The above code checks for the WP_UNINSTALL_PLUGIN constant which WordPress sets when you hit delete. Then you can proceed to delete any options or custom tables that your plugin created when it was activated.
Bonus Tips
Turn on debug
The WordPress debugger will find errors in your code that while they may not crash you plugin should still be corrected to make sure that you’re doing things correctly. So, turn on WordPress debug by placing this in your /wp-config.php:
define('WP_DEBUG', TRUE);
Study the WordPress function library
WordPress often has functions that will solve a programming task in one function that you may have written many lines of code to achieve. Check out the function library to make sure you’re not writing more code than you need to.
Get some peer review
Getting others to look at your code is a strong form of quality control. Other users will find faults that you haven’t noticed in your own testing. Don’t be afraid to post your code: everyone makes mistakes.
Don’t use deprecated functions!
WordPress is full of outdated functions that while still supported for current versions may not be in future releases. You may have used code from an old tutorial. Look it up in the WordPress codex to see if it is marked as deprecated. There will be a link to the newer function.
Use a good WordPress code forum
If you have a problem, ask others. There are plenty of forums for WordPress solutions. One of my favorites is WordPress Answers from the wonderful Stack Exchange network.
Take some pride in your work!
It’s easy to release a plugin with a rider that you take no responsibility for the effects of your code. Now, that’s a necessary given: you can’t be responsible for how your plugin will be used. But you can take a professional pride in how you go about your work. Always do your best. Your reputation will be the better for it.


Hehe Never tried writing the whole plugin myself. I always searched for similar exist plugin and hack them up. Thats make my life easier for medium level programmer like me. Hope oneday I got good enough to write one
thank you ,nice rules for Developer,must be read
Nice tips! In case you didn’t know, there’s actually a hook for when you deactivate your plugin, which works much the same as register_activation_hook and register_deactivation_hook:
register_uninstall_hook
Also, if you access any external APIs you might want to mention the Transient API that ships with WP and makes it very easy to save any retrieved data for a certain amount of time.
Yes, it’s also very important to differentiate between deactivation and uninstalling.
You don’t want to delete all the user’s custom options etc. for your plugin on deactivation, at least not without prompting. It could be very inconvenient if to temporarily deactivate a plugin and when you reactivate, all the options you carefully set are gone!
I’ve noticed some plugins have an option that allows users to indicate whether they want all options deleted on deactivation or not. That could be a good approach for some plugins.
I’m in the middle of developing a new plugin and these rules come bit late for me, but still, no time to waste … some of the I can already apply now … like “define(‘WP_DEBUG’, TRUE);”
Thanks for the cool tips guys!
It’s never too late to go back and do things the right way
Some great advice here, Ross, thanks!
Also, worth mentioning a post earlier this year from Mark Jaquith (lead core WordPress developer) on a few important things to keep in mind when developing WordPress plugins: http://markjaquith.wordpress.com/2011/06/07/how-to-write-a-plugin-that-ill-use/
If You are using class for Your functions as a library it should be a static class then, not an object.
All excellent points, Ross! Thank you for your contributions here
For your point six, you could add to only load resources (mainly JS) for widgets or short codes that are actually being presented on the page. It’s slightly tricky to do, but there are techniques to make that work. For example, we employed a technique for this in our free beCounted community plugin (widget) in case anybody could use a reference for that. We also have a free plugin coming out very soon that will uses the technique for a shortcode – our upcoming plugin is called beContacted.
I am only just starting to really look into WordPress and I am totally new to this area of design. I have been spending a lot of time reading articles from this site to help me get an idea on the the platform and give myself a head start to when I actually start to use it. Articles like this are brilliant for me because they give me a guide and let me know what I should be doing from the start so I work in the correct way. This article will be used as a constant reference for myself when it comes to plugins within WordPress. Great article and thank you.
nice article. it’s basic and useful.
thank you
Hello,
Thank you four nice writing. It will help me for my research on Recycle.
Thanks.