Menu

9 Tips for WordPress Plugin Development

In this article, I would like to share some of my tips for developing WordPress plugins.

My Background

I’ve developed more than 20 WordPress plugins. Some of them were for clients, some for free release at the WordPress Plugin Directory, others as joint ventures, or for sale on marketplaces such as CodeCanyon.

Plugins I’ve worked on have been installed on well over 50,000 sites. I’ve sold over 5,000 copies in the premium market.

Throughout this experience, I’ve learned many lessons, and would like to share them with you in this article.

1. Use the Right Hooks

Hooks are the bridge between your plugin and the larger ecosystem (WordPress). You can’t write plugins without hooks. You’d be surprised how many plugins misuse them though.

The first step to the proper use of hooks lies simply in taking the proper time to read through the official documentation of the Hooks Plugin API.

You want to end up with a deep understanding of which hook fires at which part of the sequence — from the page request, all the way to sending content to the browser. The Action Reference API shows us what order things typically fire in.

There’s a lot of hooks to choose from, and depending on what your plugin does, you might need to wire in many of them.

I always abide by the practice of sub-dividing functionality to be as relevantly-distributed across my hooks as possible. This is because, for plugin development, adopting a "just in time" (JIT) mentality by running code only when it’s needed is a good idea.

If you need to set up some global variables or register post types, regardless of what page is being loaded, that should probably be fired on init. You should not be preparing HTML nor doing any heavy-processing on init in most cases.

Any strenuous processing within the init hook will mean all front-end page loads, admin page loads, AJAX requests and such, will be subjected to the delays caused by these heavy processes. This isn’t ideal and should be avoided for better performance.

Update: Thanks for those in the comments for correcting me here. The proper hook for enqueueing scripts is 'wp_enqueue_scripts', I've updated the following example to use this cleaner form (best practice)

The following code block is a general example of how to conditionally enqueue scripts with the wp_enqueue_scripts hook. You’ll see I’m careful to feed only the required resources for each type of page. No admin stylesheets unless the user is loading one of the plugin admin pages. Likewise, no front-end stylesheets loaded for the backend interface.

<?php

#} Plugin Init
add_action('init', 'examplePlugin_init');
function examplePlugin_init(){
 
	global $examplePlugin_Settings;

	#} Retrieve settings (if not loaded)
	$settings = $examplePlugin_Settings->getAll();

	#} Catch any posted data here			

}

function examplePlugin_enqueueScripts(){

	#} Admin & Public (Global) Scripts (I usually make sure jQuery's lined up)
		wp_enqueue_script("jquery");

		#} Public-Global - JS & CSS
			wp_enqueue_script('examplepluginjs', plugins_url('/js/examplePlugin.min.js',__FILE__),array('jquery'));
			wp_enqueue_style('exampleplugincss', plugins_url('/css/examplePlugin.min.css',__FILE__) );
		
		#} Any specifically enabled elements
		if ($settings['showElement'] == 1) wp_enqueue_script('examplepluginextrajs', plugins_url('/js/examplePlugin.extraFeature.min.js',__FILE__), array('jquery'));

}
#} Add to hook
add_action( 'wp_enqueue_scripts', 'examplePlugin_enqueueScripts' );
 
function examplePlugin_enqueueAdminScripts(){

	#} Admin & Public (Global) Scripts (I usually make sure jQuery's lined up)
		wp_enqueue_script("jquery");
		
		#} Admin-Global - JS & CSS
			#} Try not to use these, unless specifically necessary, use the below method

		#} Admin only + specifically a plugin admin page
		if (examplePlugin_isAdminPage()) {

			#} Plugin-specific Admin styles
			wp_enqueue_style('examplepluginadmincss', 	plugins_url('/css/examplePlugin.admin.min.css',__FILE__) );
					
		}	

		#} Admin only + WordPress Edit Page specifically
		if (examplePlugin_is_edit_page()){

			#} Anything which is to load on the edit post/edit page, page
			#} For example shortcode inserter functionality

		} else {
		
			#} Anything which is to load on non-editor admin pages
		
		}

		#} Admin only + WordPress editor on page
		if (get_user_option('rich_editing') == 'true') {
			
			#} This is another way of targetting the WordPress Editor
			#} In this instance we use this to localize a script:
			wp_localize_script( 'examplepluginadminjs', 'exampleAJAX', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ))); 

		}

}
#} Add to hook
add_action( 'admin_enqueue_scripts', 'examplePlugin_enqueueAdminScripts' );

#} Example function for detecting if the requested page is an edit page
function examplePlugin_is_edit_page($new_edit = null){
 
 #} Global
 global $pagenow;
 
 #} Ensure we are in admin
 if (!is_admin()) return false;

 #} Detect edit page type
 if($new_edit == "edit") #} Edit page
  return in_array( $pagenow, array( 'post.php', ) );
 elseif($new_edit == "new") #} New Edit page
  return in_array( $pagenow, array( 'post-new.php' ) );
 else #} New or Edit page
  return in_array( $pagenow, array( 'post.php', 'post-new.php' ) );
}

#} Determines if this is our admin page
function examplePlugin_isAdminPage(){
	
	#} This is defined on init, and is a simple array of page slugs
	global $examplePlugin_slugs;

	#} Detect page
	if (isset($_GET['page'])) if (in_array($_GET['page'],$examplePlugin_slugs)) return true; 
	
	return false;
	
}

Beyond init, wp_enqueue_scripts and admin_enqueue_scripts, you will probably need to use a combination of the following Action hooks, which for most plugins will be enough to modularize the code logic without causing performance issues or maintainability challenges.

Note: Some themes will tend to drop wp_footer, (and sometimes even wp_head), in favor of their own versions. These WordPress themes are typically quickly-written or of the hack-y variety, but they are more common than you’d expect. So always test your plugin with as many themes as possible if your intention is to provide universal compatibility.

2. Take Advantage of WP Cron

Cron is a task-scheduling system originally built for UNIX which lets users execute commands at specified times.

Did you know WordPress core has a cron-like feature built in? This feature is aptly called wp cron.

If your plugin has a routine task that needs to be run, wp cron can be useful for firing off the task.

wp cron has its limitations though. For example, it’s dependent on web page requests, resulting in a delayed firing of a task if the WordPress site doesn’t have high-traffic. But these limitations are fixable.

For well-trafficked sites, and for those that are set up with auto-pinging, wp cron can be a pleasant way to create a cron-like setup.

Other lesser-known but useful WordPress features are:

3. Take Advantage of Auto Updates

Since WordPress 3.7, automatic updates have been available to WordPress plugin and theme developers.

This functionality is not enabled by default, and must be turned on by the user, or through your plugin. The latter is not advised because the user should explicitly opt-in for auto-updates. However, it’s good to highlight/remind the user about the auto-update option through your plugin’s admin interface.

If enabled, automatic updates are an excellent tool for continuous WordPress plugin development. It’s great for rolling out security patches, hot fixes, and version releases.

Plugins listed on WordPress.org benefit from automatic management of plugin versions through their repositories.

4. Consider Using the MVC Design Pattern

WordPress plugins benefit greatly when they are created using the MVC architecture. For maintainability, modularity, and many other reasons, there’s no better option.

MVC makes it really easy to be clean and organized with your plugin architecture.

There’s the odd occasion that I do still use what I refer to as a "wild code" architecture. It’s for tiny plugins, one-offs, and sometimes demo functionality.

Below you can see the two directory structures I typically use for plugins: the "wild" architecture version to the left, and MVC to the right. It will give you a better idea regarding the difference MVC can make:

In addition, all new plugins I write contain a documentation directory with docs composed in HTML, a languages directory, and Sass versions of the plugin’s stylesheets. Currently, I would say preprocessors are now a standard tool you’ll find among the toolsets of professional WP plugin developers.

Check out Ian Dunn’s presentation on implementing MVC for plugin development — it’s a great primer.

5. Name Plugin Files Uniquely

Don’t forget that your plugin will be installed in a "busy ecosystem", perhaps even at the same time as your competitors’ plugins.

Unique names for your files and variables are essential.

The easiest way to do this would be to prefix custom PHP variables, classes, functions, CSS selectors, and file names with your plugin’s name.

6. Test Your Plugins Thoroughly

The last part of any good software development cycle is polishing, prepping and testing the product for release.

Here are my suggestions for when you are getting ready to deploy the initial release of your plugin, or are preparing a version release:

  1. Debug your plugin with wp_debug enabled until everything is resolved.
  2. Test the plugin on a fresh WordPress install.
  3. Test the plugin using multiple WordPress themes.
  4. Consider testing the plugin on old WordPress versions and PHP versions that you suspect might affect the functionality of the plugin.
  5. Analyze and test your plugin with browser developer tools (DevTools for Chrome, Firebug for Firefox, etc.).
  6. Compress all front-end files (HTML, CSS, and images). Include non-minified versions of your stylesheets and HTML files so that the plugin user can perform custom modifications.
  7. Write good documentation. Documenter can be helpful with this process.

7. Allow Users to Customize the Plugin

There’s a dirty secret that your users are never going to tell you. They’re fumbling around behind the scenes with your plugin’s source code.

WordPress users, more than any other group of software customer I’ve dealt with, dig through code. Many plugin customers are also developers who buy your plugin to add the functionality it offers to their WordPress projects.

Any plugin that grows a large user-base typically designs with customizability in mind, or deals with the wrath of support tickets.

Rather than making plugin customization difficult and forcing customers to fumble around with the plugin’s source code, give your users options and APIs that allow them to tailor the plugin’s functionality to their needs.

Global settings should be set via the plugin’s admin interface. Single-instance settings, such as custom settings specifically for a WordPress post or page, can be accomplished by providing users with a custom shortcode API for your plugin.

I believe that your plugin users should, at the bare minimum, be able to do the following:

Other ways to empower your users:

Finally, don’t forget to give your plugin a "restore to default settings" feature. This "factory reset" feature is good to have for when something disastrous happens during customization.

8. Prioritize Plugin Performance

Performance should be a top priority when developing a plugin. Every component should be optimized with speed in mind.

In the end, your users are likely using many plugins, making each page load churn through handfuls of PHP files.

The leaner you can get your plugins, the better. Wherever possible, build in caching, especially in multi-instance environments.

Above all else: Test.

Test on several hosts, with several themes, and with other plugins. P3 Profiler is a superb tool that will help you optimize your plugin’s source code.

9. Put Effort into Branding the Plugin

This tip may not matter to you. Perhaps you’re releasing plugins just for fun. Maybe your main goal is to give back to the WordPress community.

Whether it be for fun or profit, I would argue that every plugin deserves at least a decent shot, even if there’s no money trading hands.

Why make the plugin if you don’t want it out in the hands of WP users?

There are tons of free plugins released to the community that take the time to craft a good visual brand identity.

Like any product, WordPress plugins are subject to market competition. To stand out in the bustling marketplace around WordPress, you will need to execute well across all types of job roles, including roles outside of development such as design, marketing, SEO, copywriting, and so forth.

It’s not enough to have a great plugin. No one will use it if no one knows about it.

To brand a plugin well is an art and science. To this end, I hire a designer to design a logo and a "look and feel" for all new plugins I release to the premium market.

Sometimes, if it’s a tiny thing, I’ll try and do it myself. This rarely works.

Good branding and a great plugin will carry you far.

Beyond that, building a successful WordPress plugin business is largely a game of idea-generation -> development -> marketing. And then optimizing that loop.

Here are the key lessons I’ve learned specific to plugin sales:

Conclusion

There are some painful challenges pushing a WordPress plugin to market. It can create support-ticket storms, raging refund-requests, and one-star-review woes. Using the practices above, I’ve managed to reduce a lot of these challenges, and am increasingly finding a win-win way of generating revenue from WordPress development.

Related Content

About the Author

Woody Hayday is a developer whose specialty includes WordPress development. He also runs EverClients, a lead service for freelancers, and is an advisor at EpicPlugins. You can find more about the author at WoodyHayday.com.

This was published on Jan 21, 2015

12 Comments

Interesting tips on WordPress plugin development. Is it compulsory to develop on MVC architecture? Can we use another architecture to develop WordPress plugin?

I am too much appreciated from your guides on WordPress plugin development. Most thanks to Woody Hayday for such good article.

Cathy Mayhue Jan 22 2015

Very nice article on a topic I knew little about and very eager to learn, master, so that once day a cool plugin developed by me is running on many word-press installations around the world.

govertz Jan 22 2015

Very usefull explanation of how and when to use the different hooks.
Thanks!

dimasmagadan Jan 23 2015

Looks like there are about 50,000 sites with a buggy code)
You should avoid using init hook to print styles.

http://codex.wordpress.org/Function_Reference/wp_enqueue_script#Notes
https://core.trac.wordpress.org/ticket/11526

Woody Hayday Jan 27 2015

@ Manash – There’s no particular rule for WordPress plugins, we can write them as we feel best, provided they hook into WordPress in the correct ways (as above)

@ Ankit, Cathy, govertz – Thanks for reading

@ Dimas, From your second link:

“It turns out they use wp_enqueue_script() and wp_register_script() functions not hooked to init action as recommended by Codex, but instead right in the plugin body.”

… is that not what I’ve done above?

Anh Tran Jan 29 2015

I like this post, especially the last advice. Very true!

A small thing I think should be fixed is enqueue scripts should not be done with init hook. There’s a hook wp_enqueue_scripts for that purpose.

Thanks for the advice Woody. I considered looking into developing plugins but I think I will stick to web design!

@ Anh, thanks :)

I think this comes down to a slight difference in form. The code here does work and hasn’t proven to cause any issues, though I agree for better form it should be enqueueing via the appropriate hooks.

I’ll update the post to use the best practice hook (wp_enqueue_scripts). This is why I’d call myself a hacker not a programmer… :)

@ Chris, no worries! It’s not for everyone :)

Awesome tips! Love the auto updates. Also the branding, yoast is one of the best at that, those goofy little cartoons!

Great read, coming back for more!

Very Usefull Post, Thanks for explanation

This comment section is closed. Please contact us if you have important new information about this post.

Partners