[display-posts post_type="content" id="3672" include_content=true include_title=false wrapper="div" wrapper_class=""]

Introduction to Plugin Development

Welcome to the Plugin Developer Handbook. Whether you’re writing your first plugin or your fiftieth, we hope this resource helps you write the best plugin possible.

The Plugin Developer Handbook covers a variety of topics — everything from what should be in the plugin header, to security best practices, to tools you can use to build your plugin. It’s also a work in progress — if you find something missing or incomplete, please edit and make it better.

There are three major components to WordPress:

  • core
  • themes
  • plugins

This handbook is about plugins and how they interact with WordPress. It will help you understand how they work and how to create your own.

Why We Make Plugins #

If there’s one cardinal rule in WordPress development, it’s this: Don’t touch WordPress core. This means that you don’t edit core WordPress files to add functionality to your site. This is because, when WordPress updates to a new version, it overwrites the local files. Any functionality you want to add should be added through plugins using approved WordPress APIs.

WordPress plugins can be as simple or as complicated as you need them to be, depending on what you want to do. The simplest plugin is a single PHP file. The Hello Dolly plugin is an example of such a plugin. The plugin PHP file just needs a Plugin Header, a couple of PHP functions, and some hooks to attach your functions to.

Plugins allow you to greatly extend the functionality of WordPress without touching WordPress core itself.

 
[display-posts post_type="content" id="3672" include_content=true include_title=false wrapper="div" wrapper_class=""]

What is a Plugin?

Plugins are packages of code that extend the core functionality of WordPress. WordPress plugins are made up of PHP code and other assets that make the plugin useful. These include, but are not limited to images, CSS, and Javascript.

By making your own plugin you are building additional functionality on top of what WordPress already offers.  For example, you could write a plugin that allows you to show links to the 10 most recent posts on your site.

Or, using WordPress’ custom post types, you could write a plugin that creates a full-featured support ticketing system with email notifications, custom ticket statuses, and a client-facing portal. The possibilities are endless!

Most WordPress plugins are comprised of many files, but a plugin really only needs one main file with a specifically formatted DocBlock in the header.

Hello Dolly, one of the first plugins, is only 82 lines long. Hello Dolly shows lyrics from the famous song in the WordPress Dashboard. Some CSS is used in the PHP file to control how the lyric is styled.

As a WordPress.org plugin author, you have an amazing opportunity to have your plugin installed, tinkered with, and loved by millions of WordPress users. All you need to do is turn your great idea into code. We are here to help you with that.

 
[display-posts post_type="content" id="3672" include_content=true include_title=false wrapper="div" wrapper_class=""]

Introduction to Plugin Development

Welcome to the Plugin Developer Handbook. Whether you’re writing your first plugin or your fiftieth, we hope this resource helps you write the best plugin possible.

The Plugin Developer Handbook covers a variety of topics — everything from what should be in the plugin header, to security best practices, to tools you can use to build your plugin. It’s also a work in progress — if you find something missing or incomplete, please edit and make it better.

There are three major components to WordPress:

  • core
  • themes
  • plugins

This handbook is about plugins and how they interact with WordPress. It will help you understand how they work and how to create your own.

Why We Make Plugins #

If there’s one cardinal rule in WordPress development, it’s this: Don’t touch WordPress core. This means that you don’t edit core WordPress files to add functionality to your site. This is because, when WordPress updates to a new version, it overwrites the local files. Any functionality you want to add should be added through plugins using approved WordPress APIs.

WordPress plugins can be as simple or as complicated as you need them to be, depending on what you want to do. The simplest plugin is a single PHP file. The Hello Dolly plugin is an example of such a plugin. The plugin PHP file just needs a Plugin Header, a couple of PHP functions, and some hooks to attach your functions to.

Plugins allow you to greatly extend the functionality of WordPress without touching WordPress core itself.

 
[display-posts post_type="content" id="3672" include_content=true include_title=false wrapper="div" wrapper_class=""]

What is a Plugin?

Plugins are packages of code that extend the core functionality of WordPress. WordPress plugins are made up of PHP code and other assets that make the plugin useful. These include, but are not limited to images, CSS, and Javascript.

By making your own plugin you are building additional functionality on top of what WordPress already offers.  For example, you could write a plugin that allows you to show links to the 10 most recent posts on your site.

Or, using WordPress’ custom post types, you could write a plugin that creates a full-featured support ticketing system with email notifications, custom ticket statuses, and a client-facing portal. The possibilities are endless!

Most WordPress plugins are comprised of many files, but a plugin really only needs one main file with a specifically formatted DocBlock in the header.

Hello Dolly, one of the first plugins, is only 82 lines long. Hello Dolly shows lyrics from the famous song in the WordPress Dashboard. Some CSS is used in the PHP file to control how the lyric is styled.

As a WordPress.org plugin author, you have an amazing opportunity to have your plugin installed, tinkered with, and loved by millions of WordPress users. All you need to do is turn your great idea into code. We are here to help you with that.

 
[display-posts post_type="content" id="3672" include_content=true include_title=false wrapper="div" wrapper_class=""]

Plugin Basics

Getting Started #

In the example above, ‘vi’ is the editor. Use the editor that is comfortable for you.

Now that you’re editing your new plugin, you need a name for it. The lines below are all you need for WordPress to recognize your plugin.

1
2
3
4
/*
Plugin Name: Handbook Example
*/

After you save the file, you should be able to see your plugin listed in your WordPress site. Log in to your WordPress site, and click Plugin on the left nav of your WordPress Admin. You should now see your new plugin!

Sometimes a plugin you create is just for your site. Usually though, you’ll want to share your new plugin with the rest of the WordPress community. As part of the standard Plugin Header, you specify a license. This lets the user know how they can use your code. To maintain compatibility with WordPress core, it is recommended that you pick a license that works with GNU General Public License (GPLv2+).

There are more values you can add to your Plugin Header which will help its display in your WordPress Admin. If you’re planning on submitting to WordPress.org though, you’ll need to follow the WordPress Plugin Header Requirements.

Top ↑

Hooks: Actions and Filters #

There are hooks sprinkled throughout WordPress core. WordPress hooks allow you to tap into WordPress at specific points to change how WordPress behaves without editing any core files.

There are two types of hooks within WordPress: actions and filters. Actions allow you to add or change WordPress functionality, while filters allow you to filter, or change, content as it is loaded.

Hooks are not just for plugin developers; hooks are used extensively to provide default functionality by WordPress core itself. Other hooks are unused place holders that are simply available for you to tap into when you need to alter how WordPress works. This is what makes WordPress so flexible.

Two of the hooks you’ll need when creating a plugin are the register_activation_hook() and the register_uninstall_hook() hooks. The activation hook runs when you activate a plugin. You would use this to provide a function to set up your plugin — for example, creating some default settings in the wp_options table. The uninstall hook is used to clean up after your plugin. This runs after the deactivation hook, and deletes the plugin from the user’s WordPress installation.

Additionally, you can add hooks throughout your plugin codebase with do_action, which will enable developers to extend your plugin by passing functions through your hooks.

Adding functions to hooks isn’t the only thing you can do. You can also use remove_action to remove a function that was defined earlier. For example, if your plugin is an add-on to another plugin, you can use remove_action with the same function callback that was added by the previous plugin with add_action. The priority of actions is important in these situations, as remove_action would need to run after the initial add_action.

You should be careful when removing an action from a hook, as well as when altering priorities, because it can be difficult to see how these changes will affect other interactions with the same hook. We highly recommend testing frequently.

You can learn more about creating hooks and interacting with them in the Hooks & Filters section of this handbook.

Top ↑

Use WordPress APIs #

Did you know that WordPress provides a number of Application Programming Interfaces (APIs)? These APIs can greatly simplify the code you need to write in your plugins. You don’t want to reinvent the wheel—especially when so many people have done a lot of the work and testing for you. The most common one is the Options API, which makes it easy to store data in the database for your plugin. If you’re thinking of using cURL in your plugin, the HTTP_API might be of interest to you. Since we’re talking about plugins, you’ll want to study the Plugin API. It has a variety of functions that will assist you in developing plugins.

Top ↑

How WordPress Loads Plugins #

When WordPress loads the list of installed plugins, it searches through the plugins folder and sub-folders to find PHP files with plugin headers.  If your entire plugin is just one file like Hello Dolly, it could be located directly in the plugins folder, but more commonly, plugin files will reside in their own folder, named after the plugin.

 
[display-posts post_type="content" id="3672" include_content=true include_title=false wrapper="div" wrapper_class=""]

Header Requirements

As described in Getting Started, the header section of the plugin is one of the primary components that allows WordPress to recognize a file as a plugin.

At a minimum, a header can contain just a Plugin Name, but several pieces can – and usually should – be included:

  • Plugin Name: The name of your plugin, as displayed in the Plugins list in the WordPress Admin.
  • Plugin URI: The home page of the plugin, which might be on WordPress.org or on your own website.
  • Description: A short description of the plugin, as displayed in the Plugins section in the WordPress Admin. Keep this description to fewer than 140 characters.
  • Version: The current version number of the plugin, such as 1.0 or 1.0.3.
  • Author: The name of the plugin author. More than one author may be listed.
  • Author URI: The author’s website or profile on another website, such as WordPress.org.
  • License: The short name (slug) of the plugin’s license, e.g. GPL2. More information about licensing can be found in the WordPress.org guidelines.
  • License URI: A link to the license, e.g. https://www.gnu.org/licenses/gpl-2.0.html.
  • Text Domain: The gettext text domain of the plugin. More information can be found in the How to Internationalize your Plugin Text Domain section.
  • Domain Path: The domain path is used so that WordPress knows where to find the translations. More information can be found in the How to Internationalize your Plugin Domain Path section.

A valid header might look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
Plugin Name: My Toolset
Description: This describes my plugin in a short sentence
Version: 1.5
Author: John Smith
License: GPL2
Domain Path: /languages
Text Domain: my-toolset
*/

The minimum requirement for a plugin header looks like this:

1
2
3
4
/*
Plugin Name: My Toolset
*/
 
[display-posts post_type="content" id="3672" include_content=true include_title=false wrapper="div" wrapper_class=""]

Including a Software License

Most WordPress plugins are released under the GPL, which is the same license that WordPress itself uses. However, there are other options available. It is always best to clearly indicate the license your plugin uses.

In the Header Requirements section, we briefly mentioned how you can indicate your plugin’s license within the plugin header. Another common, and encouraged, practice is to place a license block near the top of your main plugin file (the same one that has the plugin header).

This license block usually looks something like this:

1
2
3
4
5
6
7
8
9
10
11
12
{Plugin Name} is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
any later version.
 
{Plugin Name} is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with {Plugin Name}. If not, see {URI to Plugin License}.

When combined with the plugin header, you have:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
Plugin Name: Plugin Name
Description: This describes my plugin in a short sentence
Version: 1.5
Author: John Smith
License: GPL2
 
{Plugin Name} is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
any later version.
 
{Plugin Name} is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with {Plugin Name}. If not, see {License URI}.
*/
 
[display-posts post_type="content" id="3672" include_content=true include_title=false wrapper="div" wrapper_class=""]

Activation / Deactivation Hooks

Activation and deactivation hooks provide ways to perform actions when plugins are activated or deactivated.

Plugins can run an installation routine when they are activated in order to add rewrite rules, add custom database tables, or set default option values. The deactivation hook is sometimes confused with the uninstall hook. The deactivation hook is best used to clear temporary data such as caches and temp directories.

To set up an activation hook, use the register_activation_hook() function:

1
register_activation_hook( __FILE__, 'pluginprefix_function_to_run' );

To set up a deactivation hook, use the similar register_deactivation_hook() function:

1
register_deactivation_hook( __FILE__, 'pluginprefix_function_to_run' );

The first parameter in each of these functions refers to your main plugin file, which is the file in which you have placed the plugin headers. Usually these two functions will be triggered from within the main plugin file; however, if the functions are placed in any other file, you must update the first parameter to correctly point to the main file.

One of the most common uses for an activation hook is to refresh WordPress permalinks when a plugin registers a custom post type. This gets rid of the nasty 404 errors. Let’s look at an example of how to do this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function pluginprefix_setup_post_type() {
 
    // Register our "book" custom post type
    register_post_type( 'book', array( 'public' => 'true' ) );
 
}
add_action( 'init', 'pluginprefix_setup_post_type' );
 
function pluginprefix_install() {
 
    // Trigger our function that registers the custom post type
    pluginprefix_setup_post_types();
 
    // Clear the permalinks after the post type has been registered
    flush_rewrite_rules();
 
}
register_activation_hook( __FILE__, 'pluginprefix_install' );

If you are unfamiliar with registering custom post types, don’t worry – this will be covered later. This example is used simply because it’s very commonplace.

Using the example from above, the following is how to reverse this process and deactivate a plugin:

1
2
3
4
5
6
7
8
9
function pluginprefix_deactivation() {
 
    // Our post type will be automatically removed, so no need to unregister it
 
    // Clear the permalinks to remove our post type's rules
    flush_rewrite_rules();
 
}
register_deactivation_hook( __FILE__, 'pluginprefix_deactivation' );

For further information regarding activation and deactivation hooks, here are some excellent resources:

 
[display-posts post_type="content" id="3672" include_content=true include_title=false wrapper="div" wrapper_class=""]

Uninstall Methods

Your plugin may need to do some clean-up when it is uninstalled from a site. A plugin is considered uninstalled if a user has deactivated the plugin, and then clicks the delete link.

When your plugin is uninstalled, you’ll want to clear out any rewrite rules added by the plugin, options and/or settings specific to to the plugin, or other database values that need to be removed. Less experienced developers sometimes make the mistake of using the deactivation hook for this purpose.

This table illustrates the differences between deactivation and uninstall.

Scenario Deactivation Hook Uninstall Hook
Remove option from wp_options  —  X
Flush Cache  X  —

Instead of using the deactivation hook, you should do one of the following:

Here is an example of using uninstall.php.

uninstall.php #

When using uninstall.php, the plugin should always check for the WP_UNINSTALL_PLUGIN constant, before executing. The WP_UNINSTALL_PLUGIN constant is defined by WordPress at runtime during a plugin uninstall, it will not be present if uninstall.php is requested directly. It will also not be present when using the uninstall hook technique. WP_UNINSTALL_PLUGIN is only defined when an uninstall.php file is found in the plugin folder.

Here is an example removing database entries.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// If uninstall is not called from WordPress, exit
if ( !defined( 'WP_UNINSTALL_PLUGIN' ) ) {
    exit();
}
 
$option_name = 'plugin_option_name';
 
delete_option( $option_name );
 
// For site options in Multisite
delete_site_option( $option_name ); 
 
// Drop a custom db table
global $wpdb;
$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}mytable" );

Note: In Multisite, looping through all blogs to delete options can be very resource intensive.

 
[display-posts post_type="content" id="3672" include_content=true include_title=false wrapper="div" wrapper_class=""]

Best Practices

Here are some best practices to help in organizing your code so it works well alongside other WordPress plugins and WordPress core.

Prefix Everything #

All files, variables, and functions should be prefixed with a unique identifier. Prefixes prevent other plugins from overwriting your variable values or accidentally calling your functions. It will also prevent you from doing the same. Adding the initials of your plugin name or your name is a good start.

Here are a few examples of using prefixes in code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if ( !function_exists('myplugin_init' ) ) {
     function myplugin_init() {
          register_setting( 'myplugin_setting_example', 'foo' );
          register_setting( 'myplugin_setting_demo', 'bar' );
     }
}
 
if ( !function_exists( 'myplugin_get_demo_setting' ) ) {
     function myplugin_get_demo_setting() {
          return get_option( 'myplugin_setting' );
     }
}
 
/* File path: settings/myplugin_example.php */

Top ↑

File Organization #

The root level of your plugin directory should contain your plugin-name.php and, optionally, your uninstall file. All other files should be organized into folders whenever possible.

It’s also helpful to separate your admin code, and use the conditional is_admin to prevent it from loading when not needed. For example, in your main plugin file you might have the following:

1
2
3
4
5
6
if ( is_admin ) {
     // We are in admin mode
     require_once( dirname(__file__).'/admin/myplugin_admin.php' );
}
?>

Folder Structure #

A clear folder structure helps you and others working on your plugin. Keep similar files together. For example, place JavaScript files in a /js folder, style sheets in a /css folder, and images in an /images folder.

Here’s a sample folder structure for reference:

/my-plugin-name
     my-plugin-name.php
     uninstall.php
     /admin
     /js
     /css
     /images
     /includes
     /settings

Top ↑

Plugin Architecture #

The architecture, or code organization, you choose for your plugin will likely depend on the size of your plugin. For small, single-purpose plugins that only have a small interaction with WordPress Core, themes or other plugins, there’s little benefit in over-engineering it into a one or more classes, unless you know the plugin is going to expand greatly later on.

Large plugins with lots of groupable code, starting off with an end goal in mind of classes, separate style and scripts files, and even build-related files may help code organization and long-term maintenance of the plugin.

Top ↑

Architecture Patterns #

While there are a number of possible architecture patterns, they can broadly be grouped into three variations:

Top ↑

Architecture Patterns Explained #

Specific implementations of the more complex of the above code organizations have already been written up as tutorials and slides:

Top ↑

Boilerplate Starting Points #

Instead of starting from scratch for each new plugin you write, you may want to start with a boilerplate. The advantage of using a boilerplate is consistency among your own plugins, and for commonly used boilerplates, a format that other plugin contributors would also recognize.

These also serve as further examples of different yet comparable architectures.

Of course, you could take different aspects of these and others to create your own custom boilerplate.

 
Skip to toolbar