President of WebFX. Bill has over 25 years of experience in the Internet marketing industry specializing in SEO, UX, information architecture, marketing automation and more. William's background in scientific computing and education from Shippensburg and MIT provided the foundation for MarketingCloudFX and other key research and development projects at WebFX.

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.

Retrieve settings (depending on the user type and the page requested)

Catch sent data

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.

admin_menu

admin_notices

wp_head

wp_footer

wp_ajax_[yourFunction]

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:

Debug your plugin with wp_debug enabled until everything is resolved. Test the plugin on a fresh WordPress install. Test the plugin using multiple WordPress themes. Consider testing the plugin on old WordPress versions and PHP versions that you suspect might affect the functionality of the plugin. Analyze and test your plugin with browser developer tools (DevTools for Chrome, Firebug for Firefox, etc.). 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. 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:

Change styles such as colors, icons, borders, fonts, backgrounds, etc. Consider creating multiple plugin themes (dark, light, etc.).

Enable/disable optional third-party dependencies (e.g. Google Analytics, Facebook API, etc.)

Enable/disable certain features of the plugin

Change the front-facing text labels (such as the labels used to describe UI buttons and input fields)

Override the plugin’s default CSS through an admin interface

Other ways to empower your users:

Provide preprocessor versions of your stylesheets. Users who prefer to customize the plugin’s look-and-feel using Less, Sass, or another CSS preprocessor will thank you.

Have a good HTML structure. Often users restyle the plugin’s theme with CSS placed in their WordPress theme’s styles.css . Make it easy for them to select specific elements of the plugin by having a good HTML architecture with elements that have intuitive class and id names.

. Make it easy for them to select specific elements of the plugin by having a good HTML architecture with elements that have intuitive and names. Explain how to modify plugin settings via documentation.

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:

Each plugin should add just one amazing feature rather than ten mediocre ones. Keep it simple.

Price should be based on the amount of value the plugin can add to the customer.

Great customer service is hugely important.

Build an off-marketplace business website (don’t rely on your marketplace profiles).

Don’t fight competitors. Focus on creating a great product people want to use.

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