7 Simple Rules: WordPress Plugin Development Best Practices

7 Simple Rules: WordPress Plugin Development Best Practices

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.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.exploderswatergun.com Exploders

    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 :D

  • http://www.bestrapidsharesearch.com charlies

    thank you ,nice rules for Developer,must be read

  • http://shabushabu.eu Boris

    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.

    • http://wp.envato.com/ Japh

      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.

  • http://www.kreativtheme.com Kreativ Theme

    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!

    • http://wp.envato.com/ Japh

      It’s never too late to go back and do things the right way ;)

  • http://wp.envato.com/ Japh

    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/

  • http://lowgravity.pl Kamil Grzegorczyk

    If You are using class for Your functions as a library it should be a static class then, not an object.

  • http://www.beAutomated.com/ Sean Conklin

    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.

  • Pingback: A Free wordpress newsletter » WordPress News, Tutorials & Resources Roundup No.9

  • http://www.tristarwebdesign.co.uk/ Paul Weston

    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.

  • Pingback: Plugin Development Guidelines - Jean Galea | Web Designer and Developer in Malta | WordPress Consultant

  • http://webtasarimsitesi.com/wordpress/ wordpress web tasarim

    nice article. it’s basic and useful.

    thank you

  • David Wood fin

    Hello,
    Thank you four nice writing. It will help me for my research on Recycle.
    Thanks.

  • Pingback: WordPress Plugins and Usability – a Match Made in Hell?

  • Pingback: wp-coder.net » WordPress Plugins and Usability – a Match Made in Hell?

  • http://www.kelleherwebdesign.com Dharma Kelleher

    In some of my plugins, I have sections of HTML. My question is whether it’s okay to use HTML5 tags such as and .

    And how necessary is it to end standalone tags (such as input and img) with ” />”?

    Are there a lot of people still using HTML4 or XHTML 1.0 themes?

    • http://www.kelleherwebdesign.com/ Dharma Kelleher

      Oops, I forgot to use the pre tags on my comment above. I meant to say is it okay to use HTML5 tags such as section and article.

  • Pingback: Get a WordPress Job: Complete Your Checklist Below

  • Pingback: Landing a WordPress Job | iwebspider design and consulting

  • Pingback: How to do damn near anything with WordPress – Stephanie Leary

  • opo]op

    jkhjkhjkh

  • opo]op

    hjghjgjhgjh

    • opo]op

      klkjhlh

  • http://www.facebook.com/mittul.chauhan Mittul Chauhan

    so informative

  • http://www.facebook.com/pengkong.choy Choy Peng Kong

    excellent post, very helpful. i like the final part about taking pride our code.