I’ve noticed that a bunch of the how-to-write-a-plugin articles out there focus on demonstrating the minimum amount of code needed to get a plugin going. Not many focus on good plugin structure or convention. This tutorial explains how to create a class based WordPress plugin that makes sense.
Start with a Directory
WordPress plugins can be defined in a single file or a directory of files. Starting with a directory gives you more flexibility and allows you to use common structures and folder layouts between projects and will add a level of maintainability.
Generally, I use the following folder tree:
wp-plugin-name.php–main plugin class
readme.txt–optional, describes the plugin for use in the wordpress.org plugin directory.
post-types/–define each post type separately in this directory.
custom-post-type.php–each post type is defined separately.
templates/–all of your admin side templates.
custom-post-type-inner-metabox.php–every custom post type that your plugin defines will need a inner-metabox template this keeps your presentation logic out of your business logic.
settings.php–this is the plugin settings page template.
Every plugin begins with a docblock PHP comment describing the plugin. This comment describes the plugin and its licensing.
After the plugin definition comment, you need to define your main plugin logic. I prefer to write class based plugins. In my case, a class named WP_Plugin_Template. WP_Plugin_Template must have several methods. In the class constructor register all of the actions that your base plugin needs. There are also static class functions activate and deactivate that get called on plugin activation/deactivation. We’ll be adding a bunch to this later, but at a very basic level, this is what your plugin class consists of.
At the bottom of the plugin class register the activation/deactivation hooks and instantiate the plugin class by calling the constructor.
###Add a settings page
To add a settings page we need to start adding actions and callbacks to the main plugin class.
In your main plugin class’s contructor function, public function __construct(), add the following code to hook into the admin_init and admin_menu actions.
The above code calls the current class instance’s admin_init and add_menu functions. In order for these callbacks to work, you need to add those functions:
In your settings.php template file use the name-spaced settings group name that you created above as arguments for several of the functions. Those functions handle all validation and storage for this settings page. see http://codex.wordpress.org/Function_Reference/settings_fields and http://codex.wordpress.org/Function_Reference/do_settings_fields
Lastly, to add a settings link next to the plugin’s activate/deactivate link in the Plugin Management list add the following to the bottom of your main plugin file directly after the $wp_plugin_template = new WP_Plugin_Template(); line that instantiates your plugin class.
###Add a custom post type
For every custom post type you want to add to your plugin you need to define a post type class. For this example, wp-plugin-name/post-types/post_type_template.php.
In this class add a constant POST_TYPE this is the name that your post type will be registered as. Also, add a private array $_meta this is an array of all the post types additional metafield names.
This class needs a constructor to set up the initial action hooks.
Add metaboxes to our custom post type’s admin pages on admin_init call.
Our post type’s inner meta box includes a template file to keep metabox templating out of the business logic.
The template for include(sprintf("%s/../templates/%s_metabox.php", dirname(__FILE__), self::POST_TYPE)); in my case templates/post-type-template_metabox.php should look something like the following. Note: each of your posts meta fields should be represented here.
Lastly, go back to the main plugin class’s constructor. Before the end of the function call the following to incorporate your post type into the plugin.
Congrats! you have created a class based WordPress plugin that does the following: