How to make an object oriented WordPress plugin

If you’re thinking of creating a WordPress plugin, whether small or large, for your own use or the whole world to benefit from, it’s important to start right.  Most of the example code on the WordPress documentation shows the functionalities in a procedural layout, because that makes it easier to explain.  But best practice is to use modern programming techniques – classes, inheritance, closures, and so on.

This tutorial will take you through the process of creating a very basic WordPress plugin, but created the right way.  This is partly intended to be a helpful reminder to me next time I’m creating a plugin, but hopefully others will find it useful too!

What we’ll be making

This plugin will provide an options screen in the WordPress back-end for the admin to specify how many things he has.  On the front-end, we’ll use a shortcode to display a form to ask visitors how many things they’ve got.  We’ll handle the form submission, store the number of things the visitor has in our database, and then use another shortcode to display how many things we all have in total.

It’s a pretty lame plugin, really.  But it will allow us to go through the process of making an options page, creating shortcodes, using templates, and handling form submissions.

Step 1: Naming conventions

An important thing to decide before you even put fingers to the keyboard is what to call your plugin.  Even if you’re the only person who will ever use it, you need to be sure that someone else isn’t using the same plugin name so that you don’t run into issues later.  A quick search in the plugin directory will answer your question.  And remember that it’s about the internal name, not the display name; you’ll see what I mean in a moment.  If you’ve ever asked yourself how many Daves you know, you’ll understand why unique naming is important.

First create a folder under /wp-content/plugins/  with the name of your plugin, for example /wp-content/plugins/md-things-plugin/ .  The folder name should be unique in the entire WordPress plugin ecosystem.  In theory I suppose you could use a random string here, but that would just look weird, so don’t do that.

Next, create a PHP file in that folder with the same unique name, in this case md-things-plugin.php .  For clarity it’s important that the names match, not because WordPress will get confused but because you might, or another developer who looks at the code.

Step 2: The class

Here’s our first bit of code, in md-things-plugin.php.

The comment block at the top is important, as that’s what will be displayed in your WordPress plugins page to tell everyone what the plugin is.  Technically the plugin name here doesn’t need to be unique, but it helps you be sure which plugin you’re activating!  You can probably work out what the other comments are about.

Next, we create the class, again using that unique name.  We wouldn’t want to run into issues where other plugins are using the same class name!  We’ll create a __construct()  function, which we’ll put stuff into later.  And then, finally, we simply use a variable to create an instance of the class.  The variable itself won’t be used directly, but it’s a way of making sure the class is run.

Step 3: Activate and deactivate

The first thing you do when you install a plugin is activate it.  Some plugin don’t need to do anything when they activate, but if yours does then you’ll need to catch that event and do something with it.  In our case, our plugin will need to set up a database table to store the number of things visitors have.

First off, we only want to listen out for activation/deactivation when we’re logged in as an administrator, so we’ll use is_admin()  to conditionally check.  And we’ll use register_activation_hook()  to listen out for the activation event.

There are a couple of bits of magic here.  First, notice the array in the register_activation_hook()  call.  In the WordPress documentation the first example (which is the one people read first) just has a string containing the name of the function, but since we’re using an object oriented approach our function is in a class, and using array(&$this,'activate')  is the way to do it.  It’ll go off and find the public function activate()  in the current class.  Neat!

In the activate()  function itself, we’re using the global $wpdb  object, which is how we safely access the database.  I won’t go into too much detail here on how to use the WordPress database, you can look that up yourself.  But what I do want to highlight is the dbDelta()  function.  That looks at the SQL code we’ve provided, and applies it to the database.  If the table doesn’t already exist, it makes it.  So when the plugin is activated, that table will be created too, assuming it wasn’t there already.

For deactivation it’s pretty much the same deal, but using register_deactivation_hook() .  It’s up to you whether you do anything with the database you created on activation – you may want to leave it all there, or truncate the data, or drop the table completely.  Up to you.

Step 4: The options page

This step is a little more messy, in my opinion, but I’ll try to make it clear what’s going on.  Once again, we’re only interested in the options page if we’re looking at the back-end of WordPress, so we’ll add our listener in there.

The first action uses the same technique used before of sending the event to a function within our class; I’ll show you what goes in there in a moment.

But you’ll notice that the second action we’re listening for doesn’t reference a class function, but uses a closure instead.  Why?  Personal preference really.  I didn’t see the point in creating a whole new function just for one line of code.  Keeping it in a closure doesn’t affect the functionality, and keeps the class tidy and easy to understand.  In this case, all we’re saying is that when the WP admin screen initialises we want to make sure there is a setting available for our options page to use.  Again, that will become clear later.

So, let’s look at the first action we set up, which listens for the admin_menu  action.  This allows us to add a menu item to the WordPress sidebar.  The function looks something like this:

You’ll need to refer to the documentation for add_management_page()  to see the full range of options available, but in this case we’re adding a menu item to the sidebar (as a subitem of ‘Tools’) that will be called “MD Things”, which will only be visible if the logged in user has permissions to manage_options  (so usually an Administrator).  It’s only one line, so why not put it in a closure like the other action?  Notice the last argument – we’re referring to $this , which wouldn’t work in the context of a closure.  That last bit is important, because that references another function in our class that actually displays the options page:

First of all it checks that we actually have permission to view the options page, and chucks us out if we haven’t.  It’s an unlikely scenario to have to cater for, but best to be safe.  Then we tell WordPress that our plugin uses an option variable, using get_option() .  And, finally, we show the options page itself.  This approach is my personal preference, and don’t feel you have to include the ‘.tpl’ bit in the filename if you prefer a different convention.  Here’s what options.tpl.php  looks like:

There are some styling conventions in WordPress, although I’ve found they’re not particularly well documented, so the best thing I can recommend is to look at the HTML of an existing plugin options page and replicate it.

But functionally, that’s it.  When you hit the submit button WordPress will automatically handle the form submission and save your data in the setting for this plugin.  You don’t need to worry about database access or parsing or anything… WordPress just works.

Something else that saves our bacon is that we’re saving all our settings as an array of values.  We register one option for the plugin via register_setting() , and we store all our settings as an array within that option, for example in the input above name="md_things_plugin[mythings]" .  The beauty of this is that if our plugin needed more settings, we simply add another element to the array, rather than having to create more options with register_setting() .  Nice and tidy.

Step 5: Asking for visitor input

We’re going to need a shortcode to display a form.  Again, the WordPress documentation would have you believe that this is done procedurally, but it doesn’t have to be.  I like to separate my functionality from my display, so I use template files to keep things tidy.

I’m using a closure again, because it’s tidy, but you could use a class function if you prefer.  All I’m doing here is including the template file, which looks something like this:

Now if we put that [md_things_form]  shortcode on a WordPress page or post somewhere, it will show our form.  When the form is submitted, it will be sent to WordPress’s internal admin-post.php  file, which we can hook into to process the form ourselves.  Here’s how we do that, again adding to the __construct()  function:

admin_post_  listens for post data sent to the admin-post.php  file, nopriv_  listens only to post requests that come through from someone who is not logged in, and md_things_visitor  is the identified we passed from the form submit button.  We can then route the request to a class function:

This inserts a new row in our database table, storing the value the visitor entered into the form.  I’m using intval()  to validate the input, but you might want to use something else depending on the format you expect.  Then it redirects back to the page we came from, as specified in the other input in the form (if anyone knows of a better way of doing this, let me know!).

As an added bonus, we can make that form template include a bit more information.  For instance, this bit of code would show the value our administrator put into the WordPress options page:

We can also create a static function in our class and reference it directly from the template:

Conclusion

Hopefully that’s given you enough to get started writing your own object oriented WordPress plugin.  If I’ve missed anything, or if you’ve spotted any mistakes, let me know in the comments below!

Leave a Reply

Your email address will not be published. Required fields are marked *