Getting Started with Object-Oriented WordPress Plugin Development

Published Jan 20, 2016Last updated Feb 14, 2017
Getting Started with Object-Oriented WordPress Plugin Development

Why You Should Use the Object-Oriented Style for WordPress Plugins

Perhaps you've seen crazy function names in your WordPress theme's functions.php file?

It can be quite hard to read through and understand a plugin or theme that has function names like snowpower_development_registration_init(). But it's kind of required to name your functions this way, because when your function is just plopped into a PHP file with no object-oriented structure, that function is now globally available.

If you don't give it a careful name that you can be sure is going to be unique, any other plugin or theme code out there could pick the same name. If you use those plugins or theme code, this creates a conflict and crashes your site. Usually, crashing your site is bad and should be avoided.

So what we can do instead is put our code into a class. When you do that, you only need to have a unique name to your plugin and to the class itself. All the functions inside the class can be nice, short, descriptive names, like init(), with no need to worry about all the other functions named init() out there.

Plugins Versus Themes

I refer to plugins in the title of this tutorial, but it applies for theme code, too. It's less common that you're writing custom functionality into a theme, but everything we'll talk about here is going to apply.

As it happens, even though I will often have a child theme to work with, I much prefer to put my code into plugins and test it against the default WordPress theme. That provides maximum likelihood it'll keep working when the theme gets swapped out.

A Plugin Skeleton

I've gone ahead and written a plugin skeleton with just two sample functions in it. My sample enqueues a JavaScript file and a CSS file for the front-end display, plus another JavaScript file and CSS file for an admin post editor page. Even as I write this, I am contemplating future tutorials to add examples of other commonly performed actions, but I want to keep this a little more brief so you can get started with WordPress development the right way.

I'll go through the following code in pieces, so for now, just take a quick look. Without further ado, here's the entire plugin skeleton code:

<?php
// TODO: Change the header to match your details
/**
 * Plugin Name: Plugin Skeleton
 * Description: Not a real plugin, but rather a starting point for building other plugins
 * Version: 1.0
 * Author: Aaron Overton
 * Author URI: http://www.heatherstone.com
 */

// TODO: Change the class name to something unique
class PluginSkeleton {

  // Put all your add_action, add_shortcode, add_filter functions in __construct()
  // For the callback name, use this: array($this,'<function name>')
  // <function name> is the name of the function within this class, so need not be globally unique
  // Some sample commonly used functions are included below
    public function __construct() {

  // TODO: Edit the calls here to only include the ones you want, or add more

        // Add Javascript and CSS for admin screens
        add_action('admin_enqueue_scripts', array($this,'enqueueAdmin'));

        // Add Javascript and CSS for front-end display
        add_action('wp_enqueue_scripts', array($this,'enqueue'));
    }

    /* ENQUEUE SCRIPTS AND STYLES */
    // This is an example of enqueuing a Javascript file and a CSS file for use on the editor 
    public function enqueueAdmin() {
    	// These two lines allow you to only load the files on the relevant screen, in this case, the editor for a "books" custom post type
    	$screen = get_current_screen();
    	if (!($screen->base == 'post' && $screen->post_type == 'books')) return;

    	// Actual enqueues, note the files are in the js and css folders
    	// For scripts, make sure you are including the relevant dependencies (jquery in this case)
    	wp_enqueue_script('very-descriptive-name', plugins_url('js/books-post-editor.js', __FILE__), array('jquery'), '1.0', true);
    	wp_enqueue_style('very-exciting-name', plugins_url('css/books-post-editor.css', __FILE__), null, '1.0');
    }

    // This is an example of enqueuing a JavaScript file and a CSS file for use on the front end display
    public function enqueue() {
    	// Actual enqueues, note the files are in the js and css folders
    	// For scripts, make sure you are including the relevant dependencies (jquery in this case)
    	wp_enqueue_script('descriptive-name', plugins_url('js/somefile.js', __FILE__), array('jquery'), '1.0', true);
    	wp_enqueue_style('other-descriptive-name', plugins_url('css/somefile.css', __FILE__), null, '1.0');

        // Sometimes you want to have access to data on the front end in your Javascript file
        // Getting that requires this call. Always go ahead and include ajaxurl. Any other variables,
        // add to the array.
        // Then in the Javascript file, you can refer to it like this: externalName.someVariable
        wp_localize_script( 'descriptive-name', 'externalName', array(
            'ajaxurl' => admin_url('admin-ajax.php'),
            'someVariable' => 'These are my socks'
        ));

    }
}

// TODO: Replace these with a variable named appropriately and the class name above
// If you need this available beyond our initial creation, you can create it as a global
global $skeleton;

// Create an instance of our class to kick off the whole thing
$skeleton = new PluginSkeleton();

I've also included TODO: statements so that if you choose to copy/paste the above, you'll have some inline guidance as to what is required to make it into your own plugin.

Plugin Header

/**
 * Plugin Name: Plugin Skeleton
 * Description: Not a real plugin, but rather a starting point for building other plugins
 * Version: 1.0
 * Author: Aaron Overton
 * Author URI: http://www.heatherstone.com
 */

The plugin header is not unique to this style, so I will simply say that if you are writing a plugin, include a header. The only thing that might require a little thought is that you need to pick a plugin name that is unique. I have twice run into name conflicts that plugin developers created and it can really be a problem when a user clicks "Update".

Check the WordPress plugin repository if you are unsure whether your planned name is taken.

Class Name and Instantiation

class PluginSkeleton {


}
// If you need this available beyond our initial creation, you can create it as a global
global $skeleton;

// Create an instance of our class to kick off the whole thing
$skeleton = new PluginSkeleton();

Like your plugin name, you need to create a unique class name. Fortunately, uniqueness here avoids the need to be unique for every single function name later.

I used the $5 word "instantiation" above. We are creating a class, which defines our plugin object. Functionally, this is just a definition and doesn't actually do anything. It's like having a recipe for cooking a sirloin steak. If you eat it, you only eat the paper, not a steak. We need to cook a steak according to the recipe's instructions. When we "instantiate" or "create an instance" of a class, now we have something we can use.

Most plugins I write don't need to be instantiated globally because they get a bunch of things started and then they are done. So the line that creates a global variable (global $skeleton;) can probably be cut out of your own plugins unless you have a good reason why you might need to reference it elsewhere.

But we do need the line with the new keyword, as that instantiates the plugin itself. So the above code is your class and gets it all started. In fact, the above would work even if the class had nothing in it. It just wouldn't do anything except be an activated plugin.

The Constructor Gets It Started

I'm skipping past a little code (constants and private variables.) I'm going to come back to those. Let's first look at the constructor function:

    public function __construct() {

  // TODO: Edit the calls here to only include the ones you want, or add more

        // Add Javascript and CSS for admin screens
        add_action('admin_enqueue_scripts', array($this,'enqueueAdmin'));

        // Add Javascript and CSS for front-end display
        add_action('wp_enqueue_scripts', array($this,'enqueue'));
    }

When an object is instantiated using a class, PHP looks for and executes a constructor function called __construct(). This automatic execution is exactly what we need to start doing all the work we want our plugin to do.

Important: You might come across constructors that look like this:

class MyClass {
    function MyClass() {
       ...
    }
}

That is the PHP4 style constructor. It still works, but is deprecated. WordPress now throws warnings. PHP4 is really old now, so don't use that style. PHP7 will start throwing warnings, PHP8 will not recognize such functions as constructors at all, assuming the partially implemented proposal continues as planned.

Inside the constructor function, my example has two function calls, add_action(). If you've been doing non-object-oriented WordPress development, you'll will basically recognize these function calls, except for the odd array bit as the second argument. For example, on the second call above: array($this,'enqueue')

What's going on here is that where the add_action() function takes a string with the name of a function to call, it can also take an array. The array first has an instantiated object, then the string with the name of the function to call on that object.

Since we're embedding this in the class definition, there isn't actually an instantiated object at the time our server will hit this code. So we use the magic $this keyword to refer to "the instantiated object that we are inside after you create it using this class definition."

WordPress, when it reaches the wp_enqueue_scripts action, will thus call the enqueue() function on our instantiated object. A similar thing happens for admin_enqueue_scripts, calling the enqueueAdmin() function on our instantiated object.

So in this example, the constructor function will add two actions, defined within the class. All that's left is to define those function inside the class.

Class Functions

The functions themselves are no different than the functions you wrote with object-oriented style, so there's no real need to review those here. We should only note that we are using the public keyword and that the functions are defined inside the class.

The public keyword makes sure that the function is visible outside the instantiated object. This is part of what we call "visibility" and we could use any of public, private, or protected. You can read more about that on the PHP site. Technically, we don't need to include the word public, because that's the default visibility, but it is generally good practice to be explicit.

Also make sure that you're including your functions inside the curly braces that define the class:

class PluginSkeleton {
   // Put them here
}

If you don't, then you've gone ahead and created global functions after all, not part of the class definition. Then you'd have blown all the benefits I mentioned right up front. Tragic!

Next Steps

Now that you have a basic structure, you can add more work to your constructor with supporting functions in the class definition. I have a more comprehensive plugin skeleton that I use as a reference all the time. It includes things like:

-Constants
-Instance variables
-A registration function for adding new post types
-Functions for modifying the columns on the post type list page
-Adding metaboxes and saving the data entered in them
-Adding shortcodes
-Supporting Ajax calls
-And more!

Keeping a skeleton plugin like we started here is a great way to speed up your overall plugin development process, so give that a try. You can copy/paste the above to get it going.

Discover and read more posts from Aaron Overton
get started
Enjoy this post?

Leave a like and comment for Aaron

2
1
1Reply
2 Bit Coders
a month ago

Since this article (which is really good btw), there has been a concerted effort to standardize this practice. It is called THE WORDPRESS PLUGIN BOILERPLATE and can be downloaded from http://wppb.io. It provides a very abstracted way to split up your plugin.

Get curated posts in your inbox

Read more posts to become a better developer